WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] Fix hvm guest time to be more accurate

To: xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] Fix hvm guest time to be more accurate
From: Ben Guthro <bguthro@xxxxxxxxxxxxxxx>
Date: Wed, 24 Oct 2007 17:15:38 -0400
Cc: Dave Winchell <dwinchell@xxxxxxxxxxxxxxx>
Delivery-date: Wed, 24 Oct 2007 14:22:54 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.5 (X11/20070719)
The vpt timer code in effect accumulates missed ticks
when a guest is running but has interrupts disabled
or when the platform timer is starved. For guests
like 64 bit Linux which calculates missed ticks on each
clock interrupt based on the current tsc and the tsc
of the last interrupt and then adds missed ticks to jiffies
there is redundant accounting.

This change subtracts off the hypervisor calculated missed
ticks while guest running for 64 bit guests using the pit.
Missed ticks when vcpu 0 is descheduled are unaffected.

Signed-off-by: Ben Guthro <bguthro@xxxxxxxxxxxxxx>
Signed-off-by: Dave Winchell <dwinchell@xxxxxxxxxxxxxxx>
diff -r c42fcc739fc4 tools/firmware/hvmloader/acpi/static_tables.c
--- a/tools/firmware/hvmloader/acpi/static_tables.c     Tue Oct 23 08:16:39 
2007 -0400
+++ b/tools/firmware/hvmloader/acpi/static_tables.c     Tue Oct 23 08:16:39 
2007 -0400
@@ -93,7 +93,7 @@ struct acpi_20_fadt Fadt = {
     },
 
     .x_pm_tmr_blk = {
-        .address_space_id    = ACPI_SYSTEM_IO,
+        .address_space_id    = 0xff,
         .register_bit_width  = ACPI_PM_TMR_BLK_BIT_WIDTH,
         .register_bit_offset = ACPI_PM_TMR_BLK_BIT_OFFSET,
         .address             = ACPI_PM_TMR_BLK_ADDRESS,
diff -r c42fcc739fc4 xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Tue Oct 23 08:16:39 2007 -0400
+++ b/xen/arch/x86/hvm/i8254.c  Tue Oct 23 08:16:39 2007 -0400
@@ -405,6 +405,8 @@ static void pit_info(PITState *pit)
     struct hvm_hw_pit_channel *s;
     struct periodic_time *pt;
     int i;
+    struct periodic_time *pt;
+    unsigned long now;
 
     for ( i = 0; i < 3; i++ )
     {
@@ -447,11 +449,18 @@ static int pit_save(struct domain *d, hv
 {
     PITState *pit = domain_vpit(d);
     int rc;
+    unsigned long now;
+    struct periodic_time *pt;
 
     spin_lock(&pit->lock);
     
     pit_info(pit);
 
+    pt = &pit->pt0;
+    rdtscll(now);
+    pit->hw.pt_delivered = pt->delivered - now;
+    pit->hw.pt_frozen = pt->frozen - now;
+
     /* Save the PIT hardware state */
     rc = hvm_save_entry(PIT, 0, h, &pit->hw);
 
@@ -464,6 +473,8 @@ static int pit_load(struct domain *d, hv
 {
     PITState *pit = domain_vpit(d);
     int i;
+    struct periodic_time *pt;
+    unsigned long now;
 
     spin_lock(&pit->lock);
 
@@ -481,6 +492,11 @@ static int pit_load(struct domain *d, hv
     for ( i = 0; i < 3; i++ )
         pit_load_count(pit, i, pit->hw.channels[i].count);
 
+    pt = &pit->pt0;
+    rdtscll(now);
+    pt->delivered = now + pit->hw.pt_delivered;
+    pt->frozen = now + pit->hw.pt_frozen;
+
     pit_info(pit);
 
     spin_unlock(&pit->lock);
@@ -514,6 +530,18 @@ void pit_init(struct vcpu *v, unsigned l
     }
 
     spin_unlock(&pit->lock);
+}
+
+struct periodic_time *pit_get_timer(struct vcpu *v)
+{
+    PITState *pit = &v->domain->arch.hvm_domain.pl_time.vpit;
+    struct periodic_time *pt;
+
+    pt = &pit->pt0;
+    if ( pt->vcpu == v && pt->enabled )
+       return pt;
+    else
+       return NULL;
 }
 
 void pit_deinit(struct domain *d)
diff -r c42fcc739fc4 xen/arch/x86/hvm/vpt.c
--- a/xen/arch/x86/hvm/vpt.c    Tue Oct 23 08:16:39 2007 -0400
+++ b/xen/arch/x86/hvm/vpt.c    Tue Oct 23 08:18:49 2007 -0400
@@ -54,16 +54,7 @@ static void missed_ticks(struct periodic
         return;
 
     missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
-    if ( missed_ticks > 1000 )
-    {
-        /* TODO: Adjust guest time together */
-        pt->pending_intr_nr++;
-    }
-    else
-    {
-        pt->pending_intr_nr += missed_ticks;
-    }
-
+    pt->pending_intr_nr += missed_ticks;
     pt->scheduled += missed_ticks * pt->period;
 }
 
@@ -71,6 +62,7 @@ void pt_freeze_time(struct vcpu *v)
 {
     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
     struct periodic_time *pt;
+    unsigned long now;
 
     if ( test_bit(_VPF_blocked, &v->pause_flags) )
         return;
@@ -79,8 +71,12 @@ void pt_freeze_time(struct vcpu *v)
 
     v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
 
-    list_for_each_entry ( pt, head, list )
+    rdtscll(now);
+    list_for_each_entry ( pt, head, list )
+    {
         stop_timer(&pt->timer);
+       pt->frozen = now;
+    }
 
     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
 }
@@ -89,6 +85,7 @@ void pt_thaw_time(struct vcpu *v)
 {
     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
     struct periodic_time *pt;
+    unsigned long now, delta;
 
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
@@ -97,10 +94,14 @@ void pt_thaw_time(struct vcpu *v)
         hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
         v->arch.hvm_vcpu.guest_time = 0;
 
+       rdtscll(now);
         list_for_each_entry ( pt, head, list )
         {
             missed_ticks(pt);
             set_timer(&pt->timer, pt->scheduled);
+           delta = now - pt->frozen;
+           if(pt->delivered)
+               pt->delivered += delta;
         }
     }
 
@@ -158,6 +159,57 @@ void pt_update_irq(struct vcpu *v)
         hvm_isa_irq_assert(v->domain, irq);
     }
 }
+#include <asm/paging.h>
+struct periodic_time *pit_get_timer(struct vcpu *v);
+int pt_irq_subtract(struct vcpu *v, struct periodic_time *pt_handled)
+{
+    struct periodic_time *pt;
+    unsigned long delta_us;
+    unsigned long period_us;
+    int new_nr;
+    unsigned long now, delta;
+    unsigned long ticks, offset;
+    int ret = 0;
+
+    /* 64bit Linux guests calculate missed ticks in the clock interrupt handler
+     * and bump jiffies accordingly while 32bit Linux guests do not.
+     * If the (64bit) guest cpu0 has interrupts disabled for longer than two 
clock
+     * periods, and cpu0 is running, then since the tsc continues, the guest 
will
+     * find missed_ticks > 1 at the first clock interrupt. But the pt timer 
has continued
+     * to expire regularly and accumulated the missed interrupts in 
pending_intr_nr.
+     * If we deliver these accumulated interrupts the guest will run fast.
+     * Here we subtract off the missed interrupts for 64 bit guests using pit.
+     */
+
+    if(v->arch.paging.mode->guest_levels != 4)
+       return ret;
+    pt = pit_get_timer(v);
+    if(pt)
+       ret = 1;
+    if(pt == pt_handled) {
+       rdtscll(now);
+       if(!pt->delivered) {
+           pt->delivered = now;
+           return ret;
+       }
+       delta = now - pt->delivered;
+       pt->delivered = now;
+       delta_us = (delta * 1000UL)/(unsigned long)cpu_khz;
+       period_us = pt->period/1000UL; /* ns to usec*/
+       ticks = delta_us/period_us;
+       offset = delta_us % period_us;
+       if(ticks < 2)
+           return ret;
+       ticks -= 1;
+       pt->delivered = now - (offset * (unsigned long)cpu_khz)/1000UL;
+       new_nr = pt->pending_intr_nr - ticks;
+       if(new_nr < 1)
+           ticks = ticks + new_nr - 1;
+       pt->pending_intr_nr -= ticks;
+       pt->last_plt_gtime += ticks * pt->period_cycles;
+    }
+    return ret;
+}
 
 static struct periodic_time *is_pt_irq(
     struct vcpu *v, struct hvm_intack intack)
@@ -197,6 +249,7 @@ void pt_intr_post(struct vcpu *v, struct
     struct periodic_time *pt;
     time_cb *cb;
     void *cb_priv;
+    int pit_only;
 
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
@@ -207,6 +260,7 @@ void pt_intr_post(struct vcpu *v, struct
         return;
     }
 
+    pit_only = pt_irq_subtract(v, pt);
     if ( pt->one_shot )
     {
         pt->enabled = 0;
@@ -218,8 +272,12 @@ void pt_intr_post(struct vcpu *v, struct
         pt->last_plt_gtime += pt->period_cycles;
     }
 
-    if ( hvm_get_guest_time(v) < pt->last_plt_gtime )
-        hvm_set_guest_time(v, pt->last_plt_gtime);
+    if(pit_only) {
+       if((pt == pit_get_timer(v)) && (hvm_get_guest_time(pt->vcpu) < 
pt->last_plt_gtime))
+           hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime);
+    }
+    else if(hvm_get_guest_time(pt->vcpu) < pt->last_plt_gtime)
+       hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime);
 
     cb = pt->cb;
     cb_priv = pt->priv;
diff -r c42fcc739fc4 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Tue Oct 23 08:16:39 2007 -0400
+++ b/xen/include/asm-x86/hvm/vpt.h     Tue Oct 23 08:16:39 2007 -0400
@@ -76,7 +76,7 @@ struct periodic_time {
     char one_shot;              /* one shot time */
     u8 irq;
     struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
-    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
+    unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
     u64 period;                 /* frequency in ns */
     u64 period_cycles;          /* frequency in cpu cycles */
     s_time_t scheduled;         /* scheduled timer interrupt */
@@ -84,6 +84,8 @@ struct periodic_time {
     struct timer timer;         /* ac_timer */
     time_cb *cb;
     void *priv;                 /* point back to platform time source */
+    unsigned long delivered;
+    unsigned long frozen;
 };
 
 
diff -r c42fcc739fc4 xen/include/public/arch-x86/hvm/save.h
--- a/xen/include/public/arch-x86/hvm/save.h    Tue Oct 23 08:16:39 2007 -0400
+++ b/xen/include/public/arch-x86/hvm/save.h    Tue Oct 23 08:34:05 2007 -0400
@@ -156,6 +156,8 @@ struct hvm_hw_cpu {
     };
     /* error code for pending event */
     uint32_t error_code;
+    unsigned long pt_delivered;
+    unsigned long pt_frozen;    
 };
 
 DECLARE_HVM_SAVE_TYPE(CPU, 2, struct hvm_hw_cpu);
@@ -342,6 +344,8 @@ struct hvm_hw_pit {
     } channels[3];  /* 3 x 16 bytes */
     uint32_t speaker_data_on;
     uint32_t pad0;
+    unsigned long pt_delivered;
+    unsigned long pt_frozen;
 };
 
 DECLARE_HVM_SAVE_TYPE(PIT, 10, struct hvm_hw_pit);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel