Here is a patch to make the gettimeofday system call more accurate for
Alpha SMP.  Rather than
just returning xtime.tv_sec and xtime.tv_usec this patch makes each CPU
record its process cycle
counter in the cpuinfo_alpha structure for that CPU in
smp_percpu_timer_interrupt().  When
gettimeofday is called it adds the difference between the current
process cycle counter and last one
stored in the cpuinfo_alpha structure to the time.tv_sec and
xtime.tv_usec.  This is not perfect but if
you stay on the same CPU its close to what is returned on a non-SMP
alpha kernel.

Larry Woodman
http://www.missioncriticallinux.com

diff -u --recursive linux-2.3.99-pre3.vanilla/arch/alpha/kernel/smp.c 
linux-2.3.99-pre3.clock/arch/alpha/kernel/smp.c
--- linux-2.3.99-pre3.vanilla/arch/alpha/kernel/smp.c   Fri Mar 17 16:02:05 2000
+++ linux-2.3.99-pre3.clock/arch/alpha/kernel/smp.c     Fri Apr 24 09:58:04 2020
@@ -613,6 +613,13 @@
                               unsigned long user, unsigned long system,
                               int cpu);
 
+static inline __u32 rpcc(void)
+{
+    __u32 result;
+    asm volatile ("rpcc %0" : "=r"(result));
+    return result;
+}
+
 void
 smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
@@ -620,6 +627,8 @@
        unsigned long user = user_mode(regs);
        struct cpuinfo_alpha *data = &cpu_data[cpu];
 
+       /* remember the process cycle counter */
+       data->last_rpcc = rpcc();
        /* Record kernel PC.  */
        if (!user)
                alpha_do_profile(regs->pc);
diff -u --recursive linux-2.3.99-pre3.vanilla/arch/alpha/kernel/time.c 
linux-2.3.99-pre3.clock/arch/alpha/kernel/time.c
--- linux-2.3.99-pre3.vanilla/arch/alpha/kernel/time.c  Wed Mar 15 14:08:04 2000
+++ linux-2.3.99-pre3.clock/arch/alpha/kernel/time.c    Fri Apr 24 09:59:24 2020
@@ -304,10 +304,15 @@
 {
        unsigned long sec, usec, lost, flags;
        unsigned long delta_cycles, delta_usec, partial_tick;
+       struct cpuinfo_alpha *data = &cpu_data[smp_processor_id()];
 
        read_lock_irqsave(&xtime_lock, flags);
 
+#ifdef __SMP__
+       delta_cycles = rpcc() - data->last_rpcc;
+#else
        delta_cycles = rpcc() - state.last_time;
+#endif
        sec = xtime.tv_sec;
        usec = xtime.tv_usec;
        partial_tick = state.partial_tick;
@@ -315,11 +320,6 @@
 
        read_unlock_irqrestore(&xtime_lock, flags);
 
-#ifdef __SMP__
-       /* Until and unless we figure out how to get cpu cycle counters
-          in sync and keep them there, we can't use the rpcc tricks.  */
-       delta_usec = lost * (1000000 / HZ);
-#else
        /*
         * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
         *      = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
@@ -334,10 +334,11 @@
         */
 
        delta_usec = (delta_cycles * state.scaled_ticks_per_cycle 
+#ifndef __SMP__
                      + partial_tick
+#endif
                      + (lost << FIX_SHIFT)) * 15625;
        delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-#endif
 
        usec += delta_usec;
        if (usec >= 1000000) {
diff -u --recursive linux-2.3.99-pre3.vanilla/include/asm-alpha/smp.h 
linux-2.3.99-pre3.clock/include/asm-alpha/smp.h
--- linux-2.3.99-pre3.vanilla/include/asm-alpha/smp.h   Fri Mar 17 16:02:05 2000
+++ linux-2.3.99-pre3.clock/include/asm-alpha/smp.h     Fri Apr 24 10:00:35 2020
@@ -21,6 +21,7 @@
 
 #include <linux/threads.h>
 #include <asm/irq.h>
+#include <linux/types.h>
 
 struct cpuinfo_alpha {
        unsigned long loops_per_sec;
@@ -33,6 +34,7 @@
        unsigned long prof_multiplier;
        unsigned long prof_counter;
        int irq_count, bh_count;
+       __u32 last_rpcc;
        unsigned char mcheck_expected;
        unsigned char mcheck_taken;
        unsigned char mcheck_extra;

Reply via email to