[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] Fix hvm guest time to be more accurate
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |