From: Ben Guthro <bguthro@virtualiron.com>
To: xen-devel <xen-devel@lists.xensource.com>
Cc: Dave Winchell <dwinchell@virtualiron.com>
Subject: [PATCH] Fix hvm guest time to be more accurate
Date: Wed, 24 Oct 2007 17:15:38 -0400 [thread overview]
Message-ID: <471FB5FA.6060507@virtualiron.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 640 bytes --]
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@virtualron.com>
Signed-off-by: Dave Winchell <dwinchell@virtualiron.com>
[-- Attachment #2: xen-platform-time.patch --]
[-- Type: text/x-patch, Size: 8750 bytes --]
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);
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
next reply other threads:[~2007-10-24 21:15 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-24 21:15 Ben Guthro [this message]
2007-10-25 5:52 ` [PATCH] Fix hvm guest time to be more accurate Dong, Eddie
2007-10-25 14:45 ` Dave Winchell
2007-10-26 6:48 ` Dong, Eddie
2007-10-26 13:56 ` Dave Winchell
2007-10-26 18:18 ` Dave Winchell
2007-10-29 9:58 ` Dong, Eddie
2007-10-29 15:00 ` Dave Winchell
2007-10-29 17:29 ` Keir Fraser
2007-10-29 19:55 ` Dave Winchell
2007-10-29 20:40 ` Keir Fraser
2007-10-29 20:44 ` Dave Winchell
2007-10-30 11:45 ` Dong, Eddie
2007-10-29 9:57 ` Dong, Eddie
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=471FB5FA.6060507@virtualiron.com \
--to=bguthro@virtualiron.com \
--cc=dwinchell@virtualiron.com \
--cc=xen-devel@lists.xensource.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.