Ingo's CPU scheduler update (in -mm kernels) needs a new sched_clock() function which returns nanoseconds. The patch provides implementations for ppc, ppc64, x86_64 and sparc64. The x86_64 version could have overflow issues, the calculation is done in 32bits only with an multiply. But I hope it's good enough for the scheduler The ppc64 version needs scaling: it's only accurate for 1GHz CPUs. 25-akpm/arch/ppc/kernel/time.c | 25 +++++++++++++++++++++++++ 25-akpm/arch/ppc64/kernel/time.c | 9 +++++++++ 25-akpm/arch/sparc64/kernel/time.c | 20 ++++++++++++++++++-- 25-akpm/arch/x86_64/kernel/time.c | 13 +++++++++++++ 25-akpm/include/asm-ppc/time.h | 8 ++++++++ 5 files changed, 73 insertions(+), 2 deletions(-) diff -puN arch/ppc/kernel/time.c~ppc-sched_clock arch/ppc/kernel/time.c --- 25/arch/ppc/kernel/time.c~ppc-sched_clock Thu Sep 18 16:53:56 2003 +++ 25-akpm/arch/ppc/kernel/time.c Thu Sep 18 16:53:56 2003 @@ -83,6 +83,7 @@ time_t last_rtc_update; unsigned tb_ticks_per_jiffy; unsigned tb_to_us; unsigned tb_last_stamp; +unsigned long tb_to_ns_scale; extern unsigned long wall_jiffies; @@ -309,6 +310,7 @@ void __init time_init(void) tb_to_us = 0x418937; } else { ppc_md.calibrate_decr(); + tb_to_ns_scale = mulhwu(tb_to_us, 1000 << 10); } /* Now that the decrementer is calibrated, it can be used in case the @@ -432,3 +434,26 @@ unsigned mulhwu_scale_factor(unsigned in return mlt; } +unsigned long long sched_clock(void) +{ + unsigned long lo, hi, hi2; + unsigned long long tb; + + if (!__USE_RTC()) { + do { + hi = get_tbu(); + lo = get_tbl(); + hi2 = get_tbu(); + } while (hi2 != hi); + tb = ((unsigned long long) hi << 32) | lo; + tb = (tb * tb_to_ns_scale) >> 10; + } else { + do { + hi = get_rtcu(); + lo = get_rtcl(); + hi2 = get_rtcu(); + } while (hi2 != hi); + tb = ((unsigned long long) hi) * 1000000000 + lo; + } + return tb; +} diff -puN include/asm-ppc/time.h~ppc-sched_clock include/asm-ppc/time.h --- 25/include/asm-ppc/time.h~ppc-sched_clock Thu Sep 18 16:53:56 2003 +++ 25-akpm/include/asm-ppc/time.h Thu Sep 18 16:53:56 2003 @@ -97,6 +97,13 @@ extern __inline__ unsigned long get_rtcl return rtcl; } +extern __inline__ unsigned long get_rtcu(void) +{ + unsigned long rtcu; + asm volatile("mfrtcu %0" : "=r" (rtcu)); + return rtcu; +} + extern __inline__ unsigned get_native_tbl(void) { if (__USE_RTC()) return get_rtcl(); @@ -140,6 +147,7 @@ extern __inline__ unsigned binary_tbl(vo #endif /* Use mulhwu to scale processor timebase to timeval */ +/* Specifically, this computes (x * y) / 2^32. -- paulus */ #define mulhwu(x,y) \ ({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) diff -puN arch/ppc64/kernel/time.c~ppc-sched_clock arch/ppc64/kernel/time.c --- 25/arch/ppc64/kernel/time.c~ppc-sched_clock Thu Sep 18 16:54:39 2003 +++ 25-akpm/arch/ppc64/kernel/time.c Thu Sep 18 16:54:39 2003 @@ -307,6 +307,15 @@ int timer_interrupt(struct pt_regs * reg return 1; } +/* + * Scheduler clock - returns current time in nanosec units. + * + * This is wrong, but my CPUs run at 1GHz, so nyer nyer. + */ +unsigned long long sched_clock(void) +{ + return get_tb(); +} /* * This version of gettimeofday has microsecond resolution. diff -puN arch/sparc64/kernel/time.c~ppc-sched_clock arch/sparc64/kernel/time.c --- 25/arch/sparc64/kernel/time.c~ppc-sched_clock Thu Sep 18 16:54:39 2003 +++ 25-akpm/arch/sparc64/kernel/time.c Thu Sep 18 16:54:39 2003 @@ -416,6 +416,7 @@ unsigned long timer_tick_offset; unsigned long timer_tick_compare; static unsigned long timer_ticks_per_usec_quotient; +static unsigned long timer_ticks_per_nsec_quotient; #define TICK_SIZE (tick_nsec / 1000) @@ -1051,12 +1052,18 @@ static struct notifier_block sparc64_cpu #endif /* The quotient formula is taken from the IA64 port. */ +#define SPARC64_USEC_PER_CYC_SHIFT 30UL +#define SPARC64_NSEC_PER_CYC_SHIFT 30UL void __init time_init(void) { unsigned long clock = sparc64_init_timers(timer_interrupt); timer_ticks_per_usec_quotient = - (((1000000UL << 30) + + (((1000000UL << SPARC64_USEC_PER_CYC_SHIFT) + + (clock / 2)) / clock); + + timer_ticks_per_nsec_quotient = + (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + (clock / 2)) / clock); #ifdef CONFIG_CPU_FREQ @@ -1072,7 +1079,16 @@ static __inline__ unsigned long do_getti ticks += timer_tick_offset; ticks -= timer_tick_compare; - return (ticks * timer_ticks_per_usec_quotient) >> 30UL; + return (ticks * timer_ticks_per_usec_quotient) + >> SPARC64_USEC_PER_CYC_SHIFT; +} + +unsigned long long sched_clock(void) +{ + unsigned long ticks = tick_ops->get_tick(); + + return (ticks * timer_ticks_per_nsec_quotient) + >> SPARC64_NSEC_PER_CYC_SHIFT; } int do_settimeofday(struct timespec *tv) diff -puN arch/x86_64/kernel/time.c~ppc-sched_clock arch/x86_64/kernel/time.c --- 25/arch/x86_64/kernel/time.c~ppc-sched_clock Thu Sep 18 16:54:39 2003 +++ 25-akpm/arch/x86_64/kernel/time.c Thu Sep 18 16:54:39 2003 @@ -370,6 +370,19 @@ static irqreturn_t timer_interrupt(int i return IRQ_HANDLED; } +/* RED-PEN: calculation is done in 32bits with multiply for performance + and could overflow, it may be better (but slower)to use an 64bit division. */ +unsigned long long sched_clock(void) +{ + unsigned long a; + + if (__vxtime.mode == VXTIME_HPET) + return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> 32; + + rdtscll(a); + return (a * vxtime.tsc_quot) >> 32; +} + unsigned long get_cmos_time(void) { unsigned int timeout, year, mon, day, hour, min, sec; _