diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-02-22 16:55:41 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-02-22 16:55:41 +0000 |
commit | 8eb779e4223a18db9838a49ece1bc72cfdfb7761 (patch) | |
tree | 8b3bac97d620379d579e02cff3bb845f79ccdda3 /tests | |
parent | a02dabe10adc4ae3be54f7413f60dcaa67028389 (diff) | |
parent | fe243e4881bc9e09767dba05f15acb016cfa7a52 (diff) | |
download | qemu-8eb779e4223a18db9838a49ece1bc72cfdfb7761.zip qemu-8eb779e4223a18db9838a49ece1bc72cfdfb7761.tar.gz qemu-8eb779e4223a18db9838a49ece1bc72cfdfb7761.tar.bz2 |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches
# gpg: Signature made Mon 22 Feb 2016 15:59:25 GMT using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
* remotes/kevin/tags/for-upstream: (34 commits)
qemu-iotests: 140: make description slightly more verbose
qemu-iotests: 140: don't use IDE device
qemu-iotests: 067: ignore QMP events
blockdev: unset inappropriate flags when changing medium
MAINTAINERS: Add myself as maintainer of the throttling code
docs: Document the throttling infrastructure
qapi: Correct the name of the iops_rd parameter
qemu-iotests: Extend iotest 093 to test bursts
throttle: Test throttle_compute_wait() during bursts
throttle: Check that burst_level leaks correctly
qapi: Add burst length fields to BlockDeviceInfo
qapi: Add burst length parameters to block_set_io_throttle
throttle: Add command-line settings to define the burst periods
throttle: Add support for burst periods
throttle: Use throttle_config_init() to initialize ThrottleConfig
throttle: Merge all functions that check the configuration into one
throttle: Set always an average value when setting a maximum value
throttle: Make throttle_is_valid() set errp
throttle: Make throttle_max_is_missing_limit() set errp
throttle: Make throttle_conflicting() set errp
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/qemu-iotests/067 | 11 | ||||
-rw-r--r-- | tests/qemu-iotests/067.out | 144 | ||||
-rwxr-xr-x | tests/qemu-iotests/093 | 65 | ||||
-rw-r--r-- | tests/qemu-iotests/093.out | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/140 | 8 | ||||
-rw-r--r-- | tests/qemu-iotests/140.out | 1 | ||||
-rwxr-xr-x | tests/qemu-iotests/145 | 52 | ||||
-rw-r--r-- | tests/qemu-iotests/145.out | 5 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 1 | ||||
-rw-r--r-- | tests/test-throttle.c | 88 |
10 files changed, 194 insertions, 185 deletions
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index 3788534..77dec0d 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -45,11 +45,20 @@ function do_run_qemu() echo } +# Remove QMP events from (pretty-printed) output. Doesn't handle +# nested dicts correctly, but we don't get any of those in this test. +_filter_qmp_events() +{ + tr '\n' '\t' | sed -e \ + 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \ + | tr '\t' '\n' +} + function run_qemu() { do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \ | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \ - | _filter_generated_node_ids + | _filter_generated_node_ids | _filter_qmp_events } size=128M diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out index ae3fccb..7e25a49 100644 --- a/tests/qemu-iotests/067.out +++ b/tests/qemu-iotests/067.out @@ -70,34 +70,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ ] } @@ -105,14 +77,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - === -drive/device_add and device_del === @@ -186,34 +150,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ ] } @@ -221,14 +157,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - === drive_add/device_add and device_del === @@ -305,34 +233,6 @@ Testing: } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ ] } @@ -340,14 +240,6 @@ Testing: "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - === blockdev_add/device_add and device_del === @@ -425,34 +317,6 @@ Testing: } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ { "io-status": "ok", @@ -506,12 +370,4 @@ Testing: "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - *** done diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 index c0e9e2b..ce8e13c 100755 --- a/tests/qemu-iotests/093 +++ b/tests/qemu-iotests/093 @@ -3,7 +3,7 @@ # Tests for IO throttling # # Copyright (C) 2015 Red Hat, Inc. -# Copyright (C) 2015 Igalia, S.L. +# Copyright (C) 2015-2016 Igalia, S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,6 +21,8 @@ import iotests +nsec_per_sec = 1000000000 + class ThrottleTestCase(iotests.QMPTestCase): test_img = "null-aio://" max_drives = 3 @@ -42,16 +44,7 @@ class ThrottleTestCase(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - def do_test_throttle(self, ndrives, seconds, params): - def check_limit(limit, num): - # IO throttling algorithm is discrete, allow 10% error so the test - # is more robust - return limit == 0 or \ - (num < seconds * limit * 1.1 / ndrives - and num > seconds * limit * 0.9 / ndrives) - - nsec_per_sec = 1000000000 - + def configure_throttle(self, ndrives, params): params['group'] = 'test' # Set the I/O throttling parameters to all drives @@ -60,13 +53,21 @@ class ThrottleTestCase(iotests.QMPTestCase): result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) self.assert_qmp(result, 'return', {}) + def do_test_throttle(self, ndrives, seconds, params): + def check_limit(limit, num): + # IO throttling algorithm is discrete, allow 10% error so the test + # is more robust + return limit == 0 or \ + (num < seconds * limit * 1.1 / ndrives + and num > seconds * limit * 0.9 / ndrives) + # Set vm clock to a known value ns = seconds * nsec_per_sec self.vm.qtest("clock_step %d" % ns) - # Submit enough requests. They will drain bps_max and iops_max, but the - # rest requests won't get executed until we advance the virtual clock - # with qtest interface + # Submit enough requests so the throttling mechanism kicks + # in. The throttled requests won't be executed until we + # advance the virtual clock. rq_size = 512 rd_nr = max(params['bps'] / rq_size / 2, params['bps_rd'] / rq_size, @@ -142,8 +143,44 @@ class ThrottleTestCase(iotests.QMPTestCase): for tk in params: limits = dict([(k, 0) for k in params]) limits[tk] = params[tk] * ndrives + self.configure_throttle(ndrives, limits) self.do_test_throttle(ndrives, 5, limits) + def test_burst(self): + params = {"bps": 4096, + "bps_rd": 4096, + "bps_wr": 4096, + "iops": 10, + "iops_rd": 10, + "iops_wr": 10, + } + ndrives = 1 + # Pick each out of all possible params and test + for tk in params: + rate = params[tk] * ndrives + burst_rate = rate * 7 + burst_length = 4 + + # Configure the throttling settings + settings = dict([(k, 0) for k in params]) + settings[tk] = rate + settings['%s_max' % tk] = burst_rate + settings['%s_max_length' % tk] = burst_length + self.configure_throttle(ndrives, settings) + + # Wait for the bucket to empty so we can do bursts + wait_ns = nsec_per_sec * burst_length * burst_rate / rate + self.vm.qtest("clock_step %d" % wait_ns) + + # Test I/O at the max burst rate + limits = dict([(k, 0) for k in params]) + limits[tk] = burst_rate + self.do_test_throttle(ndrives, burst_length, limits) + + # Now test I/O at the normal rate + limits[tk] = rate + self.do_test_throttle(ndrives, 5, limits) + class ThrottleTestCoroutine(ThrottleTestCase): test_img = "null-co://" diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out index fbc63e6..89968f3 100644 --- a/tests/qemu-iotests/093.out +++ b/tests/qemu-iotests/093.out @@ -1,5 +1,5 @@ -.. +.... ---------------------------------------------------------------------- -Ran 2 tests +Ran 4 tests OK diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 index f78c317..05e4506 100755 --- a/tests/qemu-iotests/140 +++ b/tests/qemu-iotests/140 @@ -1,6 +1,10 @@ #!/bin/bash # -# Test case for ejecting a BB with an NBD server attached to it +# Test case for ejecting a BlockBackend with an NBD server attached to it +# +# Verify that the NBD server stops offering the drive when ejecting a +# BlockDriverState tree from a BlockBackend (that is, a medium from a +# drive) exposed via an NBD server. # # Copyright (C) 2016 Red Hat, Inc. # @@ -49,7 +53,7 @@ _make_test_img 64k $QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io keep_stderr=y \ -_launch_qemu -drive if=ide,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \ +_launch_qemu -drive if=none,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \ 2> >(_filter_nbd) _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/140.out b/tests/qemu-iotests/140.out index 72f1b4c..0409cd0 100644 --- a/tests/qemu-iotests/140.out +++ b/tests/qemu-iotests/140.out @@ -7,7 +7,6 @@ wrote 65536/65536 bytes at offset 0 {"return": {}} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "drv", "tray-open": true}} {"return": {}} can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: No export with name 'drv' available no file open, try 'help open' diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 new file mode 100755 index 0000000..7d8febb --- /dev/null +++ b/tests/qemu-iotests/145 @@ -0,0 +1,52 @@ +#!/bin/bash +# +# Test the combination of -incoming and snapshot=on +# +# Copyright (C) 2016 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + true +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +_make_test_img 1M +echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | _filter_qemu + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/145.out b/tests/qemu-iotests/145.out new file mode 100644 index 0000000..75b5c8a --- /dev/null +++ b/tests/qemu-iotests/145.out @@ -0,0 +1,5 @@ +QA output created by 145 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 65df029..47fd40c 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -147,3 +147,4 @@ 142 auto 143 auto quick 144 rw auto quick +145 auto quick diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 858f1aa..59675fa 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -35,6 +35,9 @@ static bool double_cmp(double x, double y) /* tests for single bucket operations */ static void test_leak_bucket(void) { + throttle_config_init(&cfg); + bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; + /* set initial value */ bkt.avg = 150; bkt.max = 15; @@ -57,13 +60,33 @@ static void test_leak_bucket(void) g_assert(bkt.avg == 150); g_assert(bkt.max == 15); g_assert(double_cmp(bkt.level, 0)); + + /* check that burst_level leaks correctly */ + bkt.burst_level = 6; + bkt.max = 250; + bkt.burst_length = 2; /* otherwise burst_level will not leak */ + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 3.5)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 1)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 0)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 0)); } static void test_compute_wait(void) { + unsigned i; int64_t wait; int64_t result; + throttle_config_init(&cfg); + bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; + /* no operation limit set */ bkt.avg = 0; bkt.max = 15; @@ -93,6 +116,27 @@ static void test_compute_wait(void) /* time required to do half an operation */ result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2; g_assert(wait == result); + + /* Perform I/O for 2.2 seconds at a rate of bkt.max */ + bkt.burst_length = 2; + bkt.level = 0; + bkt.avg = 10; + bkt.max = 200; + for (i = 0; i < 22; i++) { + double units = bkt.max / 10; + bkt.level += units; + bkt.burst_level += units; + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 10); + wait = throttle_compute_wait(&bkt); + g_assert(double_cmp(bkt.burst_level, 0)); + g_assert(double_cmp(bkt.level, (i + 1) * (bkt.max - bkt.avg) / 10)); + /* We can do bursts for the 2 seconds we have configured in + * burst_length. We have 100 extra miliseconds of burst + * because bkt.level has been leaking during this time. + * After that, we have to wait. */ + result = i < 21 ? 0 : 1.8 * NANOSECONDS_PER_SECOND; + g_assert(wait == result); + } } /* functions to test ThrottleState initialization/destroy methods */ @@ -222,6 +266,8 @@ static void set_cfg_value(bool is_max, int index, int value) { if (is_max) { cfg.buckets[index].max = value; + /* If max is set, avg should never be 0 */ + cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1); } else { cfg.buckets[index].avg = value; } @@ -231,17 +277,17 @@ static void test_enabled(void) { int i; - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); g_assert(!throttle_enabled(&cfg)); for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(false, i, 150); g_assert(throttle_enabled(&cfg)); } for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(false, i, -150); g_assert(!throttle_enabled(&cfg)); } @@ -254,32 +300,32 @@ static void test_conflicts_for_one_set(bool is_max, int read, int write) { - memset(&cfg, 0, sizeof(cfg)); - g_assert(!throttle_conflicting(&cfg)); + throttle_config_init(&cfg); + g_assert(throttle_is_valid(&cfg, NULL)); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, read, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, write, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, read, 1); set_cfg_value(is_max, write, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); - g_assert(!throttle_conflicting(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, read, 1); set_cfg_value(is_max, write, 1); - g_assert(!throttle_conflicting(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); } static void test_conflicting_config(void) @@ -313,9 +359,9 @@ static void test_is_valid_for_value(int value, bool should_be_valid) int is_max, index; for (is_max = 0; is_max < 2; is_max++) { for (index = 0; index < BUCKETS_COUNT; index++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, index, value); - g_assert(throttle_is_valid(&cfg) == should_be_valid); + g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid); } } } @@ -335,18 +381,18 @@ static void test_max_is_missing_limit(void) int i; for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); cfg.buckets[i].max = 100; cfg.buckets[i].avg = 0; - g_assert(throttle_max_is_missing_limit(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); cfg.buckets[i].max = 0; cfg.buckets[i].avg = 0; - g_assert(!throttle_max_is_missing_limit(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); cfg.buckets[i].max = 0; cfg.buckets[i].avg = 100; - g_assert(!throttle_max_is_missing_limit(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); } } @@ -550,7 +596,7 @@ static void test_groups(void) g_assert(bdrv1->throttle_state == bdrv3->throttle_state); /* Setting the config of a group member affects the whole group */ - memset(&cfg1, 0, sizeof(cfg1)); + throttle_config_init(&cfg1); cfg1.buckets[THROTTLE_BPS_READ].avg = 500000; cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000; cfg1.buckets[THROTTLE_OPS_READ].avg = 20000; |