block: Add support for throttling burst max in QMP and the command line.

The max parameter of the leaky bucket throttling algorithm can be used to
allow the guest to do bursts.
The max value is a pool of I/O that the guest can use without being throttled
at all. Throttling is triggered once this pool is empty.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Benoît Canet 2013-09-02 14:14:40 +02:00 committed by Stefan Hajnoczi
parent cc0681c454
commit 3e9fab690d
6 changed files with 195 additions and 24 deletions

View File

@ -232,6 +232,32 @@ void bdrv_query_info(BlockDriverState *bs,
info->inserted->iops = cfg.buckets[THROTTLE_OPS_TOTAL].avg;
info->inserted->iops_rd = cfg.buckets[THROTTLE_OPS_READ].avg;
info->inserted->iops_wr = cfg.buckets[THROTTLE_OPS_WRITE].avg;
info->inserted->has_bps_max =
cfg.buckets[THROTTLE_BPS_TOTAL].max;
info->inserted->bps_max =
cfg.buckets[THROTTLE_BPS_TOTAL].max;
info->inserted->has_bps_rd_max =
cfg.buckets[THROTTLE_BPS_READ].max;
info->inserted->bps_rd_max =
cfg.buckets[THROTTLE_BPS_READ].max;
info->inserted->has_bps_wr_max =
cfg.buckets[THROTTLE_BPS_WRITE].max;
info->inserted->bps_wr_max =
cfg.buckets[THROTTLE_BPS_WRITE].max;
info->inserted->has_iops_max =
cfg.buckets[THROTTLE_OPS_TOTAL].max;
info->inserted->iops_max =
cfg.buckets[THROTTLE_OPS_TOTAL].max;
info->inserted->has_iops_rd_max =
cfg.buckets[THROTTLE_OPS_READ].max;
info->inserted->iops_rd_max =
cfg.buckets[THROTTLE_OPS_READ].max;
info->inserted->has_iops_wr_max =
cfg.buckets[THROTTLE_OPS_WRITE].max;
info->inserted->iops_wr_max =
cfg.buckets[THROTTLE_OPS_WRITE].max;
}
bs0 = bs;

View File

@ -494,13 +494,18 @@ static DriveInfo *blockdev_init(QemuOpts *all_opts,
cfg.buckets[THROTTLE_OPS_WRITE].avg =
qemu_opt_get_number(opts, "throttling.iops-write", 0);
cfg.buckets[THROTTLE_BPS_TOTAL].max = 0;
cfg.buckets[THROTTLE_BPS_READ].max = 0;
cfg.buckets[THROTTLE_BPS_WRITE].max = 0;
cfg.buckets[THROTTLE_OPS_TOTAL].max = 0;
cfg.buckets[THROTTLE_OPS_READ].max = 0;
cfg.buckets[THROTTLE_OPS_WRITE].max = 0;
cfg.buckets[THROTTLE_BPS_TOTAL].max =
qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
cfg.buckets[THROTTLE_BPS_READ].max =
qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
cfg.buckets[THROTTLE_BPS_WRITE].max =
qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
cfg.buckets[THROTTLE_OPS_TOTAL].max =
qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
cfg.buckets[THROTTLE_OPS_READ].max =
qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
cfg.buckets[THROTTLE_OPS_WRITE].max =
qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
cfg.op_size = 0;
@ -761,6 +766,14 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
qemu_opt_rename(all_opts, "bps_rd", "throttling.bps-read");
qemu_opt_rename(all_opts, "bps_wr", "throttling.bps-write");
qemu_opt_rename(all_opts, "iops_max", "throttling.iops-total-max");
qemu_opt_rename(all_opts, "iops_rd_max", "throttling.iops-read-max");
qemu_opt_rename(all_opts, "iops_wr_max", "throttling.iops-write-max");
qemu_opt_rename(all_opts, "bps_max", "throttling.bps-total-max");
qemu_opt_rename(all_opts, "bps_rd_max", "throttling.bps-read-max");
qemu_opt_rename(all_opts, "bps_wr_max", "throttling.bps-write-max");
qemu_opt_rename(all_opts, "readonly", "read-only");
value = qemu_opt_get(all_opts, "cache");
@ -1245,8 +1258,22 @@ void qmp_change_blockdev(const char *device, const char *filename,
/* throttling disk I/O limits */
void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr, int64_t iops, int64_t iops_rd,
int64_t iops_wr, Error **errp)
int64_t bps_wr,
int64_t iops,
int64_t iops_rd,
int64_t iops_wr,
bool has_bps_max,
int64_t bps_max,
bool has_bps_rd_max,
int64_t bps_rd_max,
bool has_bps_wr_max,
int64_t bps_wr_max,
bool has_iops_max,
int64_t iops_max,
bool has_iops_rd_max,
int64_t iops_rd_max,
bool has_iops_wr_max,
int64_t iops_wr_max, Error **errp)
{
ThrottleConfig cfg;
BlockDriverState *bs;
@ -1266,13 +1293,24 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
cfg.buckets[THROTTLE_OPS_READ].avg = iops_rd;
cfg.buckets[THROTTLE_OPS_WRITE].avg = iops_wr;
cfg.buckets[THROTTLE_BPS_TOTAL].max = 0;
cfg.buckets[THROTTLE_BPS_READ].max = 0;
cfg.buckets[THROTTLE_BPS_WRITE].max = 0;
cfg.buckets[THROTTLE_OPS_TOTAL].max = 0;
cfg.buckets[THROTTLE_OPS_READ].max = 0;
cfg.buckets[THROTTLE_OPS_WRITE].max = 0;
if (has_bps_max) {
cfg.buckets[THROTTLE_BPS_TOTAL].max = bps_max;
}
if (has_bps_rd_max) {
cfg.buckets[THROTTLE_BPS_READ].max = bps_rd_max;
}
if (has_bps_wr_max) {
cfg.buckets[THROTTLE_BPS_WRITE].max = bps_wr_max;
}
if (has_iops_max) {
cfg.buckets[THROTTLE_OPS_TOTAL].max = iops_max;
}
if (has_iops_rd_max) {
cfg.buckets[THROTTLE_OPS_READ].max = iops_rd_max;
}
if (has_iops_wr_max) {
cfg.buckets[THROTTLE_OPS_WRITE].max = iops_wr_max;
}
cfg.op_size = 0;
@ -1975,6 +2013,30 @@ QemuOptsList qemu_common_drive_opts = {
.name = "throttling.bps-write",
.type = QEMU_OPT_NUMBER,
.help = "limit write bytes per second",
},{
.name = "throttling.iops-total-max",
.type = QEMU_OPT_NUMBER,
.help = "I/O operations burst",
},{
.name = "throttling.iops-read-max",
.type = QEMU_OPT_NUMBER,
.help = "I/O operations read burst",
},{
.name = "throttling.iops-write-max",
.type = QEMU_OPT_NUMBER,
.help = "I/O operations write burst",
},{
.name = "throttling.bps-total-max",
.type = QEMU_OPT_NUMBER,
.help = "total bytes burst",
},{
.name = "throttling.bps-read-max",
.type = QEMU_OPT_NUMBER,
.help = "total bytes read burst",
},{
.name = "throttling.bps-write-max",
.type = QEMU_OPT_NUMBER,
.help = "total bytes write burst",
},{
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,

32
hmp.c
View File

@ -344,14 +344,28 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, " I/O throttling: bps=%" PRId64
" bps_rd=%" PRId64 " bps_wr=%" PRId64
" bps_max=%" PRId64
" bps_rd_max=%" PRId64
" bps_wr_max=%" PRId64
" iops=%" PRId64 " iops_rd=%" PRId64
" iops_wr=%" PRId64 "\n",
" iops_wr=%" PRId64
" iops_max=%" PRId64
" iops_rd_max=%" PRId64
" iops_wr_max=%" PRId64 "\n",
info->value->inserted->bps,
info->value->inserted->bps_rd,
info->value->inserted->bps_wr,
info->value->inserted->bps_max,
info->value->inserted->bps_rd_max,
info->value->inserted->bps_wr_max,
info->value->inserted->iops,
info->value->inserted->iops_rd,
info->value->inserted->iops_wr);
info->value->inserted->iops_wr,
info->value->inserted->iops_max,
info->value->inserted->iops_rd_max,
info->value->inserted->iops_wr_max);
} else {
monitor_printf(mon, " [not inserted]");
}
if (verbose) {
@ -1098,7 +1112,19 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
qdict_get_int(qdict, "bps_wr"),
qdict_get_int(qdict, "iops"),
qdict_get_int(qdict, "iops_rd"),
qdict_get_int(qdict, "iops_wr"), &err);
qdict_get_int(qdict, "iops_wr"),
false, /* no burst max via HMP */
0,
false,
0,
false,
0,
false,
0,
false,
0,
false,
0, &err);
hmp_handle_error(mon, &err);
}

View File

@ -785,6 +785,18 @@
#
# @image: the info of image used (since: 1.6)
#
# @bps_max: #optional total max in bytes (Since 1.7)
#
# @bps_rd_max: #optional read max in bytes (Since 1.7)
#
# @bps_wr_max: #optional write max in bytes (Since 1.7)
#
# @iops_max: #optional total I/O operations max (Since 1.7)
#
# @iops_rd_max: #optional read I/O operations max (Since 1.7)
#
# @iops_wr_max: #optional write I/O operations max (Since 1.7)
#
# Since: 0.14.0
#
# Notes: This interface is only found in @BlockInfo.
@ -795,7 +807,10 @@
'encrypted': 'bool', 'encryption_key_missing': 'bool',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
'image': 'ImageInfo' } }
'image': 'ImageInfo',
'*bps_max': 'int', '*bps_rd_max': 'int',
'*bps_wr_max': 'int', '*iops_max': 'int',
'*iops_rd_max': 'int', '*iops_wr_max': 'int' } }
##
# @BlockDeviceIoStatus:
@ -2174,6 +2189,18 @@
#
# @iops_wr: write I/O operations per second
#
# @bps_max: #optional total max in bytes (Since 1.7)
#
# @bps_rd_max: #optional read max in bytes (Since 1.7)
#
# @bps_wr_max: #optional write max in bytes (Since 1.7)
#
# @iops_max: #optional total I/O operations max (Since 1.7)
#
# @iops_rd_max: #optional read I/O operations max (Since 1.7)
#
# @iops_wr_max: #optional write I/O operations max (Since 1.7)
#
# Returns: Nothing on success
# If @device is not a valid block device, DeviceNotFound
#
@ -2181,7 +2208,10 @@
##
{ 'command': 'block_set_io_throttle',
'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
'*bps_max': 'int', '*bps_rd_max': 'int',
'*bps_wr_max': 'int', '*iops_max': 'int',
'*iops_rd_max': 'int', '*iops_wr_max': 'int' } }
##
# @block-stream:

View File

@ -409,7 +409,10 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
" [,serial=s][,addr=A][,id=name][,aio=threads|native]\n"
" [,readonly=on|off][,copy-on-read=on|off]\n"
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]][[,iops=i]|[[,iops_rd=r][,iops_wr=w]]\n"
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
" [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
" [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
" [[,iops_max=im]|[[,iops_rd_max=irm][,iops_wr_max=iwm]]]\n"
" use 'file' as a drive image\n", QEMU_ARCH_ALL)
STEXI
@item -drive @var{option}[,@var{option}[,@var{option}[,...]]]

View File

@ -1389,7 +1389,7 @@ EQMP
{
.name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?",
.mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
},
@ -1408,6 +1408,12 @@ Arguments:
- "iops": total I/O operations per second (json-int)
- "iops_rd": read I/O operations per second (json-int)
- "iops_wr": write I/O operations per second (json-int)
- "bps_max": total max in bytes (json-int)
- "bps_rd_max": read max in bytes (json-int)
- "bps_wr_max": write max in bytes (json-int)
- "iops_max": total I/O operations max (json-int)
- "iops_rd_max": read I/O operations max (json-int)
- "iops_wr_max": write I/O operations max (json-int)
Example:
@ -1417,7 +1423,13 @@ Example:
"bps_wr": 0,
"iops": 0,
"iops_rd": 0,
"iops_wr": 0 } }
"iops_wr": 0,
"bps_max": 8000000,
"bps_rd_max": 0,
"bps_wr_max": 0,
"iops_max": 0,
"iops_rd_max": 0,
"iops_wr_max": 0 } }
<- { "return": {} }
EQMP
@ -1758,6 +1770,12 @@ Each json-object contain the following:
- "iops": limit total I/O operations per second (json-int)
- "iops_rd": limit read operations per second (json-int)
- "iops_wr": limit write operations per second (json-int)
- "bps_max": total max in bytes (json-int)
- "bps_rd_max": read max in bytes (json-int)
- "bps_wr_max": write max in bytes (json-int)
- "iops_max": total I/O operations max (json-int)
- "iops_rd_max": read I/O operations max (json-int)
- "iops_wr_max": write I/O operations max (json-int)
- "image": the detail of the image, it is a json-object containing
the following:
- "filename": image file name (json-string)
@ -1827,6 +1845,12 @@ Example:
"iops":1000000,
"iops_rd":0,
"iops_wr":0,
"bps_max": 8000000,
"bps_rd_max": 0,
"bps_wr_max": 0,
"iops_max": 0,
"iops_rd_max": 0,
"iops_wr_max": 0,
"image":{
"filename":"disks/test.qcow2",
"format":"qcow2",