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 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index fcb3efb..33f7ee6 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -1058,10 +1058,6 @@
/* 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 11b80d4..1954cb8 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -2885,12 +2885,6 @@
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 ???
//--------------------------------------------------------------
@@ -2944,14 +2938,6 @@
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
// aren't identified as part of the client, which would waste
diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c
index 41cd3ee..e9cebb2 100644
--- a/coregrind/vg_mylibc.c
+++ b/coregrind/vg_mylibc.c
@@ -1526,130 +1526,28 @@
/* ---------------------------------------------------------------------
- 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;
+ res = VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now,
+ (UInt)NULL);
- vg_assert(rdtsc_calibration_state == 1);
- rdtsc_calibration_state = 2;
+ now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
+
+ if (base == 0)
+ base = now;
- /* 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,
- (UInt)NULL);
-
- 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.
------------------------------------------------------------------ */