From: Jeremy Fitzhardinge Date: Sun, 25 Jan 2004 03:32:58 +0000 (+0000) Subject: Don't use TSC for internal timing purposes. This is for two reasons: X-Git-Tag: svn/VALGRIND_2_1_1~82 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9875ad6c74afc1a8eea581fd7ff3067bc4f29337;p=thirdparty%2Fvalgrind.git Don't use TSC for internal timing purposes. This is for two reasons: - old CPUs (and their modern embedded clones) don't implement the TSC - new machines with power management, the TSC changes rate, and so is useless as a timebase Valgrind doesn't use read_millisecond_timer very much these days, so the expense of doing a gettimeofday syscall shouldn't be a huge issue. Naturally, rdtsc is still available for client purposes (if the host CPU supports it). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2226 --- diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index fcb3efb543..33f7ee6922 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -1058,10 +1058,6 @@ extern void* VG_(brk) ( void* end_data_segment ); /* Skins use VG_(strdup)() which doesn't expose ArenaId */ extern Char* VG_(arena_strdup) ( ArenaId aid, const Char* s); -/* Skins shouldn't need these...(?) */ -extern void VG_(start_rdtsc_calibration) ( void ); -extern void VG_(end_rdtsc_calibration) ( void ); - extern Int VG_(fcntl) ( Int fd, Int cmd, Int arg ); extern Int VG_(select)( Int n, vki_fd_set* readfds, diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index 11b80d4848..1954cb89e5 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -2884,12 +2884,6 @@ int main(int argc, char **argv) VGP_PUSHCC(VgpStartup); - //-------------------------------------------------------------- - // Start calibration of our RDTSC-based clock - // p: n/a - //-------------------------------------------------------------- - VG_(start_rdtsc_calibration)(); - //-------------------------------------------------------------- // Reserve Valgrind's kickstart, heap and stack // p: XXX ??? @@ -2943,14 +2937,6 @@ int main(int argc, char **argv) if (VG_(needs).core_errors || VG_(needs).skin_errors) VG_(load_suppressions)(); - //-------------------------------------------------------------- - // End calibrating our RDTSC-based clock, having waited a while. - // p: VG_(start_rdtsc_calibration)() [obviously] - //-------------------------------------------------------------- - // Nb: Don't have to wait very long; it does pretty well even if - // start_rdtsc_calibration() is immediately before this. - VG_(end_rdtsc_calibration)(); - //-------------------------------------------------------------- // Initialise translation table and translation cache // p: read_procselfmaps [so the anonymous mmaps for the TT/TC diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c index 41cd3ee9b5..e9cebb2ace 100644 --- a/coregrind/vg_mylibc.c +++ b/coregrind/vg_mylibc.c @@ -1526,130 +1526,28 @@ Int VG_(system) ( Char* cmd ) /* --------------------------------------------------------------------- - Support for a millisecond-granularity counter using RDTSC. + Support for a millisecond-granularity timer. ------------------------------------------------------------------ */ -static __inline__ ULong do_rdtsc_insn ( void ) -{ - ULong x; - __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); - return x; -} - -/* 0 = pre-calibration, 1 = calibration, 2 = running */ -static Int rdtsc_calibration_state = 0; -static ULong rdtsc_ticks_per_millisecond = 0; /* invalid value */ - -static struct vki_timeval rdtsc_cal_start_timeval; -static struct vki_timeval rdtsc_cal_end_timeval; - -static ULong rdtsc_cal_start_raw; -static ULong rdtsc_cal_end_raw; - UInt VG_(read_millisecond_timer) ( void ) { - ULong rdtsc_now; - // If called before rdtsc setup completed (eg. from SK_(pre_clo_init)()) - // just return 0. - if (rdtsc_calibration_state < 2) return 0; - rdtsc_now = do_rdtsc_insn(); - vg_assert(rdtsc_now > rdtsc_cal_end_raw); - rdtsc_now -= rdtsc_cal_end_raw; - rdtsc_now /= rdtsc_ticks_per_millisecond; - return (UInt)rdtsc_now; -} - - -void VG_(start_rdtsc_calibration) ( void ) -{ + ULong base; + struct vki_timeval tv_now; + ULong now; Int res; - vg_assert(rdtsc_calibration_state == 0); - rdtsc_calibration_state = 1; - rdtsc_cal_start_raw = do_rdtsc_insn(); - res = VG_(do_syscall)(__NR_gettimeofday, (UInt)&rdtsc_cal_start_timeval, - (UInt)NULL); - vg_assert(!VG_(is_kerror)(res)); -} -void VG_(end_rdtsc_calibration) ( void ) -{ - Int res, loops; - ULong cpu_clock_MHZ; - ULong cal_clock_ticks; - ULong cal_wallclock_microseconds; - ULong wallclock_start_microseconds; - ULong wallclock_end_microseconds; - struct vki_timespec req; - struct vki_timespec rem; - - vg_assert(rdtsc_calibration_state == 1); - rdtsc_calibration_state = 2; - - /* Try and delay for 20 milliseconds, so that we can at least have - some minimum level of accuracy. */ - req.tv_sec = 0; - req.tv_nsec = 20 * 1000 * 1000; - loops = 0; - while (True) { - res = VG_(nanosleep)(&req, &rem); - vg_assert(res == 0 /*ok*/ || res == 1 /*interrupted*/); - if (res == 0) - break; - if (rem.tv_sec == 0 && rem.tv_nsec == 0) - break; - req = rem; - loops++; - if (loops > 100) - VG_(core_panic)("calibration nanosleep loop failed?!"); - } - - /* Now read both timers, and do the Math. */ - rdtsc_cal_end_raw = do_rdtsc_insn(); - res = VG_(do_syscall)(__NR_gettimeofday, (UInt)&rdtsc_cal_end_timeval, + res = VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL); + + now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec; + + if (base == 0) + base = now; - vg_assert(rdtsc_cal_end_raw > rdtsc_cal_start_raw); - cal_clock_ticks = rdtsc_cal_end_raw - rdtsc_cal_start_raw; - - wallclock_start_microseconds - = (1000000ULL * (ULong)(rdtsc_cal_start_timeval.tv_sec)) - + (ULong)(rdtsc_cal_start_timeval.tv_usec); - wallclock_end_microseconds - = (1000000ULL * (ULong)(rdtsc_cal_end_timeval.tv_sec)) - + (ULong)(rdtsc_cal_end_timeval.tv_usec); - vg_assert(wallclock_end_microseconds > wallclock_start_microseconds); - cal_wallclock_microseconds - = wallclock_end_microseconds - wallclock_start_microseconds; - - /* Since we just nanoslept for 20 ms ... */ - vg_assert(cal_wallclock_microseconds >= 20000); - - /* Now we know (roughly) that cal_clock_ticks on RDTSC take - cal_wallclock_microseconds elapsed time. Calculate the RDTSC - ticks-per-millisecond value. */ - if (0) - VG_(printf)("%lld ticks in %lld microseconds\n", - cal_clock_ticks, cal_wallclock_microseconds ); - - rdtsc_ticks_per_millisecond - = cal_clock_ticks / (cal_wallclock_microseconds / 1000ULL); - cpu_clock_MHZ - = (1000ULL * rdtsc_ticks_per_millisecond) / 1000000ULL; - if (VG_(clo_verbosity) >= 1) - VG_(message)(Vg_UserMsg, "Estimated CPU clock rate is %d MHz", - (UInt)cpu_clock_MHZ); - if (cpu_clock_MHZ < 50 || cpu_clock_MHZ > 10000) - VG_(core_panic)("end_rdtsc_calibration: " - "estimated CPU MHz outside range 50 .. 10000"); - /* Paranoia about division by zero later. */ - vg_assert(rdtsc_ticks_per_millisecond != 0); - if (0) - VG_(printf)("ticks per millisecond %llu\n", - rdtsc_ticks_per_millisecond); + return (now - base) / 1000; } - /* --------------------------------------------------------------------- Primitive support for bagging memory via mmap. ------------------------------------------------------------------ */