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 | void 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 | throttle_is_valid(&fst->cfg, errp); |
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, bool is_write, |
98 | struct iovec *iov, int iovcnt) |
99 | { |
100 | if (throttle_enabled(&fst->cfg)) { |
101 | if (throttle_schedule_timer(&fst->ts, &fst->tt, is_write) || |
102 | !qemu_co_queue_empty(&fst->throttled_reqs[is_write])) { |
103 | qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL); |
104 | } |
105 | |
106 | throttle_account(&fst->ts, is_write, iov_size(iov, iovcnt)); |
107 | |
108 | if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) && |
109 | !throttle_schedule_timer(&fst->ts, &fst->tt, is_write)) { |
110 | qemu_co_queue_next(&fst->throttled_reqs[is_write]); |
111 | } |
112 | } |
113 | } |
114 | |
115 | void fsdev_throttle_cleanup(FsThrottle *fst) |
116 | { |
117 | if (throttle_enabled(&fst->cfg)) { |
118 | throttle_timers_destroy(&fst->tt); |
119 | } |
120 | } |
121 | |