public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Luiz Capitulino <lcapitulino@redhat.com>
To: Michael Goldish <mgoldish@redhat.com>
Cc: autotest@test.kernel.org, kvm@vger.kernel.org
Subject: Re: [Autotest] [KVM-AUTOTEST PATCH] [RFC] KVM test: kvm_monitor.py: refactor _get_command_output()
Date: Mon, 18 Oct 2010 16:45:25 -0200	[thread overview]
Message-ID: <20101018164525.38d2d105@doriath> (raw)
In-Reply-To: <1287407620-30026-3-git-send-email-mgoldish@redhat.com>

On Mon, 18 Oct 2010 15:13:39 +0200
Michael Goldish <mgoldish@redhat.com> wrote:

> Instead of _get_command_output() and friends, introduce the following methods:
> 
> * QMP:
>   - _send(): send raw data without waiting for a response
>   - _get_response(): get the response to a previously sent command
>   - cmd(): send a command with arguments, return response, raise an exception
>            if the command fails
>   - cmd_raw(): send a raw string, return response dict without postprocessing
>   - cmd_obj(): send a Python object (converted to JSON), return response dict
>                without postprocessing
>   - cmd_qmp(): send a command with arguments, return response dict without
>                postprocessing
> 
>   cmd() is useful for common monitor usage.  cmd_raw(), cmd_obj() and
>   cmd_qmp() are required by Luiz Capitulino's test suite.  The difference
>   between cmd() and cmd_qmp() is that the latter does not perform any checks
>   on the response dict.  Note that cmd_raw() is functionally equivalent to
>   send() from Luiz's patch.  I propose that we use the name cmd_raw() because
>   send() implies sending data without caring about the response, whereas
>   cmd_raw() implies doing exactly what cmd_obj() and cmd_qmp() do, but using
>   raw data.

I did a quick review and it looks good to me. I have only one comment
(which should not prevent this from being merged):

> -    def _get_command_output(self, cmd, args=None, timeout=20):
> +        @param id: If not None, look for a response with this id
> +        @param timeout: Time duration to wait for response
> +        @return: The response dict, or None if none was found
>          """
> -        Send monitor command and wait for response.
> +        end_time = time.time() + timeout
> +        while time.time() < end_time:
> +            for obj in self._read_objects():
> +                if isinstance(obj, dict):
> +                    if id is not None and obj.get("id") != id:
> +                        continue
> +                    if "return" in obj or "error" in obj:
> +                        return obj
> +            time.sleep(0.1)

Is there a reason not to use select? Like the following example (which changes
the HumanMonitor class, not the QMPMonitor one):

diff --git a/client/tests/kvm/kvm_monitor.py b/client/tests/kvm/kvm_monitor.py
index 6bff07f..cfe05bf 100644
--- a/client/tests/kvm/kvm_monitor.py
+++ b/client/tests/kvm/kvm_monitor.py
@@ -4,7 +4,7 @@ Interfaces to the QEMU monitor.
 @copyright: 2008-2010 Red Hat Inc.
 """
 
-import socket, time, threading, logging
+import socket, time, threading, logging, select
 import kvm_utils
 try:
     import json
@@ -58,7 +58,6 @@ class Monitor:
         self.filename = filename
         self._lock = threading.RLock()
         self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        self._socket.setblocking(False)
 
         try:
             self._socket.connect(filename)
@@ -105,13 +104,14 @@ class Monitor:
     def _recvall(self):
         s = ""
         while True:
-            try:
+            i, o, e = select.select([self._socket], [], [], 0)
+            if len(i) > 0:
                 data = self._socket.recv(1024)
-            except socket.error:
-                break
-            if not data:
+                if not data:
+                    break
+                s += data
+            else:
                 break
-            s += data
         return s
 
 
@@ -158,19 +158,19 @@ class HumanMonitor(Monitor):
     # Private methods
 
     def _read_up_to_qemu_prompt(self, timeout=20):
-        o = ""
-        end_time = time.time() + timeout
-        while time.time() < end_time:
-            try:
+        buf = ""
+        while True:
+            i, o, e = select.select([self._socket], [], [], timeout)
+            if len(i) > 0:
                 data = self._socket.recv(1024)
-                if not data:
-                    break
-                o += data
-                if o.splitlines()[-1].split()[-1] == "(qemu)":
-                    return True, "\n".join(o.splitlines()[:-1])
-            except (socket.error, IndexError):
-                time.sleep(0.01)
-        return False, "\n".join(o.splitlines())
+                buf += data
+                try:
+                    if buf.splitlines()[-1].split()[-1] == "(qemu)":
+                        return True, "\n".join(buf.splitlines()[:-1])
+                except IndexError:
+                    continue
+            else:
+                return False, "\n".join(buf.splitlines())
 
 
     def _send_command(self, command):


Besides of getting a slightly simpler code, select has the major benefit
of not sleeping when there's data available. This is a problem with the
current implementation: if data is available before or during the sleep()
call, you'll sit there for the specified timeout, no matter what.

I'm not exactly saying we should change right now, maybe those 0.01 seconds
won't matter in practice (and I haven't measured anything), but I'd like
to know if you've considered using select.

  parent reply	other threads:[~2010-10-18 18:45 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-18 13:13 [KVM-AUTOTEST PATCH] KVM test: kvm_subprocess.py: reset _thread_kill_requested in kill_tail_threads() Michael Goldish
2010-10-18 13:13 ` [KVM-AUTOTEST PATCH] KVM test: whql_client_install: fix retrieval of server_dns_suffix Michael Goldish
2010-10-18 13:13   ` [KVM-AUTOTEST PATCH] [RFC] KVM test: kvm_monitor.py: refactor _get_command_output() Michael Goldish
2010-10-18 13:13     ` [KVM-AUTOTEST PATCH] KVM test: kvm_monitor.py: add __str__() method to QMPCmdError exception Michael Goldish
2010-10-18 16:28     ` [Autotest] [KVM-AUTOTEST PATCH] [RFC] KVM test: kvm_monitor.py: refactor _get_command_output() Lucas Meneghel Rodrigues
2010-10-18 18:25       ` Luiz Capitulino
2010-10-18 23:00         ` Lucas Meneghel Rodrigues
2010-10-18 18:45     ` Luiz Capitulino [this message]
2010-10-19  7:03       ` [Autotest] " Michael Goldish

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20101018164525.38d2d105@doriath \
    --to=lcapitulino@redhat.com \
    --cc=autotest@test.kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=mgoldish@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox