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;