From 04229f0581855f1d0450a5b412794fa34672b390 Mon Sep 17 00:00:00 2001 From: Erik van der Kouwe Date: Tue, 11 Jan 2011 11:03:37 +0000 Subject: [PATCH] Servers request TSC freq from kernel rather than each one measuring it individually --- lib/libsys/tsc_util.c | 82 +++++++++++++------------------------------ 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/lib/libsys/tsc_util.c b/lib/libsys/tsc_util.c index daa8a8c04..545991c9b 100644 --- a/lib/libsys/tsc_util.c +++ b/lib/libsys/tsc_util.c @@ -10,7 +10,10 @@ #include "sysutil.h" -#define CALIBRATE_TICKS(h) ((h)/5) +#ifndef CONFIG_MAX_CPUS +#define CONFIG_MAX_CPUS 1 +#endif + #define MICROHZ 1000000 /* number of micros per second */ #define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ @@ -21,42 +24,28 @@ panic("calibrate failed: %d", r); \ } -static u32_t calib_tsc, Hz = 0; +static u32_t calib_mhz, Hz = 0; static int calibrated = 0; int tsc_calibrate(void) { - u64_t start, end, diff; - struct tms tms; - unsigned long t = 0; + struct cpu_info cpu_info[CONFIG_MAX_CPUS]; /* Get HZ. */ Hz = sys_hz(); - /* Wait for clock to tick. */ - while(!t || (t == times(&tms))) - t = times(&tms); - - t++; - - /* Wait for clock to tick CALIBRATE_TICKS times, and time - * this using the TSC. + /* Obtain CPU frequency from kernel */ + if (sys_getcpuinfo(&cpu_info)) { + printf("tsc_calibrate: cannot get cpu info\n"); + return -1; + } + + /* For now, use the frequency of the first CPU; everything here will + * break down in case we get scheduled on multiple CPUs with different + * frequencies regardless */ - read_tsc_64(&start); - while(times(&tms) < t+CALIBRATE_TICKS(Hz)) ; - read_tsc_64(&end); - - diff = sub64(end, start); - if(ex64hi(diff) != 0) - panic("tsc_calibrate: CALIBRATE_TICKS too high for TSC frequency"); - calib_tsc = ex64lo(diff); -#if 0 - printf("tsc_calibrate: " - "%lu cycles/%d ticks of %d Hz; %lu cycles/s\n", - calib_tsc, CALIBRATE_TICKS(Hz), Hz, - div64u(mul64u(calib_tsc, Hz), CALIBRATE_TICKS(Hz))); -#endif + calib_mhz = cpu_info[0].freq; calibrated = 1; return OK; @@ -73,8 +62,7 @@ micro_delay(u32_t micros) CALIBRATE; /* We have to know when to end the delay. */ - end = add64u(now, div64u(mul64u(calib_tsc, - micros * Hz / CALIBRATE_TICKS(Hz)), MICROHZ)); + end = add64(now, mul64u(micros, calib_mhz * 1000)); /* If we have to wait for at least one HZ tick, use the regular * tickdelay first. Round downwards on purpose, so the average @@ -95,38 +83,16 @@ micro_delay(u32_t micros) u32_t tsc_64_to_micros(u64_t tsc) { u64_t tmp; - u32_t imv; CALIBRATE; - /* Various formulas provide various levels of accuracy depending on - * what still fits in a 64-bit number. - */ - if (ex64hi(tsc) != 0) { - if (ex64hi(tsc) < ULONG_MAX) { - tmp = mul64u(ex64hi(tsc) + 1, MICROHZ); - - if (ex64hi(tmp) == 0) { - imv = div64u(mul64(tsc, cvu64(MICROHZ)), - calib_tsc); - - tmp = mul64u(imv, CALIBRATE_TICKS(Hz)); - - if (ex64hi(tmp) == 0) { - /* Mid accuracy. */ - return ex64lo(tmp) / Hz; - } - } - } - - /* Low accuracy for large numbers. */ - return div64u(mul64u(div64u(tsc, calib_tsc), - MICROHZ * CALIBRATE_TICKS(Hz)), Hz); + tmp = div64u64(tsc, calib_mhz); + if (ex64hi(tmp)) { + printf("tsc_64_to_micros: more than 2^32ms\n"); + return ~0UL; + } else { + return ex64lo(tmp); } - - /* High accuracy for small numbers (the common case). */ - return div64u(mul64u(ex64lo(tsc), MICROHZ * CALIBRATE_TICKS(Hz)), - calib_tsc) / Hz; } u32_t tsc_to_micros(u32_t low, u32_t high) @@ -138,5 +104,5 @@ u32_t tsc_get_khz(void) { CALIBRATE; - return calib_tsc / (CALIBRATE_TICKS(Hz) * MICROSPERTICK(Hz)) * 1000; + return calib_mhz * 1000; } -- 2.44.0