per-cpu timer changes
PATCH 1/1 per-cpu timer changes
Here are some patches to help xen run on a system where the CPUs are not synchronized so that the tsc counters drift. Without this patch I get lots of 'time went backwards' messages in the linux logs. I still get an occasional message, but not the number I did previously.
It has been tested on an x86 box with 4 hyper threaded cpus (8 logical), but has not been tested with x86-64 or any other processor. The patches are against today's xeno-unstable.bk bits.
I am still trying to understand why I get any 'time went backwards' messages, but thought I would post this now to get feedback as it is.
xen/include/public/xen.h renamed from xen/include/public/xen.h.orig +16 -0
@@ -338,6 +338,21 @@ typedef struct }PACKED vcpu_info_t;/* 8 + arch */ /* +* Xen/kernel shared data +* per cpu timing information. +*/ +typedef struct time_info_st +{ +u32 time_version1; +u32 time_version2; +tsc_timestamp_t tsc_timestamp;/* TSC at last update */ +u64 system_time;/* time, in nanoseconds, since boot */ +u64 cpu_freq;/* CPU frequency (Hz) */ +u32 wc_sec;/* Secs 00:00:00 UTC, Jan 1, 1970. */ +u32 wc_usec;/* Usecs 00:00:00 UTC, Jan 1, 1970. */ +} PACKED time_info_t; + +/* * Xen/kernel shared data -- pointer provided in start_info. * NB. We expect that this struct is smaller than a page. */
@@ -412,6 +427,7 @@ typedef struct shared_info_starch_shared_info_t arch; +time_info_t vcpu_time[MAX_VIRT_CPUS ]; }PACKED shared_info_t;/*
xen/common/schedule.c renamed from xen/common/schedule.c.orig +23 -0
@@ -57,6 +57,7 @@ string_param("sched", opt_sched);/* Various timer handlers. */ static void s_timer_fn (unsigned long unused);static void t_timer_fn (unsigned long unused); +static void tsc_timer_fn (unsigned long unused);static void dom_timer_fn (unsigned long data);/* This is global for now so that private implementations can reach it */
@@ -80,6 +81,7 @@ static struct scheduler ops;/* Per-CPU periodic timer sends an event to the currently-executing domain. */ static struct ac_timer t_timer[NR_CPUS ]; +static struct ac_timer tsc_timer[NR_CPUS ];void free_domain_struct (struct domain *d) {
@@ -514,6 +516,7 @@ int idle_cpu(int cpu)* Timers: the scheduler utilises a number of timers * - s_timer: per CPU timer for preemption and scheduling decisions * - t_timer: per CPU periodic timer to send timer interrupt to current dom +* - tsc_timer: per CPU periodic timer to update time bases * - dom_timer: per domain timer to specifiy timeout values ****************************************************************************/
@@ -548,6 +551,18 @@ static void t_timer_fn(unsigned long unuadd_ac_timer (&t_timer[cpu]); } +/* Periodic tick timer: update time bases for per-cpu timing. */ +static void tsc_timer_fn (unsigned long unused) +{ +unsigned int cpu = current->processor; + +extern void percpu_ticks (void ); +percpu_ticks (); + + tsc_timer[cpu].expires =NOW () +MILLISECS (500 ); +add_ac_timer (&tsc_timer[cpu]); +} +/* Domain timer function, sends a virtual timer interrupt to domain */ static void dom_timer_fn (unsigned long data) {
@@ -578,6 +593,11 @@ void __init scheduler_init(void) t_timer[i].cpu = i; t_timer[i].data =3 ; t_timer[i].function = &t_timer_fn; + +init_ac_timer (&tsc_timer[i]); + tsc_timer[i].cpu = i; + tsc_timer[i].data =4 ; + tsc_timer[i].function = &tsc_timer_fn; } schedule_data[0 ].idle = &idle0_exec_domain;
@@ -609,6 +629,9 @@ void schedulers_start(void)t_timer_fn (0 );smp_call_function ((void *)t_timer_fn,NULL ,1 ,1 ); + +tsc_timer_fn (0 ); +smp_call_function ((void *)tsc_timer_fn,NULL ,1 ,1 ); }
xen/arch/x86/smpboot.c renamed from xen/arch/x86/smpboot.c.orig +3 -0
@@ -400,6 +400,7 @@ void __init start_secondary(void)extern void percpu_traps_init (void );extern void cpu_init (void ); +extern void setup_percpu_time (void );set_current (idle_task[cpu]);set_processor_id (cpu);
@@ -421,6 +422,8 @@ void __init start_secondary(void)construct_percpu_idt (cpu);#endif +setup_percpu_time (); +local_flush_tlb ();startup_cpu_idle_loop ();
xen/arch/x86/time.c renamed from xen/arch/x86/time.c.orig +71 -2
139 lines not on this page · raw message
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/time.c renamed from linux-2.6.11-xen-sparse/arch/xen/i386/kernel/time.c.orig +37 -31
196 lines not on this page · raw message
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c renamed from linux-2.6.11-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c.orig +12 -9
@@ -10,6 +10,7 @@#include <linux/cpufreq.h> #include <linux/string.h> #include <linux/jiffies.h> +#include <linux/percpu.h> #include <asm/timer.h> #include <asm/io.h>
@@ -35,8 +36,8 @@ extern spinlock_t i8253_lock;static int use_tsc; -static unsigned long long monotonic_base; -static u32 monotonic_offset; +static DEFINE_PER_CPU(unsigned long long, monotonic_base); +static DEFINE_PER_CPU(u32, monotonic_offset);static seqlock_t monotonic_lock =SEQLOCK_UNLOCKED ;/* convert from cycles(64bits) => nanoseconds (64bits)
@@ -74,8 +75,8 @@ static inline unsigned long long cycles_*/ static unsigned long fast_gettimeoffset_quotient; -extern u32 shadow_tsc_stamp; -extern u64 shadow_system_time; +extern DEFINE_PER_CPU(u32, shadow_tsc_stamp); +extern DEFINE_PER_CPU(u64, shadow_system_time);static unsigned long get_offset_tsc (void ) {
@@ -86,7 +87,7 @@ static unsigned long get_offset_tsc(voidrdtsc (eax,edx);/* .. relative to previous jiffy (32 bits is enough) */ - eax -= shadow_tsc_stamp; + eax -=per_cpu (shadow_tsc_stamp,smp_processor_id ());/* * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
@@ -110,12 +111,13 @@ static unsigned long long monotonic_cloc {unsigned long long last_offset, this_offset, base;unsigned seq; +int cpu =smp_processor_id ();/* atomically read monotonic base & last_offset */ do { seq =read_seqbegin (&monotonic_lock); - last_offset = monotonic_offset; - base = monotonic_base; + last_offset =per_cpu (monotonic_offset, cpu); + base =per_cpu (monotonic_base, cpu); }while (read_seqretry (&monotonic_lock, seq));/* Read the Time Stamp Counter */
@@ -152,11 +154,12 @@ unsigned long long sched_clock(void)static void mark_offset_tsc (void ) { +int cpu =smp_processor_id ();/* update the monotonic base value */ write_seqlock (&monotonic_lock); - monotonic_base = shadow_system_time; - monotonic_offset = shadow_tsc_stamp; +per_cpu (monotonic_base, cpu) =per_cpu (shadow_system_time, cpu); +per_cpu (monotonic_offset, cpu) =per_cpu (shadow_tsc_stamp, cpu);write_sequnlock (&monotonic_lock); }
Signature · 2 lines
Don Fry [email protected]