Re: [Qemu-devel] [PATCH v4 5/5] qemu-iotests: Add 093 for IO throttling

2014-08-27 Thread Fam Zheng
On Tue, 08/26 14:50, Stefan Hajnoczi wrote:
 On Thu, Jun 05, 2014 at 04:47:46PM +0800, Fam Zheng wrote:
  +def setUp(self):
  +qemu_img('create', '-f', iotests.imgfmt, test_img, 1G)
  +#self.vm = iotests.VM().add_drive(test_img, bps=1024,bps_max=1)
 
 Commented out lines should be dropped
 
  +self.vm = iotests.VM().add_drive(test_img)
  +self.vm.launch()
  +
  +def tearDown(self):
  +self.vm.shutdown()
  +os.remove(test_img)
  +
  +def do_test_throttle(self, seconds=10, **limits):
  +def check_limit(limit, num):
  +# IO throttling algorithm is discrete, allow 10% error so the 
  test
  +# is more deterministic
  +return limit == 0 or num  seconds * limit * 1.1
  +
  +nsec_per_sec = 10
  +
  +limits['bps_max'] = 1
  +limits['iops_max'] = 1
  +
  +# Enqueue many requests to throttling queue
 
 This comment is wrong, it actually happens further down
 
  +result = self.vm.qmp(block_set_io_throttle, conv_keys=False, 
  **limits)
  +self.assert_qmp(result, 'return', {})
  +
  +# Set vm clock to a known value
  +ns = nsec_per_sec
  +self.vm.qtest_cmd(clock_step %d % ns)
  +
  +# Append many requests into the throttle queue
  +# They drain bps_max and iops_max
  +# The rest requests won't get executed until qtest clock is driven
  +for i in range(1000):
  +self.vm.hmp_qemu_io(drive0, aio_read -a -q 0 512)
  +self.vm.hmp_qemu_io(drive0, aio_write -a -q 0 512)
  +
  +start_rd_bytes, start_rd_iops, start_wr_bytes, start_wr_iops = 
  self.blockstats('drive0')
  +
  +ns += seconds * nsec_per_sec
  +self.vm.qtest_cmd(clock_step %d % ns)
  +# wait for a while to let requests take off
  +time.sleep(1)
 
 This is not a reliable testing approach.  If the system is under heavy
 load maybe only a few requests completed.  We don't know whether that is
 due to I/O throttling or not.
 
 A reliable test would not perform real disk I/O so the test is
 independent of disk/system speed.  And it would not use time.sleep(1) to
 wait since there is no guarantee that anything happened in the
 meantime.
 
 Do you think this can be improved?

Throttling only sets the upper limit of IO, this test checks the IO doesn't
cross it: when the test fails, something must be wrong with the throttling;
when the check passes, we can't guarantee that everything is correct. That's
not uncommon across many other test cases we have. The other half is very hard,
because of host load, etc., which are out of control of this script.

Regarding to disk IO, I've submitted a separate patch, the null:// protocol,
which can be used to sidestep the host disk load uncertainty. I can base this
test on top.

 
  +end_rd_bytes, end_rd_iops, end_wr_bytes, end_wr_iops = 
  self.blockstats('drive0')
  +
  +rd_bytes = end_rd_bytes - start_rd_bytes
  +rd_iops = end_rd_iops - start_rd_iops
  +wr_bytes = end_wr_bytes - start_wr_bytes
  +wr_iops = end_wr_iops - start_wr_iops
  +
  +assert check_limit(limits['bps'], rd_bytes)
  +assert check_limit(limits['bps_rd'], rd_bytes)
  +assert check_limit(limits['bps'], wr_bytes)
  +assert check_limit(limits['bps_wr'], wr_bytes)
  +assert check_limit(limits['iops'], rd_iops)
  +assert check_limit(limits['iops_rd'], rd_iops)
  +assert check_limit(limits['iops'], wr_iops)
  +assert check_limit(limits['iops_wr'], wr_iops)
 
 Please use TestCase.assert*() methods instead of plain assert.  They
 produce humand-readable error messages including the failing values.

OK.

 
  +
  +def test_bps(self):
  +self.do_test_throttle(**{
  +'device': 'drive0',
  +'bps': 1000,
  +'bps_rd': 0,
  +'bps_wr': 0,
  +'iops': 0,
  +'iops_rd': 0,
  +'iops_wr': 0,
  +})
 
 Keyword argument syntax is more concise:
 
 self.do_test_throttle(device='drive0',
   bps=1000,
 bps_rd=0,
 ...)

OK, will change.

Thanks,
Fam





Re: [Qemu-devel] [PATCH v4 5/5] qemu-iotests: Add 093 for IO throttling

2014-08-27 Thread Stefan Hajnoczi
On Wed, Aug 27, 2014 at 02:19:44PM +0800, Fam Zheng wrote:
 On Tue, 08/26 14:50, Stefan Hajnoczi wrote:
  On Thu, Jun 05, 2014 at 04:47:46PM +0800, Fam Zheng wrote:
   +result = self.vm.qmp(block_set_io_throttle, conv_keys=False, 
   **limits)
   +self.assert_qmp(result, 'return', {})
   +
   +# Set vm clock to a known value
   +ns = nsec_per_sec
   +self.vm.qtest_cmd(clock_step %d % ns)
   +
   +# Append many requests into the throttle queue
   +# They drain bps_max and iops_max
   +# The rest requests won't get executed until qtest clock is 
   driven
   +for i in range(1000):
   +self.vm.hmp_qemu_io(drive0, aio_read -a -q 0 512)
   +self.vm.hmp_qemu_io(drive0, aio_write -a -q 0 512)
   +
   +start_rd_bytes, start_rd_iops, start_wr_bytes, start_wr_iops = 
   self.blockstats('drive0')
   +
   +ns += seconds * nsec_per_sec
   +self.vm.qtest_cmd(clock_step %d % ns)
   +# wait for a while to let requests take off
   +time.sleep(1)
  
  This is not a reliable testing approach.  If the system is under heavy
  load maybe only a few requests completed.  We don't know whether that is
  due to I/O throttling or not.
  
  A reliable test would not perform real disk I/O so the test is
  independent of disk/system speed.  And it would not use time.sleep(1) to
  wait since there is no guarantee that anything happened in the
  meantime.
  
  Do you think this can be improved?
 
 Throttling only sets the upper limit of IO, this test checks the IO doesn't
 cross it: when the test fails, something must be wrong with the throttling;
 when the check passes, we can't guarantee that everything is correct. That's
 not uncommon across many other test cases we have. The other half is very 
 hard,
 because of host load, etc., which are out of control of this script.
 
 Regarding to disk IO, I've submitted a separate patch, the null:// protocol,
 which can be used to sidestep the host disk load uncertainty. I can base this
 test on top.

If both a fake disk and fake timers are used then the execution is
deterministic.  I'll take a look at the null:// protocol you have
posted.

Although I would love this test to be deterministic, I understand it is
tricky to achieve that.  I'd like to discuss making this deterministic
but I'm not opposed to merging the current approach.

Stefan


pgpJp8DWeoagx.pgp
Description: PGP signature


Re: [Qemu-devel] [PATCH v4 5/5] qemu-iotests: Add 093 for IO throttling

2014-08-26 Thread Stefan Hajnoczi
On Thu, Jun 05, 2014 at 04:47:46PM +0800, Fam Zheng wrote:
 +def setUp(self):
 +qemu_img('create', '-f', iotests.imgfmt, test_img, 1G)
 +#self.vm = iotests.VM().add_drive(test_img, bps=1024,bps_max=1)

Commented out lines should be dropped

 +self.vm = iotests.VM().add_drive(test_img)
 +self.vm.launch()
 +
 +def tearDown(self):
 +self.vm.shutdown()
 +os.remove(test_img)
 +
 +def do_test_throttle(self, seconds=10, **limits):
 +def check_limit(limit, num):
 +# IO throttling algorithm is discrete, allow 10% error so the 
 test
 +# is more deterministic
 +return limit == 0 or num  seconds * limit * 1.1
 +
 +nsec_per_sec = 10
 +
 +limits['bps_max'] = 1
 +limits['iops_max'] = 1
 +
 +# Enqueue many requests to throttling queue

This comment is wrong, it actually happens further down

 +result = self.vm.qmp(block_set_io_throttle, conv_keys=False, 
 **limits)
 +self.assert_qmp(result, 'return', {})
 +
 +# Set vm clock to a known value
 +ns = nsec_per_sec
 +self.vm.qtest_cmd(clock_step %d % ns)
 +
 +# Append many requests into the throttle queue
 +# They drain bps_max and iops_max
 +# The rest requests won't get executed until qtest clock is driven
 +for i in range(1000):
 +self.vm.hmp_qemu_io(drive0, aio_read -a -q 0 512)
 +self.vm.hmp_qemu_io(drive0, aio_write -a -q 0 512)
 +
 +start_rd_bytes, start_rd_iops, start_wr_bytes, start_wr_iops = 
 self.blockstats('drive0')
 +
 +ns += seconds * nsec_per_sec
 +self.vm.qtest_cmd(clock_step %d % ns)
 +# wait for a while to let requests take off
 +time.sleep(1)

This is not a reliable testing approach.  If the system is under heavy
load maybe only a few requests completed.  We don't know whether that is
due to I/O throttling or not.

A reliable test would not perform real disk I/O so the test is
independent of disk/system speed.  And it would not use time.sleep(1) to
wait since there is no guarantee that anything happened in the
meantime.

Do you think this can be improved?

 +end_rd_bytes, end_rd_iops, end_wr_bytes, end_wr_iops = 
 self.blockstats('drive0')
 +
 +rd_bytes = end_rd_bytes - start_rd_bytes
 +rd_iops = end_rd_iops - start_rd_iops
 +wr_bytes = end_wr_bytes - start_wr_bytes
 +wr_iops = end_wr_iops - start_wr_iops
 +
 +assert check_limit(limits['bps'], rd_bytes)
 +assert check_limit(limits['bps_rd'], rd_bytes)
 +assert check_limit(limits['bps'], wr_bytes)
 +assert check_limit(limits['bps_wr'], wr_bytes)
 +assert check_limit(limits['iops'], rd_iops)
 +assert check_limit(limits['iops_rd'], rd_iops)
 +assert check_limit(limits['iops'], wr_iops)
 +assert check_limit(limits['iops_wr'], wr_iops)

Please use TestCase.assert*() methods instead of plain assert.  They
produce humand-readable error messages including the failing values.

 +
 +def test_bps(self):
 +self.do_test_throttle(**{
 +'device': 'drive0',
 +'bps': 1000,
 +'bps_rd': 0,
 +'bps_wr': 0,
 +'iops': 0,
 +'iops_rd': 0,
 +'iops_wr': 0,
 +})

Keyword argument syntax is more concise:

self.do_test_throttle(device='drive0',
  bps=1000,
  bps_rd=0,
  ...)


pgpZnfys40EXb.pgp
Description: PGP signature


[Qemu-devel] [PATCH v4 5/5] qemu-iotests: Add 093 for IO throttling

2014-06-05 Thread Fam Zheng
This case utilizes qemu-io command aio_{read,write} -a -q to verify
the effectiveness of IO throttling options.

The -a option will cause qemu-io requests to be accounted.

It's implemented by driving the vm timer from qtest protocol, so the
throttling timers are signaled with determinied time duration. Then we
verify the completed IO requests are within 110% of bps and iops limits.

Signed-off-by: Fam Zheng f...@redhat.com
Reviewed-by: Benoit Canet ben...@irqsave.net
---
 tests/qemu-iotests/093 | 164 +
 tests/qemu-iotests/093.out |   5 ++
 2 files changed, 169 insertions(+)
 create mode 100755 tests/qemu-iotests/093
 create mode 100644 tests/qemu-iotests/093.out

diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093
new file mode 100755
index 000..222bb37
--- /dev/null
+++ b/tests/qemu-iotests/093
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+#
+# Tests for IO throttling
+#
+# Copyright (C) 2014 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/.
+#
+
+import time
+import os
+import iotests
+from iotests import qemu_img
+
+test_img = os.path.join(iotests.test_dir, 'test.img')
+
+class ThrottleTestCase(iotests.QMPTestCase):
+image_len = 80 * 1024 * 1024 # MB
+
+def blockstats(self, device):
+result = self.vm.qmp(query-blockstats)
+for r in result['return']:
+if r['device'] == device:
+stat = r['stats']
+return stat['rd_bytes'], stat['rd_operations'], 
stat['wr_bytes'], stat['wr_operations']
+raise Exception(Device not found for blockstats: %s % device)
+
+def setUp(self):
+qemu_img('create', '-f', iotests.imgfmt, test_img, 1G)
+#self.vm = iotests.VM().add_drive(test_img, bps=1024,bps_max=1)
+self.vm = iotests.VM().add_drive(test_img)
+self.vm.launch()
+
+def tearDown(self):
+self.vm.shutdown()
+os.remove(test_img)
+
+def do_test_throttle(self, seconds=10, **limits):
+def check_limit(limit, num):
+# IO throttling algorithm is discrete, allow 10% error so the test
+# is more deterministic
+return limit == 0 or num  seconds * limit * 1.1
+
+nsec_per_sec = 10
+
+limits['bps_max'] = 1
+limits['iops_max'] = 1
+
+# Enqueue many requests to throttling queue
+result = self.vm.qmp(block_set_io_throttle, conv_keys=False, 
**limits)
+self.assert_qmp(result, 'return', {})
+
+# Set vm clock to a known value
+ns = nsec_per_sec
+self.vm.qtest_cmd(clock_step %d % ns)
+
+# Append many requests into the throttle queue
+# They drain bps_max and iops_max
+# The rest requests won't get executed until qtest clock is driven
+for i in range(1000):
+self.vm.hmp_qemu_io(drive0, aio_read -a -q 0 512)
+self.vm.hmp_qemu_io(drive0, aio_write -a -q 0 512)
+
+start_rd_bytes, start_rd_iops, start_wr_bytes, start_wr_iops = 
self.blockstats('drive0')
+
+ns += seconds * nsec_per_sec
+self.vm.qtest_cmd(clock_step %d % ns)
+# wait for a while to let requests take off
+time.sleep(1)
+end_rd_bytes, end_rd_iops, end_wr_bytes, end_wr_iops = 
self.blockstats('drive0')
+
+rd_bytes = end_rd_bytes - start_rd_bytes
+rd_iops = end_rd_iops - start_rd_iops
+wr_bytes = end_wr_bytes - start_wr_bytes
+wr_iops = end_wr_iops - start_wr_iops
+
+assert check_limit(limits['bps'], rd_bytes)
+assert check_limit(limits['bps_rd'], rd_bytes)
+assert check_limit(limits['bps'], wr_bytes)
+assert check_limit(limits['bps_wr'], wr_bytes)
+assert check_limit(limits['iops'], rd_iops)
+assert check_limit(limits['iops_rd'], rd_iops)
+assert check_limit(limits['iops'], wr_iops)
+assert check_limit(limits['iops_wr'], wr_iops)
+
+def test_bps(self):
+self.do_test_throttle(**{
+'device': 'drive0',
+'bps': 1000,
+'bps_rd': 0,
+'bps_wr': 0,
+'iops': 0,
+'iops_rd': 0,
+'iops_wr': 0,
+})
+
+def test_bps_rd(self):
+self.do_test_throttle(**{
+'device': 'drive0',
+'bps': 0,
+'bps_rd': 1000,
+'bps_wr': 0,
+