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 | 922a01a | 2018-02-01 12:18:46 +0100 | [diff] [blame] | 19 | #include "qemu/option.h" |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 20 | |
| 21 | static void fsdev_throttle_read_timer_cb(void *opaque) |
| 22 | { |
| 23 | FsThrottle *fst = opaque; |
Paolo Bonzini | 5261dd7 | 2018-02-03 10:39:34 -0500 | [diff] [blame] | 24 | qemu_co_enter_next(&fst->throttled_reqs[false], NULL); |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 25 | } |
| 26 | |
| 27 | static void fsdev_throttle_write_timer_cb(void *opaque) |
| 28 | { |
| 29 | FsThrottle *fst = opaque; |
Paolo Bonzini | 5261dd7 | 2018-02-03 10:39:34 -0500 | [diff] [blame] | 30 | qemu_co_enter_next(&fst->throttled_reqs[true], NULL); |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 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); |
Manos Pitsidianakis | 27e4cf1 | 2017-07-02 13:06:46 +0300 | [diff] [blame] | 90 | throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg); |
Pradeep Jagadeesh | b8bbdb8 | 2017-02-28 10:31:46 +0100 | [diff] [blame] | 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 | } |