static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ int size, /* size of the operation to do */ double avg, /* io limit */ uint64_t op_size, /* ideal size of an io */ double total_result, double read_result, double write_result) { BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL, THROTTLE_BPS_READ, THROTTLE_BPS_WRITE, }, { THROTTLE_OPS_TOTAL, THROTTLE_OPS_READ, THROTTLE_OPS_WRITE, } }; ThrottleConfig cfg; BucketType index; int i; for (i = 0; i < 3; i++) { BucketType index = to_test[is_ops][i]; cfg.buckets[index].avg = avg; } cfg.op_size = op_size; throttle_init(&ts); throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); throttle_config(&ts, &tt, &cfg); /* account a read */ throttle_account(&ts, false, size); /* account a write */ throttle_account(&ts, true, size); /* check total result */ index = to_test[is_ops][0]; if (!double_cmp(ts.cfg.buckets[index].level, total_result)) { return false; } /* check read result */ index = to_test[is_ops][1]; if (!double_cmp(ts.cfg.buckets[index].level, read_result)) { return false; } /* check write result */ index = to_test[is_ops][2]; if (!double_cmp(ts.cfg.buckets[index].level, write_result)) { return false; } throttle_timers_destroy(&tt); return true; }
void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, bool is_write, struct iovec *iov, int iovcnt) { if (throttle_enabled(&fst->cfg)) { if (throttle_schedule_timer(&fst->ts, &fst->tt, is_write) || !qemu_co_queue_empty(&fst->throttled_reqs[is_write])) { qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL); } throttle_account(&fst->ts, is_write, iov_size(iov, iovcnt)); if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) && !throttle_schedule_timer(&fst->ts, &fst->tt, is_write)) { qemu_co_queue_next(&fst->throttled_reqs[is_write]); } } }