All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@siemens.com>
To: Ulrich Obergfell <uobergfe@redhat.com>
Cc: "qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
	"kvm@vger.kernel.org" <kvm@vger.kernel.org>,
	"gcosta@redhat.com" <gcosta@redhat.com>,
	"avi@redhat.com" <avi@redhat.com>,
	"aliguori@us.ibm.com" <aliguori@us.ibm.com>
Subject: Re: [PATCH v2 5/5] hpet 'driftfix': add code in hpet_timer() to compensate delayed callbacks and coalesced interrupts
Date: Fri, 08 Apr 2011 17:54:52 +0200	[thread overview]
Message-ID: <4D9F2FCC.2070708@siemens.com> (raw)
In-Reply-To: <1302276042-3497-6-git-send-email-uobergfe@redhat.com>

On 2011-04-08 17:20, Ulrich Obergfell wrote:
> Loss of periodic timer interrupts caused by delayed callbacks and by
> interrupt coalescing is compensated by gradually injecting additional
> interrupts during subsequent timer intervals, starting at a rate of
> one additional interrupt per interval. If further interrupts are lost
> while compensation is in progress, the rate is increased. A limit is
> imposed on the rate and on the 'backlog' of lost interrupts that are
> to be injected. If a guest o/s modifies the comparator register value
> while compensation is in progress, the 'backlog' of lost interrupts
> that are to be injected is scaled to the new value.
> 
> Injecting additional timer interrupts to compensate lost interrupts
> can alleviate long term time drift. However, on a short time scale,
> this method can have the side effect of making virtual machine time
> intermittently pass faster than real time (depending on the guest's
> time keeping algorithm). Compensation is disabled by default and can
> be enabled for guests where this behaviour is acceptable.
> 
> Signed-off-by: Ulrich Obergfell <uobergfe@redhat.com>
> ---
>  hw/hpet.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 57 insertions(+), 1 deletions(-)
> 
> diff --git a/hw/hpet.c b/hw/hpet.c
> index b5625fb..5a25a96 100644
> --- a/hw/hpet.c
> +++ b/hw/hpet.c
> @@ -42,6 +42,9 @@
>  
>  #define HPET_MSI_SUPPORT        0
>  
> +#define MAX_IRQS_TO_INJECT (uint32_t)5000
> +#define MAX_IRQ_RATE       (uint32_t)10
> +
>  struct HPETState;
>  typedef struct HPETTimer {  /* timers */
>      uint8_t tn;             /*timer number*/
> @@ -309,8 +312,11 @@ static const VMStateDescription vmstate_hpet = {
>  static void hpet_timer(void *opaque)
>  {
>      HPETTimer *t = opaque;
> +    HPETState *s = t->state;
>      uint64_t diff;
>  
> +    int irq_delivered = 0;
> +    uint32_t irq_count = 0;
>      uint64_t period = t->period;
>      uint64_t cur_tick = hpet_get_ticks(t->state);
>  
> @@ -318,13 +324,36 @@ static void hpet_timer(void *opaque)
>          if (t->config & HPET_TN_32BIT) {
>              while (hpet_time_after(cur_tick, t->cmp)) {
>                  t->cmp = (uint32_t)(t->cmp + t->period);
> +                irq_count++;
>              }
>          } else {
>              while (hpet_time_after64(cur_tick, t->cmp)) {
>                  t->cmp += period;
> +                irq_count++;
>              }
>          }
>          diff = hpet_calculate_diff(t, cur_tick);
> +        if (s->driftfix) {
> +            if (t->saved_period != t->period) {
> +                uint64_t tmp = (t->irqs_to_inject * t->saved_period)
> +                                                  + t->ticks_not_accounted;
> +                t->irqs_to_inject = tmp / t->period;
> +                t->ticks_not_accounted = tmp % t->period;
> +                t->saved_period = t->period;
> +            }
> +            t->irqs_to_inject += irq_count;
> +            t->irqs_to_inject = MIN(t->irqs_to_inject, MAX_IRQS_TO_INJECT);
> +            if (t->irqs_to_inject > 1) {
> +                if (irq_count > 1) {
> +                    t->irq_rate++;
> +                    t->irq_rate = MIN(t->irq_rate, MAX_IRQ_RATE);
> +                }
> +                if (irq_count || t->divisor == 0) {
> +                    t->divisor = t->irq_rate;
> +                }
> +                diff /= t->divisor--;
> +            }
> +        }

Did I miss some change in the plan? I thought we were heading for a
generic, reusable driftfix tool box (or periodic timer service)? Or is
this intentionally an intermediate step?

>          qemu_mod_timer(t->qemu_timer,
>                         qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
>      } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
> @@ -335,7 +364,22 @@ static void hpet_timer(void *opaque)
>              t->wrap_flag = 0;
>          }
>      }
> -    update_irq(t, 1);
> +    if (s->driftfix && timer_is_periodic(t) && period != 0) {
> +        if (t->irqs_to_inject) {
> +            irq_delivered = update_irq(t, 1);
> +            if (irq_delivered) {
> +                t->irq_rate = MIN(t->irq_rate, t->irqs_to_inject);
> +                t->irqs_to_inject--;
> +            } else {
> +                if (irq_count) {
> +                    t->irq_rate++;
> +                    t->irq_rate = MIN(t->irq_rate, MAX_IRQ_RATE);
> +                }
> +            }
> +        }
> +    } else {
> +        update_irq(t, 1);
> +    }
>  }
>  
>  static void hpet_set_timer(HPETTimer *t)
> @@ -674,6 +718,12 @@ static void hpet_reset(DeviceState *d)
>          timer->config |=  0x00000004ULL << 32;
>          timer->period = 0ULL;
>          timer->wrap_flag = 0;
> +
> +        timer->saved_period = 0;
> +        timer->ticks_not_accounted = 0;
> +        timer->irqs_to_inject = 0;
> +        timer->irq_rate = 1;
> +        timer->divisor = 1;
>      }
>  
>      s->hpet_counter = 0ULL;
> @@ -734,6 +784,12 @@ static int hpet_init(SysBusDevice *dev)
>          timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer);
>          timer->tn = i;
>          timer->state = s;
> +
> +        timer->saved_period = 0;
> +        timer->ticks_not_accounted = 0;
> +        timer->irqs_to_inject = 0;
> +        timer->irq_rate = 1;
> +        timer->divisor = 1;

We call reset after initializing devices, at least for cold-plugged ones.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

WARNING: multiple messages have this Message-ID (diff)
From: Jan Kiszka <jan.kiszka@siemens.com>
To: Ulrich Obergfell <uobergfe@redhat.com>
Cc: "avi@redhat.com" <avi@redhat.com>,
	"aliguori@us.ibm.com" <aliguori@us.ibm.com>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
	"kvm@vger.kernel.org" <kvm@vger.kernel.org>,
	"gcosta@redhat.com" <gcosta@redhat.com>
Subject: [Qemu-devel] Re: [PATCH v2 5/5] hpet 'driftfix': add code in hpet_timer() to compensate delayed callbacks and coalesced interrupts
Date: Fri, 08 Apr 2011 17:54:52 +0200	[thread overview]
Message-ID: <4D9F2FCC.2070708@siemens.com> (raw)
In-Reply-To: <1302276042-3497-6-git-send-email-uobergfe@redhat.com>

On 2011-04-08 17:20, Ulrich Obergfell wrote:
> Loss of periodic timer interrupts caused by delayed callbacks and by
> interrupt coalescing is compensated by gradually injecting additional
> interrupts during subsequent timer intervals, starting at a rate of
> one additional interrupt per interval. If further interrupts are lost
> while compensation is in progress, the rate is increased. A limit is
> imposed on the rate and on the 'backlog' of lost interrupts that are
> to be injected. If a guest o/s modifies the comparator register value
> while compensation is in progress, the 'backlog' of lost interrupts
> that are to be injected is scaled to the new value.
> 
> Injecting additional timer interrupts to compensate lost interrupts
> can alleviate long term time drift. However, on a short time scale,
> this method can have the side effect of making virtual machine time
> intermittently pass faster than real time (depending on the guest's
> time keeping algorithm). Compensation is disabled by default and can
> be enabled for guests where this behaviour is acceptable.
> 
> Signed-off-by: Ulrich Obergfell <uobergfe@redhat.com>
> ---
>  hw/hpet.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 57 insertions(+), 1 deletions(-)
> 
> diff --git a/hw/hpet.c b/hw/hpet.c
> index b5625fb..5a25a96 100644
> --- a/hw/hpet.c
> +++ b/hw/hpet.c
> @@ -42,6 +42,9 @@
>  
>  #define HPET_MSI_SUPPORT        0
>  
> +#define MAX_IRQS_TO_INJECT (uint32_t)5000
> +#define MAX_IRQ_RATE       (uint32_t)10
> +
>  struct HPETState;
>  typedef struct HPETTimer {  /* timers */
>      uint8_t tn;             /*timer number*/
> @@ -309,8 +312,11 @@ static const VMStateDescription vmstate_hpet = {
>  static void hpet_timer(void *opaque)
>  {
>      HPETTimer *t = opaque;
> +    HPETState *s = t->state;
>      uint64_t diff;
>  
> +    int irq_delivered = 0;
> +    uint32_t irq_count = 0;
>      uint64_t period = t->period;
>      uint64_t cur_tick = hpet_get_ticks(t->state);
>  
> @@ -318,13 +324,36 @@ static void hpet_timer(void *opaque)
>          if (t->config & HPET_TN_32BIT) {
>              while (hpet_time_after(cur_tick, t->cmp)) {
>                  t->cmp = (uint32_t)(t->cmp + t->period);
> +                irq_count++;
>              }
>          } else {
>              while (hpet_time_after64(cur_tick, t->cmp)) {
>                  t->cmp += period;
> +                irq_count++;
>              }
>          }
>          diff = hpet_calculate_diff(t, cur_tick);
> +        if (s->driftfix) {
> +            if (t->saved_period != t->period) {
> +                uint64_t tmp = (t->irqs_to_inject * t->saved_period)
> +                                                  + t->ticks_not_accounted;
> +                t->irqs_to_inject = tmp / t->period;
> +                t->ticks_not_accounted = tmp % t->period;
> +                t->saved_period = t->period;
> +            }
> +            t->irqs_to_inject += irq_count;
> +            t->irqs_to_inject = MIN(t->irqs_to_inject, MAX_IRQS_TO_INJECT);
> +            if (t->irqs_to_inject > 1) {
> +                if (irq_count > 1) {
> +                    t->irq_rate++;
> +                    t->irq_rate = MIN(t->irq_rate, MAX_IRQ_RATE);
> +                }
> +                if (irq_count || t->divisor == 0) {
> +                    t->divisor = t->irq_rate;
> +                }
> +                diff /= t->divisor--;
> +            }
> +        }

Did I miss some change in the plan? I thought we were heading for a
generic, reusable driftfix tool box (or periodic timer service)? Or is
this intentionally an intermediate step?

>          qemu_mod_timer(t->qemu_timer,
>                         qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
>      } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
> @@ -335,7 +364,22 @@ static void hpet_timer(void *opaque)
>              t->wrap_flag = 0;
>          }
>      }
> -    update_irq(t, 1);
> +    if (s->driftfix && timer_is_periodic(t) && period != 0) {
> +        if (t->irqs_to_inject) {
> +            irq_delivered = update_irq(t, 1);
> +            if (irq_delivered) {
> +                t->irq_rate = MIN(t->irq_rate, t->irqs_to_inject);
> +                t->irqs_to_inject--;
> +            } else {
> +                if (irq_count) {
> +                    t->irq_rate++;
> +                    t->irq_rate = MIN(t->irq_rate, MAX_IRQ_RATE);
> +                }
> +            }
> +        }
> +    } else {
> +        update_irq(t, 1);
> +    }
>  }
>  
>  static void hpet_set_timer(HPETTimer *t)
> @@ -674,6 +718,12 @@ static void hpet_reset(DeviceState *d)
>          timer->config |=  0x00000004ULL << 32;
>          timer->period = 0ULL;
>          timer->wrap_flag = 0;
> +
> +        timer->saved_period = 0;
> +        timer->ticks_not_accounted = 0;
> +        timer->irqs_to_inject = 0;
> +        timer->irq_rate = 1;
> +        timer->divisor = 1;
>      }
>  
>      s->hpet_counter = 0ULL;
> @@ -734,6 +784,12 @@ static int hpet_init(SysBusDevice *dev)
>          timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer);
>          timer->tn = i;
>          timer->state = s;
> +
> +        timer->saved_period = 0;
> +        timer->ticks_not_accounted = 0;
> +        timer->irqs_to_inject = 0;
> +        timer->irq_rate = 1;
> +        timer->divisor = 1;

We call reset after initializing devices, at least for cold-plugged ones.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

  reply	other threads:[~2011-04-08 15:55 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-08 15:20 [PATCH v2 0/5] hpet 'driftfix': alleviate time drift with HPET periodic timers Ulrich Obergfell
2011-04-08 15:20 ` [Qemu-devel] " Ulrich Obergfell
2011-04-08 15:20 ` [PATCH v2 1/5] hpet 'driftfix': add hooks required to detect coalesced interrupts (x86 apic only) Ulrich Obergfell
2011-04-08 15:20   ` [Qemu-devel] " Ulrich Obergfell
2011-04-08 15:46   ` Anthony Liguori
2011-04-08 15:46     ` Anthony Liguori
2011-04-08 15:51   ` Jan Kiszka
2011-04-08 15:51     ` [Qemu-devel] " Jan Kiszka
2011-04-08 15:20 ` [PATCH v2 2/5] hpet 'driftfix': add driftfix property to HPETState and DeviceInfo Ulrich Obergfell
2011-04-08 15:20   ` [Qemu-devel] " Ulrich Obergfell
2011-04-08 15:20 ` [PATCH v2 3/5] hpet 'driftfix': add fields to HPETTimer and VMStateDescription Ulrich Obergfell
2011-04-08 15:20   ` [Qemu-devel] " Ulrich Obergfell
2011-04-08 15:47   ` Anthony Liguori
2011-04-08 15:47     ` Anthony Liguori
2011-04-11  8:24     ` Ulrich Obergfell
2011-04-11  8:24       ` Ulrich Obergfell
2011-04-11  9:06       ` Ulrich Obergfell
2011-04-11  9:06         ` Ulrich Obergfell
2011-04-11  9:08         ` Avi Kivity
2011-04-11  9:08           ` Avi Kivity
2011-04-11 13:10           ` Anthony Liguori
2011-04-11 13:10             ` Anthony Liguori
2011-04-11 13:39             ` Glauber Costa
2011-04-11 13:39               ` Glauber Costa
2011-04-11 13:43               ` Avi Kivity
2011-04-11 13:43                 ` Avi Kivity
2011-04-11 13:47               ` Anthony Liguori
2011-04-11 13:47                 ` Anthony Liguori
2011-04-11 13:57                 ` Glauber Costa
2011-04-11 13:57                   ` Glauber Costa
2011-04-11 13:10       ` Anthony Liguori
2011-04-11 13:10         ` Anthony Liguori
2011-04-08 15:20 ` [PATCH v2 4/5] hpet 'driftfix': add code in update_irq() to detect coalesced interrupts (x86 apic only) Ulrich Obergfell
2011-04-08 15:20   ` [Qemu-devel] " Ulrich Obergfell
2011-04-08 15:20 ` [PATCH v2 5/5] hpet 'driftfix': add code in hpet_timer() to compensate delayed callbacks and coalesced interrupts Ulrich Obergfell
2011-04-08 15:20   ` [Qemu-devel] " Ulrich Obergfell
2011-04-08 15:54   ` Jan Kiszka [this message]
2011-04-08 15:54     ` [Qemu-devel] " Jan Kiszka
2011-04-08 16:08     ` Glauber Costa
2011-04-08 16:08       ` [Qemu-devel] " Glauber Costa
2011-04-08 16:12       ` Jan Kiszka
2011-04-08 16:12         ` [Qemu-devel] " Jan Kiszka

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=4D9F2FCC.2070708@siemens.com \
    --to=jan.kiszka@siemens.com \
    --cc=aliguori@us.ibm.com \
    --cc=avi@redhat.com \
    --cc=gcosta@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=qemu-devel@nongnu.org \
    --cc=uobergfe@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 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.