All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling
@ 2014-02-11  6:40 Fam Zheng
  2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 1/5] qemu-io: Account IO by aio_read and aio_write Fam Zheng
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Fam Zheng @ 2014-02-11  6:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Benoît Canet, Stefan Hajnoczi, pbonzini

This series adds iotest case for IO throttling.

There is a change in qemu-io sub-commands "aio_read" and "aio_write", which
makes the aio requests accounted and the statistics reflected in blockstats.

Note that IO throttling implementation allows overcommiting of requests, so the
actual IO happened in a time unit may be a bit larger than given limits. In the
test case, the stats numbers are compared against 110%, to make room for such
flexibility in order to improve determinism.

v3: Address comments from Benoît. (Thanks for the review!)

    [02/05] qtest: Add scripts/qtest/qtest.py
            Fix comments.
            Fix socket close order.
            Removed unused lines.

    [03/05] qemu-iotests: Add VM method qtest() to iotests.py
            Remove duplicated VM.qtest definition.

    [05/05] qemu-iotests: Add 080 for IO throttling
            Check for lower bound (0.9 * limit * seconds).
            Remove unused lines.
            Fix checking of total bps and iops by adding up read and write.



Fam Zheng (5):
  qemu-io: Account IO by aio_read and aio_write
  qtest: Add scripts/qtest/qtest.py
  qemu-iotests: Add VM method qtest() to iotests.py
  qemu-iotests: Allow caller to disable underscore convertion for qmp
  qemu-iotests: Add 080 for IO throttling

 qemu-io-cmds.c                |  10 +++
 scripts/qtest                 |   5 --
 scripts/qtest/qtest.py        |  74 ++++++++++++++++++
 tests/qemu-iotests/080        | 175 ++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/080.out    |   5 ++
 tests/qemu-iotests/group      |   1 +
 tests/qemu-iotests/iotests.py |  24 +++++-
 7 files changed, 285 insertions(+), 9 deletions(-)
 delete mode 100755 scripts/qtest
 create mode 100644 scripts/qtest/qtest.py
 create mode 100755 tests/qemu-iotests/080
 create mode 100644 tests/qemu-iotests/080.out

-- 
1.8.5.4

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 1/5] qemu-io: Account IO by aio_read and aio_write
  2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
@ 2014-02-11  6:40 ` Fam Zheng
  2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 2/5] qtest: Add scripts/qtest/qtest.py Fam Zheng
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Fam Zheng @ 2014-02-11  6:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Benoît Canet, Stefan Hajnoczi, pbonzini

This will enable accounting of aio requests issued from qemu-io aio
read/write commands.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
---
 qemu-io-cmds.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index f1de24c..d68eb23 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1346,6 +1346,7 @@ out:
 }
 
 struct aio_ctx {
+    BlockDriverState *bs;
     QEMUIOVector qiov;
     int64_t offset;
     char *buf;
@@ -1353,6 +1354,7 @@ struct aio_ctx {
     int vflag;
     int Cflag;
     int Pflag;
+    BlockAcctCookie acct;
     int pattern;
     struct timeval t1;
 };
@@ -1370,6 +1372,8 @@ static void aio_write_done(void *opaque, int ret)
         goto out;
     }
 
+    bdrv_acct_done(ctx->bs, &ctx->acct);
+
     if (ctx->qflag) {
         goto out;
     }
@@ -1407,6 +1411,8 @@ static void aio_read_done(void *opaque, int ret)
         g_free(cmp_buf);
     }
 
+    bdrv_acct_done(ctx->bs, &ctx->acct);
+
     if (ctx->qflag) {
         goto out;
     }
@@ -1462,6 +1468,7 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
     int nr_iov, c;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
+    ctx->bs = bs;
     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
         switch (c) {
         case 'C':
@@ -1515,6 +1522,7 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     gettimeofday(&ctx->t1, NULL);
+    bdrv_acct_start(bs, &ctx->acct, ctx->qiov.size, BDRV_ACCT_READ);
     bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
                    ctx->qiov.size >> 9, aio_read_done, ctx);
     return 0;
@@ -1558,6 +1566,7 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
     int pattern = 0xcd;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
+    ctx->bs = bs;
     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
         switch (c) {
         case 'C':
@@ -1607,6 +1616,7 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     gettimeofday(&ctx->t1, NULL);
+    bdrv_acct_start(bs, &ctx->acct, ctx->qiov.size, BDRV_ACCT_WRITE);
     bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
                     ctx->qiov.size >> 9, aio_write_done, ctx);
     return 0;
-- 
1.8.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 2/5] qtest: Add scripts/qtest/qtest.py
  2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
  2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 1/5] qemu-io: Account IO by aio_read and aio_write Fam Zheng
@ 2014-02-11  6:40 ` Fam Zheng
  2014-02-11 10:41   ` Benoît Canet
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 3/5] qemu-iotests: Add VM method qtest() to iotests.py Fam Zheng
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Fam Zheng @ 2014-02-11  6:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Benoît Canet, Stefan Hajnoczi, pbonzini

This removes the dummy scripts/qtest and adds scripts/qtest/qtest.py as
a python library for qtest protocol.

This is a skeleton with a basic "cmd" method to execute a command,
reading and parsing of qtest output will be added later on demand.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 scripts/qtest          |  5 ----
 scripts/qtest/qtest.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 5 deletions(-)
 delete mode 100755 scripts/qtest
 create mode 100644 scripts/qtest/qtest.py

diff --git a/scripts/qtest b/scripts/qtest
deleted file mode 100755
index 4ef6c1c..0000000
--- a/scripts/qtest
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-export QTEST_QEMU_BINARY=$1
-shift
-"$@"
diff --git a/scripts/qtest/qtest.py b/scripts/qtest/qtest.py
new file mode 100644
index 0000000..16c6713
--- /dev/null
+++ b/scripts/qtest/qtest.py
@@ -0,0 +1,74 @@
+# QEMU qtest library
+#
+# Copyright (C) 2014 Red Hat Inc.
+#
+# Authors:
+#  Fam Zheng <famz@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+# Based on qmp.py.
+#
+
+import errno
+import socket
+
+class QEMUQtestProtocol:
+    def __init__(self, address, server=False):
+        """
+        Create a QEMUQtestProtocol object.
+
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @param server: server mode listens on the socket (bool)
+        @raise socket.error on socket connection errors
+        @note No connection is established, this is done by the connect() or
+              accept() methods
+        """
+        self.__address = address
+        self.__sock = self.__get_sock()
+        if server:
+            self.__sock.bind(self.__address)
+            self.__sock.listen(1)
+
+    def __get_sock(self):
+        if isinstance(self.__address, tuple):
+            family = socket.AF_INET
+        else:
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
+
+    def connect(self):
+        """
+        Connect to the qtest socket.
+
+        @raise socket.error on socket connection errors
+        """
+        self.__sock.connect(self.__address)
+        self.__sockfile = self.__sock.makefile()
+
+    def accept(self):
+        """
+        Await connection from QEMU.
+
+        @raise socket.error on socket connection errors
+        """
+        self.__sock, _ = self.__sock.accept()
+        self.__sockfile = self.__sock.makefile()
+
+    def cmd(self, qtest_cmd):
+        """
+        Send a qtest command on the wire.
+
+        @param qtest_cmd: qtest command text to be sent
+        """
+        self.__sock.sendall(qtest_cmd + "\n")
+
+    def close(self):
+        self.__sockfile.close()
+        self.__sock.close()
+
+    def settimeout(self, timeout):
+        self.__sock.settimeout(timeout)
-- 
1.8.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 3/5] qemu-iotests: Add VM method qtest() to iotests.py
  2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
  2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 1/5] qemu-io: Account IO by aio_read and aio_write Fam Zheng
  2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 2/5] qtest: Add scripts/qtest/qtest.py Fam Zheng
@ 2014-02-11  6:41 ` Fam Zheng
  2014-02-11 10:58   ` Benoît Canet
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 4/5] qemu-iotests: Allow caller to disable underscore convertion for qmp Fam Zheng
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Fam Zheng @ 2014-02-11  6:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Benoît Canet, Stefan Hajnoczi, pbonzini

This will allow test case to run command in qtest protocol. It's
write-only for now.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/qemu-iotests/iotests.py | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e4fa9af..27547ac 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -21,9 +21,13 @@ import re
 import subprocess
 import string
 import unittest
-import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp'))
+import sys
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp'))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qtest'))
 import qmp
+import qtest
 import struct
+import socket
 
 __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
            'VM', 'QMPTestCase', 'notrun', 'main']
@@ -80,10 +84,12 @@ class VM(object):
     def __init__(self):
         self._monitor_path = os.path.join(test_dir, 'qemu-mon.%d' % os.getpid())
         self._qemu_log_path = os.path.join(test_dir, 'qemu-log.%d' % os.getpid())
+        self._qtest_path = os.path.join(test_dir, 'qemu-qtest.%d' % os.getpid())
         self._args = qemu_args + ['-chardev',
                      'socket,id=mon,path=' + self._monitor_path,
                      '-mon', 'chardev=mon,mode=control',
-                     '-qtest', 'stdio', '-machine', 'accel=qtest',
+                     '-qtest', 'unix:path=' + self._qtest_path,
+                     '-machine', 'accel=qtest',
                      '-display', 'none', '-vga', 'none']
         self._num_drives = 0
 
@@ -159,9 +165,11 @@ class VM(object):
         qemulog = open(self._qemu_log_path, 'wb')
         try:
             self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True)
+            self._qtest = qtest.QEMUQtestProtocol(self._qtest_path, server=True)
             self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog,
                                            stderr=subprocess.STDOUT)
             self._qmp.accept()
+            self._qtest.accept()
         except:
             os.remove(self._monitor_path)
             raise
@@ -172,6 +180,7 @@ class VM(object):
             self._qmp.cmd('quit')
             self._popen.wait()
             os.remove(self._monitor_path)
+            os.remove(self._qtest_path)
             os.remove(self._qemu_log_path)
             self._popen = None
 
@@ -184,6 +193,10 @@ class VM(object):
 
         return self._qmp.cmd(cmd, args=qmp_args)
 
+    def qtest(self, cmd):
+        '''Send a qtest command to guest'''
+        return self._qtest.cmd(cmd)
+
     def get_qmp_event(self, wait=False):
         '''Poll for one queued QMP events and return it'''
         return self._qmp.pull_event(wait=wait)
-- 
1.8.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 4/5] qemu-iotests: Allow caller to disable underscore convertion for qmp
  2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
                   ` (2 preceding siblings ...)
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 3/5] qemu-iotests: Add VM method qtest() to iotests.py Fam Zheng
@ 2014-02-11  6:41 ` Fam Zheng
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 5/5] qemu-iotests: Add 080 for IO throttling Fam Zheng
  2014-06-02 13:41 ` [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case " Stefan Hajnoczi
  5 siblings, 0 replies; 10+ messages in thread
From: Fam Zheng @ 2014-02-11  6:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Benoît Canet, Stefan Hajnoczi, pbonzini

QMP command "block_set_io_throttle" expects underscores in parameters
instead of dashes: {iops,bps}_{rd,wr,max}.

Add optional argument conv_keys (defaults to True, backward compatible),
it will be used in IO throttling test case.

Reviewed-by: Benoit Canet <benoit@irqsave.net>
Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/qemu-iotests/iotests.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 27547ac..8a11419 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -185,11 +185,14 @@ class VM(object):
             self._popen = None
 
     underscore_to_dash = string.maketrans('_', '-')
-    def qmp(self, cmd, **args):
+    def qmp(self, cmd, conv_keys=True, **args):
         '''Invoke a QMP command and return the result dict'''
         qmp_args = dict()
         for k in args.keys():
-            qmp_args[k.translate(self.underscore_to_dash)] = args[k]
+            if conv_keys:
+                qmp_args[k.translate(self.underscore_to_dash)] = args[k]
+            else:
+                qmp_args[k] = args[k]
 
         return self._qmp.cmd(cmd, args=qmp_args)
 
-- 
1.8.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 5/5] qemu-iotests: Add 080 for IO throttling
  2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
                   ` (3 preceding siblings ...)
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 4/5] qemu-iotests: Allow caller to disable underscore convertion for qmp Fam Zheng
@ 2014-02-11  6:41 ` Fam Zheng
  2014-02-11 10:41   ` Benoît Canet
  2014-06-02 13:41 ` [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case " Stefan Hajnoczi
  5 siblings, 1 reply; 10+ messages in thread
From: Fam Zheng @ 2014-02-11  6:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Benoît Canet, Stefan Hajnoczi, pbonzini

This case utilizes qemu-io command "aio_{read,write} -q" to verify the
effectiveness of IO throttling options.

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

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/qemu-iotests/080     | 175 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/080.out |   5 ++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 181 insertions(+)
 create mode 100755 tests/qemu-iotests/080
 create mode 100644 tests/qemu-iotests/080.out

diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
new file mode 100755
index 0000000..9e2c762
--- /dev/null
+++ b/tests/qemu-iotests/080
@@ -0,0 +1,175 @@
+#!/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):
+
+    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)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(test_img)
+
+    def do_test_throttle(self, seconds=20, **limits):
+        def check_limit(limit, num):
+            # IO throttling algorithm is discrete, allow 10% error so the test
+            # is more deterministic
+            v = limit * seconds
+            return limit == 0 or v * 0.9 <= num <= v * 1.1
+
+        nsec_per_sec = 1000000000
+
+        # With current interface we can't set burst to 0, they will be override
+        # to bps / 10 and iops / 10. Setting to 1 workarounds this and gets to
+        # a close effect as no burst, which is good enough for us
+        limits['bps_max'] = 1
+        limits['iops_max'] = 1
+
+        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("clock_step %d" % ns)
+
+        # Append more than needed requests into the throttle queue, they should
+        # drain bps_max and iops_max.
+        # The remaining requests won't get executed until qtest clock is driven
+        n = max(limits['iops'],
+                limits['iops_rd'],
+                limits['iops_wr'],
+                limits['bps'] / 512,
+                limits['bps_rd'] / 512,
+                limits['bps_wr'] / 512) * seconds + 100
+        for i in range(n):
+            self.vm.hmp_qemu_io("drive0", "aio_read -q 0 512")
+            self.vm.hmp_qemu_io("drive0", "aio_write -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("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')
+
+        # Read and write requests should be processed
+        assert end_rd_bytes > 0
+        assert end_rd_iops > 0
+        assert end_wr_bytes > 0
+        assert end_wr_iops > 0
+
+        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 + wr_bytes)
+        assert check_limit(limits['bps_rd'], rd_bytes)
+        assert check_limit(limits['bps_wr'], wr_bytes)
+        assert check_limit(limits['iops'], rd_iops + wr_iops)
+        assert check_limit(limits['iops_rd'], rd_iops)
+        assert check_limit(limits['iops_wr'], wr_iops)
+
+    def test_bps(self):
+        self.do_test_throttle(**{
+            'device': 'drive0',
+            'bps': 1024,
+            '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': 1024,
+            'bps_wr': 0,
+            'iops': 0,
+            'iops_rd': 0,
+            'iops_wr': 0,
+            })
+
+    def test_bps_wr(self):
+        self.do_test_throttle(**{
+            'device': 'drive0',
+            'bps': 0,
+            'bps_rd': 0,
+            'bps_wr': 1024,
+            'iops': 0,
+            'iops_rd': 0,
+            'iops_wr': 0,
+            })
+
+    def test_iops(self):
+        self.do_test_throttle(**{
+            'device': 'drive0',
+            'bps': 0,
+            'bps_rd': 0,
+            'bps_wr': 0,
+            'iops': 10,
+            'iops_rd': 0,
+            'iops_wr': 0,
+            })
+
+    def test_iops_rd(self):
+        self.do_test_throttle(**{
+            'device': 'drive0',
+            'bps': 0,
+            'bps_rd': 0,
+            'bps_wr': 0,
+            'iops': 0,
+            'iops_rd': 10,
+            'iops_wr': 0,
+            })
+
+    def test_iops_wr(self):
+        self.do_test_throttle(**{
+            'device': 'drive0',
+            'bps': 0,
+            'bps_rd': 0,
+            'bps_wr': 0,
+            'iops': 0,
+            'iops_rd': 0,
+            'iops_wr': 10,
+            })
+
+if __name__ == '__main__':
+    iotests.main()
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
new file mode 100644
index 0000000..3f8a935
--- /dev/null
+++ b/tests/qemu-iotests/080.out
@@ -0,0 +1,5 @@
+......
+----------------------------------------------------------------------
+Ran 6 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 03c762f..013a7ef 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -82,3 +82,4 @@
 073 rw auto
 074 rw auto
 077 rw auto
+080 rw auto
-- 
1.8.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/5] qtest: Add scripts/qtest/qtest.py
  2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 2/5] qtest: Add scripts/qtest/qtest.py Fam Zheng
@ 2014-02-11 10:41   ` Benoît Canet
  0 siblings, 0 replies; 10+ messages in thread
From: Benoît Canet @ 2014-02-11 10:41 UTC (permalink / raw)
  To: Fam Zheng
  Cc: Kevin Wolf, Benoît Canet, qemu-devel, Stefan Hajnoczi, pbonzini

The Tuesday 11 Feb 2014 à 14:40:59 (+0800), Fam Zheng wrote :
> This removes the dummy scripts/qtest and adds scripts/qtest/qtest.py as
> a python library for qtest protocol.
> 
> This is a skeleton with a basic "cmd" method to execute a command,
> reading and parsing of qtest output will be added later on demand.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  scripts/qtest          |  5 ----
>  scripts/qtest/qtest.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 74 insertions(+), 5 deletions(-)
>  delete mode 100755 scripts/qtest
>  create mode 100644 scripts/qtest/qtest.py
> 
> diff --git a/scripts/qtest b/scripts/qtest
> deleted file mode 100755
> index 4ef6c1c..0000000
> --- a/scripts/qtest
> +++ /dev/null
> @@ -1,5 +0,0 @@
> -#!/bin/sh
> -
> -export QTEST_QEMU_BINARY=$1
> -shift
> -"$@"
> diff --git a/scripts/qtest/qtest.py b/scripts/qtest/qtest.py
> new file mode 100644
> index 0000000..16c6713
> --- /dev/null
> +++ b/scripts/qtest/qtest.py
> @@ -0,0 +1,74 @@
> +# QEMU qtest library
> +#
> +# Copyright (C) 2014 Red Hat Inc.
> +#
> +# Authors:
> +#  Fam Zheng <famz@redhat.com>
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2.  See
> +# the COPYING file in the top-level directory.
> +#
> +# Based on qmp.py.
> +#
> +
> +import errno
> +import socket
> +
> +class QEMUQtestProtocol:
> +    def __init__(self, address, server=False):
> +        """
> +        Create a QEMUQtestProtocol object.
> +
> +        @param address: QEMU address, can be either a unix socket path (string)
> +                        or a tuple in the form ( address, port ) for a TCP
> +                        connection
> +        @param server: server mode listens on the socket (bool)
> +        @raise socket.error on socket connection errors
> +        @note No connection is established, this is done by the connect() or
> +              accept() methods
> +        """
> +        self.__address = address
> +        self.__sock = self.__get_sock()
> +        if server:
> +            self.__sock.bind(self.__address)
> +            self.__sock.listen(1)
> +
> +    def __get_sock(self):
> +        if isinstance(self.__address, tuple):
> +            family = socket.AF_INET
> +        else:
> +            family = socket.AF_UNIX
> +        return socket.socket(family, socket.SOCK_STREAM)
> +
> +    def connect(self):
> +        """
> +        Connect to the qtest socket.
> +
> +        @raise socket.error on socket connection errors
> +        """
> +        self.__sock.connect(self.__address)
> +        self.__sockfile = self.__sock.makefile()
> +
> +    def accept(self):
> +        """
> +        Await connection from QEMU.
> +
> +        @raise socket.error on socket connection errors
> +        """
> +        self.__sock, _ = self.__sock.accept()
> +        self.__sockfile = self.__sock.makefile()
> +
> +    def cmd(self, qtest_cmd):
> +        """
> +        Send a qtest command on the wire.
> +
> +        @param qtest_cmd: qtest command text to be sent
> +        """
> +        self.__sock.sendall(qtest_cmd + "\n")
> +
> +    def close(self):
> +        self.__sockfile.close()
> +        self.__sock.close()
> +
> +    def settimeout(self, timeout):
> +        self.__sock.settimeout(timeout)
> -- 
> 1.8.5.4
> 
Reviewed-by: Benoit Canet <benoit@irqsave.net>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 5/5] qemu-iotests: Add 080 for IO throttling
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 5/5] qemu-iotests: Add 080 for IO throttling Fam Zheng
@ 2014-02-11 10:41   ` Benoît Canet
  0 siblings, 0 replies; 10+ messages in thread
From: Benoît Canet @ 2014-02-11 10:41 UTC (permalink / raw)
  To: Fam Zheng
  Cc: Kevin Wolf, Benoît Canet, qemu-devel, Stefan Hajnoczi, pbonzini

The Tuesday 11 Feb 2014 à 14:41:02 (+0800), Fam Zheng wrote :
> This case utilizes qemu-io command "aio_{read,write} -q" to verify the
> effectiveness of IO throttling options.
> 
> It's implemented by driving the vm timer from qtest protocol, so the
> throttling timers are signaled with determined time duration. Then we
> verify the completed IO requests are within 110% of bps and iops limits.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  tests/qemu-iotests/080     | 175 +++++++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/080.out |   5 ++
>  tests/qemu-iotests/group   |   1 +
>  3 files changed, 181 insertions(+)
>  create mode 100755 tests/qemu-iotests/080
>  create mode 100644 tests/qemu-iotests/080.out
> 
> diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
> new file mode 100755
> index 0000000..9e2c762
> --- /dev/null
> +++ b/tests/qemu-iotests/080
> @@ -0,0 +1,175 @@
> +#!/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):
> +
> +    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)
> +        self.vm.launch()
> +
> +    def tearDown(self):
> +        self.vm.shutdown()
> +        os.remove(test_img)
> +
> +    def do_test_throttle(self, seconds=20, **limits):
> +        def check_limit(limit, num):
> +            # IO throttling algorithm is discrete, allow 10% error so the test
> +            # is more deterministic
> +            v = limit * seconds
> +            return limit == 0 or v * 0.9 <= num <= v * 1.1
> +
> +        nsec_per_sec = 1000000000
> +
> +        # With current interface we can't set burst to 0, they will be override
> +        # to bps / 10 and iops / 10. Setting to 1 workarounds this and gets to
> +        # a close effect as no burst, which is good enough for us
> +        limits['bps_max'] = 1
> +        limits['iops_max'] = 1
> +
> +        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("clock_step %d" % ns)
> +
> +        # Append more than needed requests into the throttle queue, they should
> +        # drain bps_max and iops_max.
> +        # The remaining requests won't get executed until qtest clock is driven
> +        n = max(limits['iops'],
> +                limits['iops_rd'],
> +                limits['iops_wr'],
> +                limits['bps'] / 512,
> +                limits['bps_rd'] / 512,
> +                limits['bps_wr'] / 512) * seconds + 100
> +        for i in range(n):
> +            self.vm.hmp_qemu_io("drive0", "aio_read -q 0 512")
> +            self.vm.hmp_qemu_io("drive0", "aio_write -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("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')
> +
> +        # Read and write requests should be processed
> +        assert end_rd_bytes > 0
> +        assert end_rd_iops > 0
> +        assert end_wr_bytes > 0
> +        assert end_wr_iops > 0
> +
> +        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 + wr_bytes)
> +        assert check_limit(limits['bps_rd'], rd_bytes)
> +        assert check_limit(limits['bps_wr'], wr_bytes)
> +        assert check_limit(limits['iops'], rd_iops + wr_iops)
> +        assert check_limit(limits['iops_rd'], rd_iops)
> +        assert check_limit(limits['iops_wr'], wr_iops)
> +
> +    def test_bps(self):
> +        self.do_test_throttle(**{
> +            'device': 'drive0',
> +            'bps': 1024,
> +            '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': 1024,
> +            'bps_wr': 0,
> +            'iops': 0,
> +            'iops_rd': 0,
> +            'iops_wr': 0,
> +            })
> +
> +    def test_bps_wr(self):
> +        self.do_test_throttle(**{
> +            'device': 'drive0',
> +            'bps': 0,
> +            'bps_rd': 0,
> +            'bps_wr': 1024,
> +            'iops': 0,
> +            'iops_rd': 0,
> +            'iops_wr': 0,
> +            })
> +
> +    def test_iops(self):
> +        self.do_test_throttle(**{
> +            'device': 'drive0',
> +            'bps': 0,
> +            'bps_rd': 0,
> +            'bps_wr': 0,
> +            'iops': 10,
> +            'iops_rd': 0,
> +            'iops_wr': 0,
> +            })
> +
> +    def test_iops_rd(self):
> +        self.do_test_throttle(**{
> +            'device': 'drive0',
> +            'bps': 0,
> +            'bps_rd': 0,
> +            'bps_wr': 0,
> +            'iops': 0,
> +            'iops_rd': 10,
> +            'iops_wr': 0,
> +            })
> +
> +    def test_iops_wr(self):
> +        self.do_test_throttle(**{
> +            'device': 'drive0',
> +            'bps': 0,
> +            'bps_rd': 0,
> +            'bps_wr': 0,
> +            'iops': 0,
> +            'iops_rd': 0,
> +            'iops_wr': 10,
> +            })
> +
> +if __name__ == '__main__':
> +    iotests.main()
> diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
> new file mode 100644
> index 0000000..3f8a935
> --- /dev/null
> +++ b/tests/qemu-iotests/080.out
> @@ -0,0 +1,5 @@
> +......
> +----------------------------------------------------------------------
> +Ran 6 tests
> +
> +OK
> diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
> index 03c762f..013a7ef 100644
> --- a/tests/qemu-iotests/group
> +++ b/tests/qemu-iotests/group
> @@ -82,3 +82,4 @@
>  073 rw auto
>  074 rw auto
>  077 rw auto
> +080 rw auto
> -- 
> 1.8.5.4
> 
Reviewed-by: Benoit Canet <benoit@irqsave.net>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/5] qemu-iotests: Add VM method qtest() to iotests.py
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 3/5] qemu-iotests: Add VM method qtest() to iotests.py Fam Zheng
@ 2014-02-11 10:58   ` Benoît Canet
  0 siblings, 0 replies; 10+ messages in thread
From: Benoît Canet @ 2014-02-11 10:58 UTC (permalink / raw)
  To: Fam Zheng
  Cc: Kevin Wolf, Benoît Canet, qemu-devel, Stefan Hajnoczi, pbonzini

The Tuesday 11 Feb 2014 à 14:41:00 (+0800), Fam Zheng wrote :
> This will allow test case to run command in qtest protocol. It's
> write-only for now.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  tests/qemu-iotests/iotests.py | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index e4fa9af..27547ac 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -21,9 +21,13 @@ import re
>  import subprocess
>  import string
>  import unittest
> -import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp'))
> +import sys
> +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp'))
> +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qtest'))
>  import qmp
> +import qtest
>  import struct
> +import socket
>  
>  __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
>             'VM', 'QMPTestCase', 'notrun', 'main']
> @@ -80,10 +84,12 @@ class VM(object):
>      def __init__(self):
>          self._monitor_path = os.path.join(test_dir, 'qemu-mon.%d' % os.getpid())
>          self._qemu_log_path = os.path.join(test_dir, 'qemu-log.%d' % os.getpid())
> +        self._qtest_path = os.path.join(test_dir, 'qemu-qtest.%d' % os.getpid())
>          self._args = qemu_args + ['-chardev',
>                       'socket,id=mon,path=' + self._monitor_path,
>                       '-mon', 'chardev=mon,mode=control',
> -                     '-qtest', 'stdio', '-machine', 'accel=qtest',
> +                     '-qtest', 'unix:path=' + self._qtest_path,
> +                     '-machine', 'accel=qtest',
>                       '-display', 'none', '-vga', 'none']
>          self._num_drives = 0
>  
> @@ -159,9 +165,11 @@ class VM(object):
>          qemulog = open(self._qemu_log_path, 'wb')
>          try:
>              self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True)
> +            self._qtest = qtest.QEMUQtestProtocol(self._qtest_path, server=True)
>              self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog,
>                                             stderr=subprocess.STDOUT)
>              self._qmp.accept()
> +            self._qtest.accept()
>          except:
>              os.remove(self._monitor_path)
>              raise
> @@ -172,6 +180,7 @@ class VM(object):
>              self._qmp.cmd('quit')
>              self._popen.wait()
>              os.remove(self._monitor_path)
> +            os.remove(self._qtest_path)
>              os.remove(self._qemu_log_path)
>              self._popen = None
>  
> @@ -184,6 +193,10 @@ class VM(object):
>  
>          return self._qmp.cmd(cmd, args=qmp_args)
>  
> +    def qtest(self, cmd):
> +        '''Send a qtest command to guest'''
> +        return self._qtest.cmd(cmd)
> +
>      def get_qmp_event(self, wait=False):
>          '''Poll for one queued QMP events and return it'''
>          return self._qmp.pull_event(wait=wait)
> -- 
> 1.8.5.4
> 
> 

Reviewed-by: Benoit Canet <benoit@irqsave.net>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling
  2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
                   ` (4 preceding siblings ...)
  2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 5/5] qemu-iotests: Add 080 for IO throttling Fam Zheng
@ 2014-06-02 13:41 ` Stefan Hajnoczi
  5 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-06-02 13:41 UTC (permalink / raw)
  To: Fam Zheng
  Cc: Kevin Wolf, Benoît Canet, qemu-devel, Stefan Hajnoczi, pbonzini

On Tue, Feb 11, 2014 at 02:40:57PM +0800, Fam Zheng wrote:
> This series adds iotest case for IO throttling.
> 
> There is a change in qemu-io sub-commands "aio_read" and "aio_write", which
> makes the aio requests accounted and the statistics reflected in blockstats.
> 
> Note that IO throttling implementation allows overcommiting of requests, so the
> actual IO happened in a time unit may be a bit larger than given limits. In the
> test case, the stats numbers are compared against 110%, to make room for such
> flexibility in order to improve determinism.
> 
> v3: Address comments from Benoît. (Thanks for the review!)
> 
>     [02/05] qtest: Add scripts/qtest/qtest.py
>             Fix comments.
>             Fix socket close order.
>             Removed unused lines.
> 
>     [03/05] qemu-iotests: Add VM method qtest() to iotests.py
>             Remove duplicated VM.qtest definition.
> 
>     [05/05] qemu-iotests: Add 080 for IO throttling
>             Check for lower bound (0.9 * limit * seconds).
>             Remove unused lines.
>             Fix checking of total bps and iops by adding up read and write.
> 
> 
> 
> Fam Zheng (5):
>   qemu-io: Account IO by aio_read and aio_write
>   qtest: Add scripts/qtest/qtest.py
>   qemu-iotests: Add VM method qtest() to iotests.py
>   qemu-iotests: Allow caller to disable underscore convertion for qmp
>   qemu-iotests: Add 080 for IO throttling
> 
>  qemu-io-cmds.c                |  10 +++
>  scripts/qtest                 |   5 --
>  scripts/qtest/qtest.py        |  74 ++++++++++++++++++
>  tests/qemu-iotests/080        | 175 ++++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/080.out    |   5 ++
>  tests/qemu-iotests/group      |   1 +
>  tests/qemu-iotests/iotests.py |  24 +++++-
>  7 files changed, 285 insertions(+), 9 deletions(-)
>  delete mode 100755 scripts/qtest
>  create mode 100644 scripts/qtest/qtest.py
>  create mode 100755 tests/qemu-iotests/080
>  create mode 100644 tests/qemu-iotests/080.out

Is this series still alive?

Just going through old patch series.

Stefan

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-06-02 13:42 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-11  6:40 [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case for IO throttling Fam Zheng
2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 1/5] qemu-io: Account IO by aio_read and aio_write Fam Zheng
2014-02-11  6:40 ` [Qemu-devel] [PATCH v3 2/5] qtest: Add scripts/qtest/qtest.py Fam Zheng
2014-02-11 10:41   ` Benoît Canet
2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 3/5] qemu-iotests: Add VM method qtest() to iotests.py Fam Zheng
2014-02-11 10:58   ` Benoît Canet
2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 4/5] qemu-iotests: Allow caller to disable underscore convertion for qmp Fam Zheng
2014-02-11  6:41 ` [Qemu-devel] [PATCH v3 5/5] qemu-iotests: Add 080 for IO throttling Fam Zheng
2014-02-11 10:41   ` Benoît Canet
2014-06-02 13:41 ` [Qemu-devel] [PATCH v3 0/5] qemu-iotests: Test case " Stefan Hajnoczi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.