xref: /openbmc/qemu/fsdev/qemu-fsdev-throttle.c (revision 1be82d89)
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/option.h"
20 
21 static void fsdev_throttle_read_timer_cb(void *opaque)
22 {
23     FsThrottle *fst = opaque;
24     qemu_co_enter_next(&fst->throttled_reqs[false], NULL);
25 }
26 
27 static void fsdev_throttle_write_timer_cb(void *opaque)
28 {
29     FsThrottle *fst = opaque;
30     qemu_co_enter_next(&fst->throttled_reqs[true], NULL);
31 }
32 
33 void fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp)
34 {
35     throttle_config_init(&fst->cfg);
36     fst->cfg.buckets[THROTTLE_BPS_TOTAL].avg =
37         qemu_opt_get_number(opts, "throttling.bps-total", 0);
38     fst->cfg.buckets[THROTTLE_BPS_READ].avg  =
39         qemu_opt_get_number(opts, "throttling.bps-read", 0);
40     fst->cfg.buckets[THROTTLE_BPS_WRITE].avg =
41         qemu_opt_get_number(opts, "throttling.bps-write", 0);
42     fst->cfg.buckets[THROTTLE_OPS_TOTAL].avg =
43         qemu_opt_get_number(opts, "throttling.iops-total", 0);
44     fst->cfg.buckets[THROTTLE_OPS_READ].avg =
45         qemu_opt_get_number(opts, "throttling.iops-read", 0);
46     fst->cfg.buckets[THROTTLE_OPS_WRITE].avg =
47         qemu_opt_get_number(opts, "throttling.iops-write", 0);
48 
49     fst->cfg.buckets[THROTTLE_BPS_TOTAL].max =
50         qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
51     fst->cfg.buckets[THROTTLE_BPS_READ].max  =
52         qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
53     fst->cfg.buckets[THROTTLE_BPS_WRITE].max =
54         qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
55     fst->cfg.buckets[THROTTLE_OPS_TOTAL].max =
56         qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
57     fst->cfg.buckets[THROTTLE_OPS_READ].max =
58         qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
59     fst->cfg.buckets[THROTTLE_OPS_WRITE].max =
60         qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
61 
62     fst->cfg.buckets[THROTTLE_BPS_TOTAL].burst_length =
63         qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1);
64     fst->cfg.buckets[THROTTLE_BPS_READ].burst_length  =
65         qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1);
66     fst->cfg.buckets[THROTTLE_BPS_WRITE].burst_length =
67         qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1);
68     fst->cfg.buckets[THROTTLE_OPS_TOTAL].burst_length =
69         qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1);
70     fst->cfg.buckets[THROTTLE_OPS_READ].burst_length =
71         qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1);
72     fst->cfg.buckets[THROTTLE_OPS_WRITE].burst_length =
73         qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1);
74     fst->cfg.op_size =
75         qemu_opt_get_number(opts, "throttling.iops-size", 0);
76 
77     throttle_is_valid(&fst->cfg, errp);
78 }
79 
80 void fsdev_throttle_init(FsThrottle *fst)
81 {
82     if (throttle_enabled(&fst->cfg)) {
83         throttle_init(&fst->ts);
84         throttle_timers_init(&fst->tt,
85                              qemu_get_aio_context(),
86                              QEMU_CLOCK_REALTIME,
87                              fsdev_throttle_read_timer_cb,
88                              fsdev_throttle_write_timer_cb,
89                              fst);
90         throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg);
91         qemu_co_queue_init(&fst->throttled_reqs[0]);
92         qemu_co_queue_init(&fst->throttled_reqs[1]);
93     }
94 }
95 
96 void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, bool is_write,
97                                             struct iovec *iov, int iovcnt)
98 {
99     if (throttle_enabled(&fst->cfg)) {
100         if (throttle_schedule_timer(&fst->ts, &fst->tt, is_write) ||
101             !qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
102             qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL);
103         }
104 
105         throttle_account(&fst->ts, is_write, iov_size(iov, iovcnt));
106 
107         if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) &&
108             !throttle_schedule_timer(&fst->ts, &fst->tt, is_write)) {
109             qemu_co_queue_next(&fst->throttled_reqs[is_write]);
110         }
111     }
112 }
113 
114 void fsdev_throttle_cleanup(FsThrottle *fst)
115 {
116     if (throttle_enabled(&fst->cfg)) {
117         throttle_timers_destroy(&fst->tt);
118     }
119 }
120