Skip to contentSkip to conversation

per-cpu timer changes

PATCH New Don Fry 1 participant 1 message May 24, 2005

lore
Share & tools
lore

Don Fry

author
#0 lore raw

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_st
 
     arch_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 unu
     add_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(void
 	rdtsc(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]