Re: [Autotest] [KVM-AUTOTEST PATCH] [RFC] KVM test: kvm_monitor.py: refactor _get_command_output()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/18/2010 08:45 PM, Luiz Capitulino wrote:
> On Mon, 18 Oct 2010 15:13:39 +0200
> Michael Goldish <mgoldish@xxxxxxxxxx> 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.

I've considered it, but I don't quite remember why I didn't use it in
the first place.  Let me re-read the code more thoroughly and get back
to you.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux