xref: /openbmc/qemu/fsdev/qemu-fsdev-throttle.c (revision 2f95279a)
1 /*
2  * Fsdev Throttle
3  *
4  * Copyright (C) 2016 Huawei Technologies Duesseldorf GmbH
5  *
6  * Author: Pradeep Jagadeesh <pradeep.jagadeesh@huawei.com>
7  *
8  * This work is licensed under the terms of the GNU GPL, version 2 or
9  * (at your option) any later version.
10  *
11  * See the COPYING file in the top-level directory for details.
12  *
13  */
14 
15 #include "qemu/osdep.h"
16 #include "qemu/error-report.h"
17 #include "qemu-fsdev-throttle.h"
18 #include "qemu/iov.h"
19 #include "qemu/main-loop.h"
20 #include "qemu/option.h"
21 
22 static void fsdev_throttle_read_timer_cb(void *opaque)
23 {
24     FsThrottle *fst = opaque;
25     qemu_co_enter_next(&fst->throttled_reqs[false], NULL);
26 }
27 
28 static void fsdev_throttle_write_timer_cb(void *opaque)
29 {
30     FsThrottle *fst = opaque;
31     qemu_co_enter_next(&fst->throttled_reqs[true], NULL);
32 }
33 
34 int fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp)
35 {
36     throttle_config_init(&fst->cfg);
37     fst->cfg.buckets[THROTTLE_BPS_TOTAL].avg =
38         qemu_opt_get_number(opts, "throttling.bps-total", 0);
39     fst->cfg.buckets[THROTTLE_BPS_READ].avg  =
40         qemu_opt_get_number(opts, "throttling.bps-read", 0);
41     fst->cfg.buckets[THROTTLE_BPS_WRITE].avg =
42         qemu_opt_get_number(opts, "throttling.bps-write", 0);
43     fst->cfg.buckets[THROTTLE_OPS_TOTAL].avg =
44         qemu_opt_get_number(opts, "throttling.iops-total", 0);
45     fst->cfg.buckets[THROTTLE_OPS_READ].avg =
46         qemu_opt_get_number(opts, "throttling.iops-read", 0);
47     fst->cfg.buckets[THROTTLE_OPS_WRITE].avg =
48         qemu_opt_get_number(opts, "throttling.iops-write", 0);
49 
50     fst->cfg.buckets[THROTTLE_BPS_TOTAL].max =
51         qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
52     fst->cfg.buckets[THROTTLE_BPS_READ].max  =
53         qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
54     fst->cfg.buckets[THROTTLE_BPS_WRITE].max =
55         qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
56     fst->cfg.buckets[THROTTLE_OPS_TOTAL].max =
57         qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
58     fst->cfg.buckets[THROTTLE_OPS_READ].max =
59         qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
60     fst->cfg.buckets[THROTTLE_OPS_WRITE].max =
61         qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
62 
63     fst->cfg.buckets[THROTTLE_BPS_TOTAL].burst_length =
64         qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1);
65     fst->cfg.buckets[THROTTLE_BPS_READ].burst_length  =
66         qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1);
67     fst->cfg.buckets[THROTTLE_BPS_WRITE].burst_length =
68         qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1);
69     fst->cfg.buckets[THROTTLE_OPS_TOTAL].burst_length =
70         qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1);
71     fst->cfg.buckets[THROTTLE_OPS_READ].burst_length =
72         qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1);
73     fst->cfg.buckets[THROTTLE_OPS_WRITE].burst_length =
74         qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1);
75     fst->cfg.op_size =
76         qemu_opt_get_number(opts, "throttling.iops-size", 0);
77 
78     return throttle_is_valid(&fst->cfg, errp) ? 0 : -1;
79 }
80 
81 void fsdev_throttle_init(FsThrottle *fst)
82 {
83     if (throttle_enabled(&fst->cfg)) {
84         throttle_init(&fst->ts);
85         throttle_timers_init(&fst->tt,
86                              qemu_get_aio_context(),
87                              QEMU_CLOCK_REALTIME,
88                              fsdev_throttle_read_timer_cb,
89                              fsdev_throttle_write_timer_cb,
90                              fst);
91         throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg);
92         qemu_co_queue_init(&fst->throttled_reqs[0]);
93         qemu_co_queue_init(&fst->throttled_reqs[1]);
94     }
95 }
96 
97 void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst,
98                                             ThrottleDirection direction,
99                                             struct iovec *iov, int iovcnt)
100 {
101     assert(direction < THROTTLE_MAX);
102     if (throttle_enabled(&fst->cfg)) {
103         if (throttle_schedule_timer(&fst->ts, &fst->tt, direction) ||
104             !qemu_co_queue_empty(&fst->throttled_reqs[direction])) {
105             qemu_co_queue_wait(&fst->throttled_reqs[direction], NULL);
106         }
107 
108         throttle_account(&fst->ts, direction, iov_size(iov, iovcnt));
109 
110         if (!qemu_co_queue_empty(&fst->throttled_reqs[direction]) &&
111             !throttle_schedule_timer(&fst->ts, &fst->tt, direction)) {
112             qemu_co_queue_next(&fst->throttled_reqs[direction]);
113         }
114     }
115 }
116 
117 void fsdev_throttle_cleanup(FsThrottle *fst)
118 {
119     if (throttle_enabled(&fst->cfg)) {
120         throttle_timers_destroy(&fst->tt);
121     }
122 }
123