Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 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" |
Markus Armbruster | db72581 | 2019-08-12 07:23:50 +0200 | [diff] [blame] | 19 | #include "qemu/main-loop.h" |
Markus Armbruster | 922a01a | 2018-02-01 12:18:46 +0100 | [diff] [blame] | 20 | #include "qemu/option.h" |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 21 | |
| 22 | static void fsdev_throttle_read_timer_cb(void *opaque) |
| 23 | { |
| 24 | FsThrottle *fst = opaque; |
Paolo Bonzini | 5261dd7 | 2018-02-03 10:39:34 -0500 | [diff] [blame] | 25 | qemu_co_enter_next(&fst->throttled_reqs[false], NULL); |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 26 | } |
| 27 | |
| 28 | static void fsdev_throttle_write_timer_cb(void *opaque) |
| 29 | { |
| 30 | FsThrottle *fst = opaque; |
Paolo Bonzini | 5261dd7 | 2018-02-03 10:39:34 -0500 | [diff] [blame] | 31 | qemu_co_enter_next(&fst->throttled_reqs[true], NULL); |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 32 | } |
| 33 | |
Greg Kurz | ea52cdd | 2019-10-10 11:36:05 +0200 | [diff] [blame] | 34 | int fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp) |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 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 | |
Greg Kurz | ea52cdd | 2019-10-10 11:36:05 +0200 | [diff] [blame] | 78 | return throttle_is_valid(&fst->cfg, errp) ? 0 : -1; |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 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); |
Manos Pitsidianakis | 27e4cf1 | 2017-07-02 13:06:46 +0300 | [diff] [blame] | 91 | throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg); |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 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 | } |