From patchwork Fri Apr 8 15:20:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulrich Obergfell X-Patchwork-Id: 90390 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 39357B6F7B for ; Sat, 9 Apr 2011 01:52:50 +1000 (EST) Received: from localhost ([127.0.0.1]:56048 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q8DzK-0001pN-F2 for incoming@patchwork.ozlabs.org; Fri, 08 Apr 2011 11:52:46 -0400 Received: from [140.186.70.92] (port=53566 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q8DvN-0001BM-Bl for qemu-devel@nongnu.org; Fri, 08 Apr 2011 11:48:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q8DUW-0005Yf-2N for qemu-devel@nongnu.org; Fri, 08 Apr 2011 11:20:57 -0400 Received: from mx1.redhat.com ([209.132.183.28]:65021) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q8DUV-0005YZ-Oo for qemu-devel@nongnu.org; Fri, 08 Apr 2011 11:20:56 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p38FKtHq004116 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 8 Apr 2011 11:20:55 -0400 Received: from localhost.localdomain (vpn1-4-212.ams2.redhat.com [10.36.4.212]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p38FKgc5018813; Fri, 8 Apr 2011 11:20:53 -0400 From: Ulrich Obergfell To: qemu-devel@nongnu.org Date: Fri, 8 Apr 2011 17:20:42 +0200 Message-Id: <1302276042-3497-6-git-send-email-uobergfe@redhat.com> In-Reply-To: <1302276042-3497-1-git-send-email-uobergfe@redhat.com> References: <1302276042-3497-1-git-send-email-uobergfe@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: aliguori@us.ibm.com, kvm@vger.kernel.org, jan.kiszka@siemens.com, uobergfe@redhat.com, gcosta@redhat.com, avi@redhat.com Subject: [Qemu-devel] [PATCH v2 5/5] hpet 'driftfix': add code in hpet_timer() to compensate delayed callbacks and coalesced interrupts X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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--; + } + } 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; } /* 64-bit main counter; LegacyReplacementRoute. */