diff -r 092a15aa2430 xen/arch/x86/time.c --- a/xen/arch/x86/time.c Fri Jul 18 15:03:55 2008 +0100 +++ b/xen/arch/x86/time.c Fri Jul 25 19:14:39 2008 -0600 @@ -708,6 +708,51 @@ static unsigned long get_cmos_time(void) * System Time ***************************************************************************/ +u64 max_stime_skew = 0; /* record max intra-CPU stime skew */ +u64 stime_goes_backwards = 0; +static DEFINE_SPINLOCK(time_skew_lock); + +int measure_stime = 0; +boolean_param("measurestime", measure_stime); + +static inline void measure_stime_skew(s_time_t now, struct cpu_time *t, u64 tsc) +{ + long cur_procid; + static int ignore = 10000L; + static s_time_t last = 0; + static int last_procid; + int back = 0; + + if ( ignore > 0 ) + { + ignore--; /* ignore for awhile to wait for calibrate */ + return; + } + local_irq_disable(); + spin_lock(&time_skew_lock); + cur_procid = smp_processor_id(); + if ( last && last > now ) { + if ( last_procid != cur_procid ) { + if ( (last - now) > max_stime_skew ) + max_stime_skew = last - now; + } + else + { + stime_goes_backwards++; + back++; + } + } + last = now; + last_procid = cur_procid; + spin_unlock(&time_skew_lock); + local_irq_enable(); + if (back) + printk("back: now=%"PRIu64" tsc=%"PRIu64", local_tsc_stamp=%"PRIu64"" + " stime_local_stamp=%"PRIu64" shift=%d mul_frac=%"PRIu32"\n", + now, tsc, t->local_tsc_stamp, t->stime_local_stamp, + t->tsc_scale.shift, t->tsc_scale.mul_frac); +} + s_time_t get_s_time(void) { struct cpu_time *t = &this_cpu(cpu_time); @@ -717,6 +762,8 @@ s_time_t get_s_time(void) rdtscll(tsc); delta = tsc - t->local_tsc_stamp; now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale); + if (measure_stime) + measure_stime_skew(now,t,tsc); return now; } @@ -828,6 +875,10 @@ void do_settime(unsigned long secs, unsi rcu_read_unlock(&domlist_read_lock); } +u64 stime_skew_max = 0; +u32 stime_skew_count = 0; +u64 stime_skew_sum = 0; + static void local_time_calibration(void *unused) { struct cpu_time *t = &this_cpu(cpu_time); @@ -861,6 +912,10 @@ static void local_time_calibration(void /* The overall calibration scale multiplier. */ u32 calibration_mul_frac; + /* record skew vs platform counter */ + static int skip_max_skew_calc = 100; + u64 curr_stime_skew; + prev_tsc = t->local_tsc_stamp; prev_local_stime = t->stime_local_stamp; prev_master_stime = t->stime_master_stamp; @@ -875,6 +930,18 @@ static void local_time_calibration(void rdtscll(curr_tsc); local_irq_enable(); + if ( skip_max_skew_calc > 0) + skip_max_skew_calc--; /* allow calibration to converge */ + else + { + stime_skew_count++; + curr_stime_skew = curr_master_stime - curr_local_stime; + if ( (s64) curr_stime_skew < 0 ) + curr_stime_skew = - curr_stime_skew; + if ( curr_stime_skew > stime_skew_max ) + stime_skew_max = curr_stime_skew; + stime_skew_sum += curr_stime_skew; + } #if 0 printk("PRE%d: tsc=%"PRIu64" stime=%"PRIu64" master=%"PRIu64"\n", smp_processor_id(), prev_tsc, prev_local_stime, prev_master_stime); diff -r 092a15aa2430 xen/common/keyhandler.c --- a/xen/common/keyhandler.c Fri Jul 18 15:03:55 2008 +0100 +++ b/xen/common/keyhandler.c Fri Jul 25 19:14:39 2008 -0600 @@ -246,11 +246,26 @@ static void read_clocks_slave(void *unus cpu_clear(cpu, read_clocks_cpumask); } +/* + * Print collected skew information; three different measures because: + * 1) Sync'ed skew is only sampled manually (e.g. xm debug-key t) but + * measures precisely what we want + * 2) max_stime_skew is sampled in get_s_time at high frequency but + * max capture requires near simultaneous access by different processors + * (and the code is ugly so Keir will probably remove ;-) + * 3) stime_skew_max is recorded at n Hz in local_time_calibration but + * only records positive skew from platform timer (n = #CPUs) + * NOTE: HVM's with timer_mode==0 intentionally cause intra-CPU skew + * Also, ntpd may affect results(?) so should be turned off + */ static void read_clocks(unsigned char key) { unsigned int cpu = smp_processor_id(), min_cpu, max_cpu; u64 min, max, dif, difus; + static u64 sumdif = 0, maxdif = 0, count = 0; static DEFINE_SPINLOCK(lock); + extern u64 max_stime_skew, stime_goes_backwards; + extern u64 stime_skew_max, stime_skew_count, stime_skew_sum; spin_lock(&lock); @@ -280,10 +295,20 @@ static void read_clocks(unsigned char ke spin_unlock(&lock); dif = difus = max - min; + if ( dif > maxdif ) + maxdif = dif; + count++; + sumdif += dif; do_div(difus, 1000); - printk("Min = %"PRIu64" ; Max = %"PRIu64" ; Diff = %"PRIu64 - " (%"PRIu64" microseconds)\n", - min, max, dif, difus); + printk("Synced skew: max=%"PRIu64"ns;avg=%"PRIu64"ns " + "cnt=%"PRIu64" cur=%"PRIu64"\n", + maxdif, sumdif/count, count, dif); + printk("Max recorded stime skew: %"PRIu64"ns backwards=%"PRIu64"\n", + max_stime_skew, stime_goes_backwards); + if ( !stime_skew_count ) + stime_skew_count = 1; /* shouldn't happen but avoid divide by zero */ + printk("Platform skew: max=%"PRIu64"ns; avg=%"PRIu64"ns; cnt=%"PRIu64"\n", + stime_skew_max, stime_skew_sum/stime_skew_count, stime_skew_count); } extern void dump_runq(unsigned char key);