Patchwork Limit ptimer rate to something achievable

login
register
mail settings
Submitter Peter Chubb
Date April 20, 2012, 5:32 a.m.
Message ID <w48vhr2ck1.wl%peter@chubb.wattle.id.au>
Download mbox | patch
Permalink /patch/153936/
State New
Headers show

Comments

Peter Chubb - April 20, 2012, 5:32 a.m.
If a guest sets very short timeouts, and asks for a timer to be reloaded on 
timeout, QEMU can go to 100%CPU utilisation and become unresponsive,
as it is spending all its time generating timeout interrupts.  On real
hardware this doesn't matter, as the interrupts are just coalesced,
and the effect is to have the interrupt asserted all the time.

This patch is a band-aid, that prevents timeouts less than 10
microseconds from being set.  10 microseconds is a limit that was
determined empirically on a variety of machines as the shortest that
allowed QEMU to pick up a control-a c sequence to get at the monitor.

Reported-by: Anna Lyons <anna.lyons@nicta.com.au>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>

---
 hw/ptimer.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)

--
Dr Peter Chubb				        peter.chubb AT nicta.com.au
http://www.ssrg.nicta.com.au          Software Systems Research Group/NICTA
Anthony Liguori - April 24, 2012, 6:24 p.m.
On 04/20/2012 12:32 AM, Peter Chubb wrote:
>
> If a guest sets very short timeouts, and asks for a timer to be reloaded on
> timeout, QEMU can go to 100%CPU utilisation and become unresponsive,
> as it is spending all its time generating timeout interrupts.  On real
> hardware this doesn't matter, as the interrupts are just coalesced,
> and the effect is to have the interrupt asserted all the time.
>
> This patch is a band-aid, that prevents timeouts less than 10
> microseconds from being set.  10 microseconds is a limit that was
> determined empirically on a variety of machines as the shortest that
> allowed QEMU to pick up a control-a c sequence to get at the monitor.
>
> Reported-by: Anna Lyons<anna.lyons@nicta.com.au>
> Signed-off-by: Peter Chubb<peter.chubb@nicta.com.au>

Applied.  Thanks.

Regards,

Anthony Liguori

>
> ---
>   hw/ptimer.c |   13 +++++++++++++
>   1 file changed, 13 insertions(+)
>
> Index: qemu-working/hw/ptimer.c
> ===================================================================
> --- qemu-working.orig/hw/ptimer.c	2012-04-20 15:09:09.317922659 +1000
> +++ qemu-working/hw/ptimer.c	2012-04-20 15:30:42.108486207 +1000
> @@ -180,6 +180,19 @@ void ptimer_set_freq(ptimer_state *s, ui
>      count = limit.  */
>   void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
>   {
> +    /*
> +     * Artificially limit timeout rate to something
> +     * achievable under QEMU.  Otherwise, QEMU spends all
> +     * its time generating timer interrupts, and there
> +     * is no forward progress.
> +     * About ten microseconds is the fastest that really works
> +     * on the current generation of host machines.
> +     */
> +
> +    if (limit * s->period<  10000&&  s->period) {
> +        limit = 10000 / s->period;
> +    }
> +
>       s->limit = limit;
>       if (reload)
>           s->delta = limit;
> --
> Dr Peter Chubb				        peter.chubb AT nicta.com.au
> http://www.ssrg.nicta.com.au          Software Systems Research Group/NICTA
>
>

Patch

Index: qemu-working/hw/ptimer.c
===================================================================
--- qemu-working.orig/hw/ptimer.c	2012-04-20 15:09:09.317922659 +1000
+++ qemu-working/hw/ptimer.c	2012-04-20 15:30:42.108486207 +1000
@@ -180,6 +180,19 @@  void ptimer_set_freq(ptimer_state *s, ui
    count = limit.  */
 void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
 {
+    /*
+     * Artificially limit timeout rate to something
+     * achievable under QEMU.  Otherwise, QEMU spends all
+     * its time generating timer interrupts, and there
+     * is no forward progress.
+     * About ten microseconds is the fastest that really works
+     * on the current generation of host machines.
+     */
+
+    if (limit * s->period < 10000 && s->period) {
+        limit = 10000 / s->period;
+    }
+
     s->limit = limit;
     if (reload)
         s->delta = limit;