[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttl
From: |
Zhi Yong Wu |
Subject: |
Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm |
Date: |
Tue, 9 Aug 2011 17:06:00 +0800 |
On Tue, Aug 9, 2011 at 4:57 PM, Ram Pai <address@hidden> wrote:
> On Tue, Aug 09, 2011 at 12:17:51PM +0800, Zhi Yong Wu wrote:
>> Note:
>> 1.) When bps/iops limits are specified to a small value such as 511
>> bytes/s, this VM will hang up. We are considering how to handle this senario.
>> 2.) When "dd" command is issued in guest, if its option bs is set to a
>> large value such as "bs=1024K", the result speed will slightly bigger than
>> the limits.
>>
>> For these problems, if you have nice thought, pls let us know.:)
>>
>> Signed-off-by: Zhi Yong Wu <address@hidden>
>> ---
>> block.c | 347
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>> block.h | 6 +-
>> block_int.h | 30 +++++
>> 3 files changed, 372 insertions(+), 11 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index 24a25d5..8fd6643 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -29,6 +29,9 @@
>> #include "module.h"
>> #include "qemu-objects.h"
>>
>> +#include "qemu-timer.h"
>> +#include "block/blk-queue.h"
>> +
>> #ifdef CONFIG_BSD
>> #include <sys/types.h>
>> #include <sys/stat.h>
>> @@ -58,6 +61,13 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t
>> sector_num,
>> static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
>> const uint8_t *buf, int nb_sectors);
>>
>> +static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
>> + bool is_write, double elapsed_time, uint64_t *wait);
>> +static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
>> + double elapsed_time, uint64_t *wait);
>> +static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
>> + bool is_write, uint64_t *wait);
>> +
>> static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
>> QTAILQ_HEAD_INITIALIZER(bdrv_states);
>>
>> @@ -90,6 +100,68 @@ int is_windows_drive(const char *filename)
>> }
>> #endif
>>
>> +/* throttling disk I/O limits */
>> +void bdrv_io_limits_disable(BlockDriverState *bs)
>> +{
>> + bs->io_limits_enabled = false;
>> + bs->req_from_queue = false;
>> +
>> + if (bs->block_queue) {
>> + qemu_block_queue_flush(bs->block_queue);
>> + qemu_del_block_queue(bs->block_queue);
>> + }
>> +
>> + if (bs->block_timer) {
>> + qemu_del_timer(bs->block_timer);
>> + qemu_free_timer(bs->block_timer);
>> + }
>> +
>> + bs->slice_start[0] = 0;
>> + bs->slice_start[1] = 0;
>> +
>> + bs->slice_end[0] = 0;
>> + bs->slice_end[1] = 0;
>> +}
>> +
>> +static void bdrv_block_timer(void *opaque)
>> +{
>> + BlockDriverState *bs = opaque;
>> + BlockQueue *queue = bs->block_queue;
>> +
>> + qemu_block_queue_flush(queue);
>> +}
>> +
>> +void bdrv_io_limits_enable(BlockDriverState *bs)
>> +{
>> + bs->req_from_queue = false;
>> +
>> + bs->block_queue = qemu_new_block_queue();
>> + bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs);
>> +
>> + bs->slice_start[BLOCK_IO_LIMIT_READ] = qemu_get_clock_ns(vm_clock);
>> + bs->slice_start[BLOCK_IO_LIMIT_WRITE] = qemu_get_clock_ns(vm_clock);
>
> a minor comment. better to keep the slice_start of the both the READ and WRITE
> side the same.
>
> bs->slice_start[BLOCK_IO_LIMIT_WRITE] =
> bs->slice_start[BLOCK_IO_LIMIT_READ];
>
> saves a call to qemu_get_clock_ns().
>
>> +
>> + bs->slice_end[BLOCK_IO_LIMIT_READ] =
>> + qemu_get_clock_ns(vm_clock) + BLOCK_IO_SLICE_TIME;
>
> bs->slice_end[BLOCK_IO_LIMIT_READ] = bs->slice_start[BLOCK_IO_LIMIT_READ] +
> BLOCK_IO_SLICE_TIME;
>
> saves one more call to qemu_get_clock_ns()
>
>> + bs->slice_end[BLOCK_IO_LIMIT_WRITE] =
>> + qemu_get_clock_ns(vm_clock) + BLOCK_IO_SLICE_TIME;
>
>
> bs->slice_end[BLOCK_IO_LIMIT_WRITE] =
> bs->slice_start[BLOCK_IO_LIMIT_WRITE] +
> BLOCK_IO_SLICE_TIME;
>
> yet another call saving.
OK. thanks.
>
>
>> +}
>> +
>> +bool bdrv_io_limits_enabled(BlockDriverState *bs)
>> +{
>> + BlockIOLimit *io_limits = &bs->io_limits;
>> + if ((io_limits->bps[BLOCK_IO_LIMIT_READ] == 0)
>> + && (io_limits->bps[BLOCK_IO_LIMIT_WRITE] == 0)
>> + && (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] == 0)
>> + && (io_limits->iops[BLOCK_IO_LIMIT_READ] == 0)
>> + && (io_limits->iops[BLOCK_IO_LIMIT_WRITE] == 0)
>> + && (io_limits->iops[BLOCK_IO_LIMIT_TOTAL] == 0)) {
>> + return false;
>> + }
>> +
>> + return true;
>> +}
>
> can be optimized to:
>
> return (io_limits->bps[BLOCK_IO_LIMIT_READ]
> || io_limits->bps[BLOCK_IO_LIMIT_WRITE]
> || io_limits->bps[BLOCK_IO_LIMIT_TOTAL]
> || io_limits->iops[BLOCK_IO_LIMIT_READ]
> || io_limits->iops[BLOCK_IO_LIMIT_WRITE]
> || io_limits->iops[BLOCK_IO_LIMIT_TOTAL]);
OK. thanks.
>
>> +
>> /* check if the path starts with "<protocol>:" */
>> static int path_has_protocol(const char *path)
>> {
>> @@ -642,6 +714,11 @@ int bdrv_open(BlockDriverState *bs, const char
>> *filename, int flags,
>> bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
>> }
>>
>> + /* throttling disk I/O limits */
>> + if (bs->io_limits_enabled) {
>> + bdrv_io_limits_enable(bs);
>> + }
>> +
>> return 0;
>>
>> unlink_and_fail:
>> @@ -680,6 +757,16 @@ void bdrv_close(BlockDriverState *bs)
>> if (bs->change_cb)
>> bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
>> }
>> +
>> + /* throttling disk I/O limits */
>> + if (bs->block_queue) {
>> + qemu_del_block_queue(bs->block_queue);
>> + }
>> +
>> + if (bs->block_timer) {
>> + qemu_del_timer(bs->block_timer);
>> + qemu_free_timer(bs->block_timer);
>> + }
>> }
>>
>> void bdrv_close_all(void)
>> @@ -1312,6 +1399,15 @@ void bdrv_get_geometry_hint(BlockDriverState *bs,
>> *psecs = bs->secs;
>> }
>>
>> +/* throttling disk io limits */
>> +void bdrv_set_io_limits(BlockDriverState *bs,
>> + BlockIOLimit *io_limits)
>> +{
>> + memset(&bs->io_limits, 0, sizeof(BlockIOLimit));
>> + bs->io_limits = *io_limits;
>> + bs->io_limits_enabled = bdrv_io_limits_enabled(bs);
>> +}
>> +
>> /* Recognize floppy formats */
>> typedef struct FDFormat {
>> FDriveType drive;
>> @@ -1707,6 +1803,16 @@ static void bdrv_print_dict(QObject *obj, void
>> *opaque)
>> qdict_get_bool(qdict, "ro"),
>> qdict_get_str(qdict, "drv"),
>> qdict_get_bool(qdict, "encrypted"));
>> +
>> + monitor_printf(mon, " bps=%" PRId64 " bps_rd=%" PRId64
>> + " bps_wr=%" PRId64 " iops=%" PRId64
>> + " iops_rd=%" PRId64 " iops_wr=%" PRId64,
>> + qdict_get_int(qdict, "bps"),
>> + qdict_get_int(qdict, "bps_rd"),
>> + qdict_get_int(qdict, "bps_wr"),
>> + qdict_get_int(qdict, "iops"),
>> + qdict_get_int(qdict, "iops_rd"),
>> + qdict_get_int(qdict, "iops_wr"));
>> } else {
>> monitor_printf(mon, " [not inserted]");
>> }
>> @@ -1739,10 +1845,22 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
>> QDict *bs_dict = qobject_to_qdict(bs_obj);
>>
>> obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
>> - "'encrypted': %i }",
>> + "'encrypted': %i, "
>> + "'bps': %" PRId64 ","
>> + "'bps_rd': %" PRId64 ","
>> + "'bps_wr': %" PRId64 ","
>> + "'iops': %" PRId64 ","
>> + "'iops_rd': %" PRId64 ","
>> + "'iops_wr': %" PRId64 "}",
>> bs->filename, bs->read_only,
>> bs->drv->format_name,
>> - bdrv_is_encrypted(bs));
>> + bdrv_is_encrypted(bs),
>> +
>> bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL],
>> + bs->io_limits.bps[BLOCK_IO_LIMIT_READ],
>> +
>> bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE],
>> +
>> bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL],
>> +
>> bs->io_limits.iops[BLOCK_IO_LIMIT_READ],
>> +
>> bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]);
>> if (bs->backing_file[0] != '\0') {
>> QDict *qdict = qobject_to_qdict(obj);
>> qdict_put(qdict, "backing_file",
>> @@ -2111,6 +2229,165 @@ char *bdrv_snapshot_dump(char *buf, int buf_size,
>> QEMUSnapshotInfo *sn)
>> return buf;
>> }
>>
>> +static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
>> + bool is_write, double elapsed_time, uint64_t *wait) {
>> + uint64_t bps_limit = 0;
>> + double bytes_limit, bytes_disp, bytes_res;
>> + double slice_time, wait_time;
>> +
>> + if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
>> + bps_limit = bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL];
>> + } else if (bs->io_limits.bps[is_write]) {
>> + bps_limit = bs->io_limits.bps[is_write];
>> + } else {
>> + if (wait) {
>> + *wait = 0;
>> + }
>> +
>> + return false;
>> + }
>> +
>> + slice_time = bs->slice_end[is_write] - bs->slice_start[is_write];
>> + slice_time /= (BLOCK_IO_SLICE_TIME * 10.0);
>> + bytes_limit = bps_limit * slice_time;
>> + bytes_disp = bs->io_disps.bytes[is_write];
>> + if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
>> + bytes_disp += bs->io_disps.bytes[!is_write];
>> + }
>> +
>> + bytes_res = (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
>> +
>> + if (bytes_disp + bytes_res <= bytes_limit) {
>> + if (wait) {
>> + *wait = 0;
>> + }
>> +
>> + return false;
>> + }
>> +
>> + /* Calc approx time to dispatch */
>> + wait_time = (bytes_disp + bytes_res) / bps_limit - elapsed_time;
>> +
>> + if (wait) {
>> + *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
>> + }
>> +
>> + return true;
>> +}
>> +
>> +static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
>> + double elapsed_time, uint64_t *wait) {
>> + uint64_t iops_limit = 0;
>> + double ios_limit, ios_disp;
>> + double slice_time, wait_time;
>> +
>> + if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
>> + iops_limit = bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL];
>> + } else if (bs->io_limits.iops[is_write]) {
>> + iops_limit = bs->io_limits.iops[is_write];
>> + } else {
>> + if (wait) {
>> + *wait = 0;
>> + }
>> +
>> + return false;
>> + }
>> +
>> + slice_time = bs->slice_end[is_write] - bs->slice_start[is_write];
>> + slice_time /= (BLOCK_IO_SLICE_TIME * 10.0);
>> + ios_limit = iops_limit * slice_time;
>> + ios_disp = bs->io_disps.ios[is_write];
>> + if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
>> + ios_disp += bs->io_disps.ios[!is_write];
>> + }
>> +
>> + if (ios_disp + 1 <= ios_limit) {
>> + if (wait) {
>> + *wait = 0;
>> + }
>> +
>> + return false;
>> + }
>> +
>> + /* Calc approx time to dispatch */
>> + wait_time = (ios_disp + 1) / iops_limit;
>> + if (wait_time > elapsed_time) {
>> + wait_time = wait_time - elapsed_time;
>> + } else {
>> + wait_time = 0;
>> + }
>> +
>> + if (wait) {
>> + *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
>> + }
>> +
>> + return true;
>> +}
>
> bdrv_exceed_bps_limits() and bdrv_exceed_iops_limits() has almost similar
> logic.
> Probably can be abstracted into a single function.
I ever attempted to consolidate them, but found that it will also not
save LOC and cause the bad readability of this code; So i gave up.
>
> RP
>
>
--
Regards,
Zhi Yong Wu
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, (continued)
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Stefan Hajnoczi, 2011/08/10
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Zhi Yong Wu, 2011/08/11
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Zhi Yong Wu, 2011/08/11
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Zhi Yong Wu, 2011/08/12
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Stefan Hajnoczi, 2011/08/12
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Zhi Yong Wu, 2011/08/12
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Stefan Hajnoczi, 2011/08/12
- Re: [Qemu-devel] [PATCH v5 2/4] block: add the block queue support, Zhi Yong Wu, 2011/08/12
[Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Zhi Yong Wu, 2011/08/09
Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Stefan Hajnoczi, 2011/08/09
- Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Zhi Yong Wu, 2011/08/10
- Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Stefan Hajnoczi, 2011/08/10
- Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Zhi Yong Wu, 2011/08/12
- Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Stefan Hajnoczi, 2011/08/12
- Re: [Qemu-devel] [PATCH v5 3/4] block: add block timer and block throttling algorithm, Zhi Yong Wu, 2011/08/12
[Qemu-devel] [PATCH v5 4/4] qmp/hmp: add block_set_io_throttle, Zhi Yong Wu, 2011/08/09