diff mbox

hid: Extend the event queue size to 1024

Message ID 1460643912-244245-1-git-send-email-agraf@suse.de
State New
Headers show

Commit Message

Alexander Graf April 14, 2016, 2:25 p.m. UTC
We can currently buffer up to 16 events in our event queue for input
devices. While it sounds like 16 events backlog for everyone should
be enough, our automated testing tools (OpenQA) manage to easily
type faster than our guests can handle.

So we run into queue overflows and start to drop input characters.
By typing quickly, I was even able to reproduce this manually in
a vnc session on SLOF.

Fix this by increasing the queue buffer. With 1k events I'm sure we
can get by for the foreseeable future. To maintain backwards compatibility
on live migration, put the extra queue items into separate subsections.

Reported-by: Dinar Valeev <dvaleev@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/input/hid.c         | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
 include/hw/input/hid.h |  4 ++--
 2 files changed, 48 insertions(+), 6 deletions(-)

Comments

Gerd Hoffmann April 14, 2016, 3:17 p.m. UTC | #1
On Do, 2016-04-14 at 16:25 +0200, Alexander Graf wrote:
> We can currently buffer up to 16 events in our event queue for input
> devices. While it sounds like 16 events backlog for everyone should
> be enough, our automated testing tools (OpenQA) manage to easily
> type faster than our guests can handle.

IMO you should fix OpenQA to type slower then.

Real hardware is made for human typing speeds.  qemu emulates real
hardware.  Typing insane fast is going to cause problems because the
hardware interfaces are not designed for that.

Note the ps/2 keyboard has only a 16 byte queue too.  Used to be 256
bytes, but that caused problems because this diverges from real hardware
(see commit 2858ab09e6f708e381fc1a1cc87e747a690c4884 for all the
details).

Note that the generic input code has support for slow typing already
(see qemu_input_event_send_key_delay in ui/input.c).  That queue will
(a) work for all keyboard devices and (b) isn't visible to the guest, so
using that might be a reasonable option if you can't put the delay logic
into OpenQA.  How to you feed the guest with keystrokes?  monitor?  vnc?

cheers,
  Gerd
Alexander Graf April 14, 2016, 3:29 p.m. UTC | #2
On 04/14/2016 05:17 PM, Gerd Hoffmann wrote:
> On Do, 2016-04-14 at 16:25 +0200, Alexander Graf wrote:
>> We can currently buffer up to 16 events in our event queue for input
>> devices. While it sounds like 16 events backlog for everyone should
>> be enough, our automated testing tools (OpenQA) manage to easily
>> type faster than our guests can handle.
> IMO you should fix OpenQA to type slower then.
>
> Real hardware is made for human typing speeds.  qemu emulates real
> hardware.  Typing insane fast is going to cause problems because the
> hardware interfaces are not designed for that.
>
> Note the ps/2 keyboard has only a 16 byte queue too.  Used to be 256
> bytes, but that caused problems because this diverges from real hardware
> (see commit 2858ab09e6f708e381fc1a1cc87e747a690c4884 for all the
> details).
>
> Note that the generic input code has support for slow typing already
> (see qemu_input_event_send_key_delay in ui/input.c).  That queue will
> (a) work for all keyboard devices and (b) isn't visible to the guest, so
> using that might be a reasonable option if you can't put the delay logic
> into OpenQA.  How to you feed the guest with keystrokes?  monitor?  vnc?

It used to type via the monitor, but these days everything goes via vnc.

Vnc already uses qemu_input_event_send_key_delay today, so I'm not sure 
where things fall apart.


Alex
Gerd Hoffmann April 14, 2016, 4:19 p.m. UTC | #3
On Do, 2016-04-14 at 17:29 +0200, Alexander Graf wrote:
> On 04/14/2016 05:17 PM, Gerd Hoffmann wrote:
> > On Do, 2016-04-14 at 16:25 +0200, Alexander Graf wrote:
> >> We can currently buffer up to 16 events in our event queue for input
> >> devices. While it sounds like 16 events backlog for everyone should
> >> be enough, our automated testing tools (OpenQA) manage to easily
> >> type faster than our guests can handle.
> > IMO you should fix OpenQA to type slower then.
> >
> > Real hardware is made for human typing speeds.  qemu emulates real
> > hardware.  Typing insane fast is going to cause problems because the
> > hardware interfaces are not designed for that.
> >
> > Note the ps/2 keyboard has only a 16 byte queue too.  Used to be 256
> > bytes, but that caused problems because this diverges from real hardware
> > (see commit 2858ab09e6f708e381fc1a1cc87e747a690c4884 for all the
> > details).
> >
> > Note that the generic input code has support for slow typing already
> > (see qemu_input_event_send_key_delay in ui/input.c).  That queue will
> > (a) work for all keyboard devices and (b) isn't visible to the guest, so
> > using that might be a reasonable option if you can't put the delay logic
> > into OpenQA.  How to you feed the guest with keystrokes?  monitor?  vnc?
> 
> It used to type via the monitor, but these days everything goes via vnc.
> 
> Vnc already uses qemu_input_event_send_key_delay today, so I'm not sure 
> where things fall apart.

Try a larger delay for starters.

Possibly OpenQA starts typing before the guest detected the device, in
that case the delay wouldn't avoid the queue filling up because the
guest doesn't read it (yet).

cheers,
  Gerd
dvaleev@suse.de April 15, 2016, 12:18 p.m. UTC | #4
On 04/14/2016 06:19 PM, Gerd Hoffmann wrote:
> On Do, 2016-04-14 at 17:29 +0200, Alexander Graf wrote:
>> On 04/14/2016 05:17 PM, Gerd Hoffmann wrote:
>>> On Do, 2016-04-14 at 16:25 +0200, Alexander Graf wrote:
>>>> We can currently buffer up to 16 events in our event queue for input
>>>> devices. While it sounds like 16 events backlog for everyone should
>>>> be enough, our automated testing tools (OpenQA) manage to easily
>>>> type faster than our guests can handle.
>>> IMO you should fix OpenQA to type slower then.
>>>
>>> Real hardware is made for human typing speeds.  qemu emulates real
>>> hardware.  Typing insane fast is going to cause problems because the
>>> hardware interfaces are not designed for that.
>>>
>>> Note the ps/2 keyboard has only a 16 byte queue too.  Used to be 256
>>> bytes, but that caused problems because this diverges from real hardware
>>> (see commit 2858ab09e6f708e381fc1a1cc87e747a690c4884 for all the
>>> details).
>>>
>>> Note that the generic input code has support for slow typing already
>>> (see qemu_input_event_send_key_delay in ui/input.c).  That queue will
>>> (a) work for all keyboard devices and (b) isn't visible to the guest, so
>>> using that might be a reasonable option if you can't put the delay logic
>>> into OpenQA.  How to you feed the guest with keystrokes?  monitor?  vnc?
>>
>> It used to type via the monitor, but these days everything goes via vnc.
>>
>> Vnc already uses qemu_input_event_send_key_delay today, so I'm not sure 
>> where things fall apart.
> 
> Try a larger delay for starters.
> 
> Possibly OpenQA starts typing before the guest detected the device, in
> that case the delay wouldn't avoid the queue filling up because the
> guest doesn't read it (yet).
This happens randomly.

Yes we use vnc to type into the screen. If we start 10 guests in parallel,
one or two might have keyboard issues.

like we send "zypper lr" the guest receives "zyppe lr"

or "ps -ef | grep bin/X ; echo __wHP > /dev/hvc0" results into "ps -ef | GREP BIN?X ; echo __wHP > /dev/hvc0"

openQA types with the same speed on all architectures. however we see problems only on aarch64 and POWER due to USB keyboard usage.
> 
> cheers,
>   Gerd
>
Juan Quintela April 19, 2016, 9:28 a.m. UTC | #5
Alexander Graf <agraf@suse.de> wrote:
> We can currently buffer up to 16 events in our event queue for input
> devices. While it sounds like 16 events backlog for everyone should
> be enough, our automated testing tools (OpenQA) manage to easily
> type faster than our guests can handle.
>
> So we run into queue overflows and start to drop input characters.
> By typing quickly, I was even able to reproduce this manually in
> a vnc session on SLOF.
>
> Fix this by increasing the queue buffer. With 1k events I'm sure we
> can get by for the foreseeable future. To maintain backwards compatibility
> on live migration, put the extra queue items into separate subsections.
>
> Reported-by: Dinar Valeev <dvaleev@suse.de>
> Signed-off-by: Alexander Graf <agraf@suse.de>

Hi

I see that it appears you have agreed in a different solution.

Just to say that this patch is ok from the migration point of view O:-)

Later, Juan.

PD. No, REAL HARDWARE don't have migration either O:-)
diff mbox

Patch

diff --git a/hw/input/hid.c b/hw/input/hid.c
index d92c746..56119a3 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -569,6 +569,16 @@  static int hid_post_load(void *opaque, int version_id)
     return 0;
 }
 
+static bool hid_extra_queue_needed(void *opaque)
+{
+        /*
+         * The queue is a ring, so chances are really good that we need to
+         * submit entries beyond entry 16 anyway. Let's just always send
+         * them, that way we have less chance of missing events by accident.
+         */
+	return true;
+}
+
 static const VMStateDescription vmstate_hid_ptr_queue = {
     .name = "HIDPointerEventQueue",
     .version_id = 1,
@@ -582,19 +592,47 @@  static const VMStateDescription vmstate_hid_ptr_queue = {
     }
 };
 
+static const VMStateDescription vmstate_hid_ptr_extra_queue = {
+    .name = "hid_ptr_extra_queue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = hid_extra_queue_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_SUB_ARRAY(ptr.queue, HIDState, 16, QUEUE_LENGTH - 16, 0,
+                                 vmstate_hid_ptr_queue, HIDPointerEvent),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_hid_ptr_device = {
     .name = "HIDPointerDevice",
     .version_id = 1,
     .minimum_version_id = 1,
     .post_load = hid_post_load,
     .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
-                             vmstate_hid_ptr_queue, HIDPointerEvent),
+        VMSTATE_STRUCT_SUB_ARRAY(ptr.queue, HIDState, 0, 16, 0,
+                                 vmstate_hid_ptr_queue, HIDPointerEvent),
         VMSTATE_UINT32(head, HIDState),
         VMSTATE_UINT32(n, HIDState),
         VMSTATE_INT32(protocol, HIDState),
         VMSTATE_UINT8(idle, HIDState),
         VMSTATE_END_OF_LIST(),
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_hid_ptr_extra_queue,
+        NULL
+    }
+};
+
+static const VMStateDescription vmstate_hid_keyboard_extra_keys = {
+    .name = "hid_kbd_extra_keys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = hid_extra_queue_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_SUB_ARRAY(kbd.keycodes, HIDState, 16, QUEUE_LENGTH - 16),
+        VMSTATE_UINT8_SUB_ARRAY(kbd.key, HIDState, 16, QUEUE_LENGTH - 16),
+        VMSTATE_END_OF_LIST()
     }
 };
 
@@ -604,15 +642,19 @@  const VMStateDescription vmstate_hid_keyboard_device = {
     .minimum_version_id = 1,
     .post_load = hid_post_load,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32_SUB_ARRAY(kbd.keycodes, HIDState, 0, 16),
         VMSTATE_UINT32(head, HIDState),
         VMSTATE_UINT32(n, HIDState),
         VMSTATE_UINT16(kbd.modifiers, HIDState),
         VMSTATE_UINT8(kbd.leds, HIDState),
-        VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
+        VMSTATE_UINT8_SUB_ARRAY(kbd.key, HIDState, 0, 16),
         VMSTATE_INT32(kbd.keys, HIDState),
         VMSTATE_INT32(protocol, HIDState),
         VMSTATE_UINT8(idle, HIDState),
         VMSTATE_END_OF_LIST(),
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_hid_keyboard_extra_keys,
+        NULL
     }
 };
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
index 2127c7c..bc561d4 100644
--- a/include/hw/input/hid.h
+++ b/include/hw/input/hid.h
@@ -13,7 +13,7 @@  typedef struct HIDPointerEvent {
     int32_t dz, buttons_state;
 } HIDPointerEvent;
 
-#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
+#define QUEUE_LENGTH    1024
 #define QUEUE_MASK      (QUEUE_LENGTH-1u)
 #define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
 
@@ -29,7 +29,7 @@  typedef struct HIDKeyboardState {
     uint32_t keycodes[QUEUE_LENGTH];
     uint16_t modifiers;
     uint8_t leds;
-    uint8_t key[16];
+    uint8_t key[QUEUE_LENGTH];
     int32_t keys;
 } HIDKeyboardState;