mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-09-06 18:05:37 +00:00
throttle: Extract timers from ThrottleState into a separate structure
Group throttling will share ThrottleState between multiple bs. As a consequence the ThrottleState will be accessed by multiple aio context. Timers are tied to their aio context so they must go out of the ThrottleState structure. This commit paves the way for each bs of a common ThrottleState to have its own timer. Signed-off-by: Benoit Canet <benoit.canet@nodalink.com> Signed-off-by: Alberto Garcia <berto@igalia.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 6cf9ea96d8b32ae2f8769cead38f68a6a0c8c909.1433779731.git.berto@igalia.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
f4a769abaa
commit
0e5b0a2d54
11
block.c
11
block.c
|
@ -1825,6 +1825,9 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||||
memcpy(&bs_dest->throttle_state,
|
memcpy(&bs_dest->throttle_state,
|
||||||
&bs_src->throttle_state,
|
&bs_src->throttle_state,
|
||||||
sizeof(ThrottleState));
|
sizeof(ThrottleState));
|
||||||
|
memcpy(&bs_dest->throttle_timers,
|
||||||
|
&bs_src->throttle_timers,
|
||||||
|
sizeof(ThrottleTimers));
|
||||||
bs_dest->throttled_reqs[0] = bs_src->throttled_reqs[0];
|
bs_dest->throttled_reqs[0] = bs_src->throttled_reqs[0];
|
||||||
bs_dest->throttled_reqs[1] = bs_src->throttled_reqs[1];
|
bs_dest->throttled_reqs[1] = bs_src->throttled_reqs[1];
|
||||||
bs_dest->io_limits_enabled = bs_src->io_limits_enabled;
|
bs_dest->io_limits_enabled = bs_src->io_limits_enabled;
|
||||||
|
@ -1886,7 +1889,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||||
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
||||||
assert(bs_new->job == NULL);
|
assert(bs_new->job == NULL);
|
||||||
assert(bs_new->io_limits_enabled == false);
|
assert(bs_new->io_limits_enabled == false);
|
||||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
assert(!throttle_timers_are_initialized(&bs_new->throttle_timers));
|
||||||
|
|
||||||
tmp = *bs_new;
|
tmp = *bs_new;
|
||||||
*bs_new = *bs_old;
|
*bs_new = *bs_old;
|
||||||
|
@ -1903,7 +1906,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||||
/* Check a few fields that should remain attached to the device */
|
/* Check a few fields that should remain attached to the device */
|
||||||
assert(bs_new->job == NULL);
|
assert(bs_new->job == NULL);
|
||||||
assert(bs_new->io_limits_enabled == false);
|
assert(bs_new->io_limits_enabled == false);
|
||||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
assert(!throttle_timers_are_initialized(&bs_new->throttle_timers));
|
||||||
|
|
||||||
/* insert the nodes back into the graph node list if needed */
|
/* insert the nodes back into the graph node list if needed */
|
||||||
if (bs_new->node_name[0] != '\0') {
|
if (bs_new->node_name[0] != '\0') {
|
||||||
|
@ -3691,7 +3694,7 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->io_limits_enabled) {
|
if (bs->io_limits_enabled) {
|
||||||
throttle_detach_aio_context(&bs->throttle_state);
|
throttle_timers_detach_aio_context(&bs->throttle_timers);
|
||||||
}
|
}
|
||||||
if (bs->drv->bdrv_detach_aio_context) {
|
if (bs->drv->bdrv_detach_aio_context) {
|
||||||
bs->drv->bdrv_detach_aio_context(bs);
|
bs->drv->bdrv_detach_aio_context(bs);
|
||||||
|
@ -3727,7 +3730,7 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||||
bs->drv->bdrv_attach_aio_context(bs, new_context);
|
bs->drv->bdrv_attach_aio_context(bs, new_context);
|
||||||
}
|
}
|
||||||
if (bs->io_limits_enabled) {
|
if (bs->io_limits_enabled) {
|
||||||
throttle_attach_aio_context(&bs->throttle_state, new_context);
|
throttle_timers_attach_aio_context(&bs->throttle_timers, new_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
QLIST_FOREACH(ban, &bs->aio_notifiers, list) {
|
QLIST_FOREACH(ban, &bs->aio_notifiers, list) {
|
||||||
|
|
24
block/io.c
24
block/io.c
|
@ -65,7 +65,7 @@ void bdrv_set_io_limits(BlockDriverState *bs,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
throttle_config(&bs->throttle_state, cfg);
|
throttle_config(&bs->throttle_state, &bs->throttle_timers, cfg);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
qemu_co_enter_next(&bs->throttled_reqs[i]);
|
qemu_co_enter_next(&bs->throttled_reqs[i]);
|
||||||
|
@ -98,7 +98,7 @@ void bdrv_io_limits_disable(BlockDriverState *bs)
|
||||||
|
|
||||||
bdrv_start_throttled_reqs(bs);
|
bdrv_start_throttled_reqs(bs);
|
||||||
|
|
||||||
throttle_destroy(&bs->throttle_state);
|
throttle_timers_destroy(&bs->throttle_timers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_throttle_read_timer_cb(void *opaque)
|
static void bdrv_throttle_read_timer_cb(void *opaque)
|
||||||
|
@ -123,12 +123,13 @@ void bdrv_io_limits_enable(BlockDriverState *bs)
|
||||||
clock_type = QEMU_CLOCK_VIRTUAL;
|
clock_type = QEMU_CLOCK_VIRTUAL;
|
||||||
}
|
}
|
||||||
assert(!bs->io_limits_enabled);
|
assert(!bs->io_limits_enabled);
|
||||||
throttle_init(&bs->throttle_state,
|
throttle_init(&bs->throttle_state);
|
||||||
bdrv_get_aio_context(bs),
|
throttle_timers_init(&bs->throttle_timers,
|
||||||
clock_type,
|
bdrv_get_aio_context(bs),
|
||||||
bdrv_throttle_read_timer_cb,
|
clock_type,
|
||||||
bdrv_throttle_write_timer_cb,
|
bdrv_throttle_read_timer_cb,
|
||||||
bs);
|
bdrv_throttle_write_timer_cb,
|
||||||
|
bs);
|
||||||
bs->io_limits_enabled = true;
|
bs->io_limits_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +143,9 @@ static void bdrv_io_limits_intercept(BlockDriverState *bs,
|
||||||
bool is_write)
|
bool is_write)
|
||||||
{
|
{
|
||||||
/* does this io must wait */
|
/* does this io must wait */
|
||||||
bool must_wait = throttle_schedule_timer(&bs->throttle_state, is_write);
|
bool must_wait = throttle_schedule_timer(&bs->throttle_state,
|
||||||
|
&bs->throttle_timers,
|
||||||
|
is_write);
|
||||||
|
|
||||||
/* if must wait or any request of this type throttled queue the IO */
|
/* if must wait or any request of this type throttled queue the IO */
|
||||||
if (must_wait ||
|
if (must_wait ||
|
||||||
|
@ -155,7 +158,8 @@ static void bdrv_io_limits_intercept(BlockDriverState *bs,
|
||||||
|
|
||||||
|
|
||||||
/* if the next request must wait -> do nothing */
|
/* if the next request must wait -> do nothing */
|
||||||
if (throttle_schedule_timer(&bs->throttle_state, is_write)) {
|
if (throttle_schedule_timer(&bs->throttle_state, &bs->throttle_timers,
|
||||||
|
is_write)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -380,6 +380,7 @@ struct BlockDriverState {
|
||||||
|
|
||||||
/* I/O throttling */
|
/* I/O throttling */
|
||||||
ThrottleState throttle_state;
|
ThrottleState throttle_state;
|
||||||
|
ThrottleTimers throttle_timers;
|
||||||
CoQueue throttled_reqs[2];
|
CoQueue throttled_reqs[2];
|
||||||
bool io_limits_enabled;
|
bool io_limits_enabled;
|
||||||
|
|
||||||
|
|
|
@ -65,14 +65,17 @@ typedef struct ThrottleConfig {
|
||||||
typedef struct ThrottleState {
|
typedef struct ThrottleState {
|
||||||
ThrottleConfig cfg; /* configuration */
|
ThrottleConfig cfg; /* configuration */
|
||||||
int64_t previous_leak; /* timestamp of the last leak done */
|
int64_t previous_leak; /* timestamp of the last leak done */
|
||||||
QEMUTimer * timers[2]; /* timers used to do the throttling */
|
} ThrottleState;
|
||||||
|
|
||||||
|
typedef struct ThrottleTimers {
|
||||||
|
QEMUTimer *timers[2]; /* timers used to do the throttling */
|
||||||
QEMUClockType clock_type; /* the clock used */
|
QEMUClockType clock_type; /* the clock used */
|
||||||
|
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
QEMUTimerCB *read_timer_cb;
|
QEMUTimerCB *read_timer_cb;
|
||||||
QEMUTimerCB *write_timer_cb;
|
QEMUTimerCB *write_timer_cb;
|
||||||
void *timer_opaque;
|
void *timer_opaque;
|
||||||
} ThrottleState;
|
} ThrottleTimers;
|
||||||
|
|
||||||
/* operations on single leaky buckets */
|
/* operations on single leaky buckets */
|
||||||
void throttle_leak_bucket(LeakyBucket *bkt, int64_t delta);
|
void throttle_leak_bucket(LeakyBucket *bkt, int64_t delta);
|
||||||
|
@ -86,20 +89,23 @@ bool throttle_compute_timer(ThrottleState *ts,
|
||||||
int64_t *next_timestamp);
|
int64_t *next_timestamp);
|
||||||
|
|
||||||
/* init/destroy cycle */
|
/* init/destroy cycle */
|
||||||
void throttle_init(ThrottleState *ts,
|
void throttle_init(ThrottleState *ts);
|
||||||
AioContext *aio_context,
|
|
||||||
QEMUClockType clock_type,
|
|
||||||
void (read_timer)(void *),
|
|
||||||
void (write_timer)(void *),
|
|
||||||
void *timer_opaque);
|
|
||||||
|
|
||||||
void throttle_destroy(ThrottleState *ts);
|
void throttle_timers_init(ThrottleTimers *tt,
|
||||||
|
AioContext *aio_context,
|
||||||
|
QEMUClockType clock_type,
|
||||||
|
QEMUTimerCB *read_timer_cb,
|
||||||
|
QEMUTimerCB *write_timer_cb,
|
||||||
|
void *timer_opaque);
|
||||||
|
|
||||||
void throttle_detach_aio_context(ThrottleState *ts);
|
void throttle_timers_destroy(ThrottleTimers *tt);
|
||||||
|
|
||||||
void throttle_attach_aio_context(ThrottleState *ts, AioContext *new_context);
|
void throttle_timers_detach_aio_context(ThrottleTimers *tt);
|
||||||
|
|
||||||
bool throttle_have_timer(ThrottleState *ts);
|
void throttle_timers_attach_aio_context(ThrottleTimers *tt,
|
||||||
|
AioContext *new_context);
|
||||||
|
|
||||||
|
bool throttle_timers_are_initialized(ThrottleTimers *tt);
|
||||||
|
|
||||||
/* configuration */
|
/* configuration */
|
||||||
bool throttle_enabled(ThrottleConfig *cfg);
|
bool throttle_enabled(ThrottleConfig *cfg);
|
||||||
|
@ -108,12 +114,16 @@ bool throttle_conflicting(ThrottleConfig *cfg);
|
||||||
|
|
||||||
bool throttle_is_valid(ThrottleConfig *cfg);
|
bool throttle_is_valid(ThrottleConfig *cfg);
|
||||||
|
|
||||||
void throttle_config(ThrottleState *ts, ThrottleConfig *cfg);
|
void throttle_config(ThrottleState *ts,
|
||||||
|
ThrottleTimers *tt,
|
||||||
|
ThrottleConfig *cfg);
|
||||||
|
|
||||||
void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg);
|
void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg);
|
||||||
|
|
||||||
/* usage */
|
/* usage */
|
||||||
bool throttle_schedule_timer(ThrottleState *ts, bool is_write);
|
bool throttle_schedule_timer(ThrottleState *ts,
|
||||||
|
ThrottleTimers *tt,
|
||||||
|
bool is_write);
|
||||||
|
|
||||||
void throttle_account(ThrottleState *ts, bool is_write, uint64_t size);
|
void throttle_account(ThrottleState *ts, bool is_write, uint64_t size);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ static AioContext *ctx;
|
||||||
static LeakyBucket bkt;
|
static LeakyBucket bkt;
|
||||||
static ThrottleConfig cfg;
|
static ThrottleConfig cfg;
|
||||||
static ThrottleState ts;
|
static ThrottleState ts;
|
||||||
|
static ThrottleTimers tt;
|
||||||
|
|
||||||
/* useful function */
|
/* useful function */
|
||||||
static bool double_cmp(double x, double y)
|
static bool double_cmp(double x, double y)
|
||||||
|
@ -103,17 +104,19 @@ static void test_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* fill the structure with crap */
|
/* fill the structures with crap */
|
||||||
memset(&ts, 1, sizeof(ts));
|
memset(&ts, 1, sizeof(ts));
|
||||||
|
memset(&tt, 1, sizeof(tt));
|
||||||
|
|
||||||
/* init the structure */
|
/* init structures */
|
||||||
throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
|
throttle_init(&ts);
|
||||||
read_timer_cb, write_timer_cb, &ts);
|
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
|
||||||
|
read_timer_cb, write_timer_cb, &ts);
|
||||||
|
|
||||||
/* check initialized fields */
|
/* check initialized fields */
|
||||||
g_assert(ts.clock_type == QEMU_CLOCK_VIRTUAL);
|
g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
|
||||||
g_assert(ts.timers[0]);
|
g_assert(tt.timers[0]);
|
||||||
g_assert(ts.timers[1]);
|
g_assert(tt.timers[1]);
|
||||||
|
|
||||||
/* check other fields where cleared */
|
/* check other fields where cleared */
|
||||||
g_assert(!ts.previous_leak);
|
g_assert(!ts.previous_leak);
|
||||||
|
@ -124,17 +127,18 @@ static void test_init(void)
|
||||||
g_assert(!ts.cfg.buckets[i].level);
|
g_assert(!ts.cfg.buckets[i].level);
|
||||||
}
|
}
|
||||||
|
|
||||||
throttle_destroy(&ts);
|
throttle_timers_destroy(&tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_destroy(void)
|
static void test_destroy(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
|
throttle_init(&ts);
|
||||||
read_timer_cb, write_timer_cb, &ts);
|
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
|
||||||
throttle_destroy(&ts);
|
read_timer_cb, write_timer_cb, &ts);
|
||||||
|
throttle_timers_destroy(&tt);
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
g_assert(!ts.timers[i]);
|
g_assert(!tt.timers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,11 +174,12 @@ static void test_config_functions(void)
|
||||||
|
|
||||||
orig_cfg.op_size = 1;
|
orig_cfg.op_size = 1;
|
||||||
|
|
||||||
throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
|
throttle_init(&ts);
|
||||||
read_timer_cb, write_timer_cb, &ts);
|
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
|
||||||
|
read_timer_cb, write_timer_cb, &ts);
|
||||||
/* structure reset by throttle_init previous_leak should be null */
|
/* structure reset by throttle_init previous_leak should be null */
|
||||||
g_assert(!ts.previous_leak);
|
g_assert(!ts.previous_leak);
|
||||||
throttle_config(&ts, &orig_cfg);
|
throttle_config(&ts, &tt, &orig_cfg);
|
||||||
|
|
||||||
/* has previous leak been initialized by throttle_config ? */
|
/* has previous leak been initialized by throttle_config ? */
|
||||||
g_assert(ts.previous_leak);
|
g_assert(ts.previous_leak);
|
||||||
|
@ -182,7 +187,7 @@ static void test_config_functions(void)
|
||||||
/* get back the fixed configuration */
|
/* get back the fixed configuration */
|
||||||
throttle_get_config(&ts, &final_cfg);
|
throttle_get_config(&ts, &final_cfg);
|
||||||
|
|
||||||
throttle_destroy(&ts);
|
throttle_timers_destroy(&tt);
|
||||||
|
|
||||||
g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
|
g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
|
||||||
g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg == 56);
|
g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg == 56);
|
||||||
|
@ -323,43 +328,47 @@ static void test_is_valid(void)
|
||||||
|
|
||||||
static void test_have_timer(void)
|
static void test_have_timer(void)
|
||||||
{
|
{
|
||||||
/* zero the structure */
|
/* zero structures */
|
||||||
memset(&ts, 0, sizeof(ts));
|
memset(&ts, 0, sizeof(ts));
|
||||||
|
memset(&tt, 0, sizeof(tt));
|
||||||
|
|
||||||
/* no timer set should return false */
|
/* no timer set should return false */
|
||||||
g_assert(!throttle_have_timer(&ts));
|
g_assert(!throttle_timers_are_initialized(&tt));
|
||||||
|
|
||||||
/* init the structure */
|
/* init structures */
|
||||||
throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
|
throttle_init(&ts);
|
||||||
read_timer_cb, write_timer_cb, &ts);
|
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
|
||||||
|
read_timer_cb, write_timer_cb, &ts);
|
||||||
|
|
||||||
/* timer set by init should return true */
|
/* timer set by init should return true */
|
||||||
g_assert(throttle_have_timer(&ts));
|
g_assert(throttle_timers_are_initialized(&tt));
|
||||||
|
|
||||||
throttle_destroy(&ts);
|
throttle_timers_destroy(&tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_detach_attach(void)
|
static void test_detach_attach(void)
|
||||||
{
|
{
|
||||||
/* zero the structure */
|
/* zero structures */
|
||||||
memset(&ts, 0, sizeof(ts));
|
memset(&ts, 0, sizeof(ts));
|
||||||
|
memset(&tt, 0, sizeof(tt));
|
||||||
|
|
||||||
/* init the structure */
|
/* init the structure */
|
||||||
throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
|
throttle_init(&ts);
|
||||||
read_timer_cb, write_timer_cb, &ts);
|
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
|
||||||
|
read_timer_cb, write_timer_cb, &ts);
|
||||||
|
|
||||||
/* timer set by init should return true */
|
/* timer set by init should return true */
|
||||||
g_assert(throttle_have_timer(&ts));
|
g_assert(throttle_timers_are_initialized(&tt));
|
||||||
|
|
||||||
/* timer should no longer exist after detaching */
|
/* timer should no longer exist after detaching */
|
||||||
throttle_detach_aio_context(&ts);
|
throttle_timers_detach_aio_context(&tt);
|
||||||
g_assert(!throttle_have_timer(&ts));
|
g_assert(!throttle_timers_are_initialized(&tt));
|
||||||
|
|
||||||
/* timer should exist again after attaching */
|
/* timer should exist again after attaching */
|
||||||
throttle_attach_aio_context(&ts, ctx);
|
throttle_timers_attach_aio_context(&tt, ctx);
|
||||||
g_assert(throttle_have_timer(&ts));
|
g_assert(throttle_timers_are_initialized(&tt));
|
||||||
|
|
||||||
throttle_destroy(&ts);
|
throttle_timers_destroy(&tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
|
static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
|
||||||
|
@ -387,9 +396,10 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
|
||||||
|
|
||||||
cfg.op_size = op_size;
|
cfg.op_size = op_size;
|
||||||
|
|
||||||
throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
|
throttle_init(&ts);
|
||||||
read_timer_cb, write_timer_cb, &ts);
|
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
|
||||||
throttle_config(&ts, &cfg);
|
read_timer_cb, write_timer_cb, &ts);
|
||||||
|
throttle_config(&ts, &tt, &cfg);
|
||||||
|
|
||||||
/* account a read */
|
/* account a read */
|
||||||
throttle_account(&ts, false, size);
|
throttle_account(&ts, false, size);
|
||||||
|
@ -414,7 +424,7 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
throttle_destroy(&ts);
|
throttle_timers_destroy(&tt);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,29 +159,36 @@ bool throttle_compute_timer(ThrottleState *ts,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add timers to event loop */
|
/* Add timers to event loop */
|
||||||
void throttle_attach_aio_context(ThrottleState *ts, AioContext *new_context)
|
void throttle_timers_attach_aio_context(ThrottleTimers *tt,
|
||||||
|
AioContext *new_context)
|
||||||
{
|
{
|
||||||
ts->timers[0] = aio_timer_new(new_context, ts->clock_type, SCALE_NS,
|
tt->timers[0] = aio_timer_new(new_context, tt->clock_type, SCALE_NS,
|
||||||
ts->read_timer_cb, ts->timer_opaque);
|
tt->read_timer_cb, tt->timer_opaque);
|
||||||
ts->timers[1] = aio_timer_new(new_context, ts->clock_type, SCALE_NS,
|
tt->timers[1] = aio_timer_new(new_context, tt->clock_type, SCALE_NS,
|
||||||
ts->write_timer_cb, ts->timer_opaque);
|
tt->write_timer_cb, tt->timer_opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To be called first on the ThrottleState */
|
/* To be called first on the ThrottleState */
|
||||||
void throttle_init(ThrottleState *ts,
|
void throttle_init(ThrottleState *ts)
|
||||||
AioContext *aio_context,
|
|
||||||
QEMUClockType clock_type,
|
|
||||||
QEMUTimerCB *read_timer_cb,
|
|
||||||
QEMUTimerCB *write_timer_cb,
|
|
||||||
void *timer_opaque)
|
|
||||||
{
|
{
|
||||||
memset(ts, 0, sizeof(ThrottleState));
|
memset(ts, 0, sizeof(ThrottleState));
|
||||||
|
}
|
||||||
|
|
||||||
ts->clock_type = clock_type;
|
/* To be called first on the ThrottleTimers */
|
||||||
ts->read_timer_cb = read_timer_cb;
|
void throttle_timers_init(ThrottleTimers *tt,
|
||||||
ts->write_timer_cb = write_timer_cb;
|
AioContext *aio_context,
|
||||||
ts->timer_opaque = timer_opaque;
|
QEMUClockType clock_type,
|
||||||
throttle_attach_aio_context(ts, aio_context);
|
QEMUTimerCB *read_timer_cb,
|
||||||
|
QEMUTimerCB *write_timer_cb,
|
||||||
|
void *timer_opaque)
|
||||||
|
{
|
||||||
|
memset(tt, 0, sizeof(ThrottleTimers));
|
||||||
|
|
||||||
|
tt->clock_type = clock_type;
|
||||||
|
tt->read_timer_cb = read_timer_cb;
|
||||||
|
tt->write_timer_cb = write_timer_cb;
|
||||||
|
tt->timer_opaque = timer_opaque;
|
||||||
|
throttle_timers_attach_aio_context(tt, aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destroy a timer */
|
/* destroy a timer */
|
||||||
|
@ -195,25 +202,25 @@ static void throttle_timer_destroy(QEMUTimer **timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove timers from event loop */
|
/* Remove timers from event loop */
|
||||||
void throttle_detach_aio_context(ThrottleState *ts)
|
void throttle_timers_detach_aio_context(ThrottleTimers *tt)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
throttle_timer_destroy(&ts->timers[i]);
|
throttle_timer_destroy(&tt->timers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To be called last on the ThrottleState */
|
/* To be called last on the ThrottleTimers */
|
||||||
void throttle_destroy(ThrottleState *ts)
|
void throttle_timers_destroy(ThrottleTimers *tt)
|
||||||
{
|
{
|
||||||
throttle_detach_aio_context(ts);
|
throttle_timers_detach_aio_context(tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* is any throttling timer configured */
|
/* is any throttling timer configured */
|
||||||
bool throttle_have_timer(ThrottleState *ts)
|
bool throttle_timers_are_initialized(ThrottleTimers *tt)
|
||||||
{
|
{
|
||||||
if (ts->timers[0]) {
|
if (tt->timers[0]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,9 +331,12 @@ static void throttle_cancel_timer(QEMUTimer *timer)
|
||||||
/* Used to configure the throttle
|
/* Used to configure the throttle
|
||||||
*
|
*
|
||||||
* @ts: the throttle state we are working on
|
* @ts: the throttle state we are working on
|
||||||
|
* @tt: the throttle timers we use in this aio context
|
||||||
* @cfg: the config to set
|
* @cfg: the config to set
|
||||||
*/
|
*/
|
||||||
void throttle_config(ThrottleState *ts, ThrottleConfig *cfg)
|
void throttle_config(ThrottleState *ts,
|
||||||
|
ThrottleTimers *tt,
|
||||||
|
ThrottleConfig *cfg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -336,10 +346,10 @@ void throttle_config(ThrottleState *ts, ThrottleConfig *cfg)
|
||||||
throttle_fix_bucket(&ts->cfg.buckets[i]);
|
throttle_fix_bucket(&ts->cfg.buckets[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ts->previous_leak = qemu_clock_get_ns(ts->clock_type);
|
ts->previous_leak = qemu_clock_get_ns(tt->clock_type);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
throttle_cancel_timer(ts->timers[i]);
|
throttle_cancel_timer(tt->timers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,12 +368,15 @@ void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg)
|
||||||
*
|
*
|
||||||
* NOTE: this function is not unit tested due to it's usage of timer_mod
|
* NOTE: this function is not unit tested due to it's usage of timer_mod
|
||||||
*
|
*
|
||||||
|
* @tt: the timers structure
|
||||||
* @is_write: the type of operation (read/write)
|
* @is_write: the type of operation (read/write)
|
||||||
* @ret: true if the timer has been scheduled else false
|
* @ret: true if the timer has been scheduled else false
|
||||||
*/
|
*/
|
||||||
bool throttle_schedule_timer(ThrottleState *ts, bool is_write)
|
bool throttle_schedule_timer(ThrottleState *ts,
|
||||||
|
ThrottleTimers *tt,
|
||||||
|
bool is_write)
|
||||||
{
|
{
|
||||||
int64_t now = qemu_clock_get_ns(ts->clock_type);
|
int64_t now = qemu_clock_get_ns(tt->clock_type);
|
||||||
int64_t next_timestamp;
|
int64_t next_timestamp;
|
||||||
bool must_wait;
|
bool must_wait;
|
||||||
|
|
||||||
|
@ -378,12 +391,12 @@ bool throttle_schedule_timer(ThrottleState *ts, bool is_write)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* request throttled and timer pending -> do nothing */
|
/* request throttled and timer pending -> do nothing */
|
||||||
if (timer_pending(ts->timers[is_write])) {
|
if (timer_pending(tt->timers[is_write])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* request throttled and timer not pending -> arm timer */
|
/* request throttled and timer not pending -> arm timer */
|
||||||
timer_mod(ts->timers[is_write], next_timestamp);
|
timer_mod(tt->timers[is_write], next_timestamp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue