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