summaryrefslogtreecommitdiff
path: root/src/timer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/timer.cpp')
-rw-r--r--src/timer.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/timer.cpp b/src/timer.cpp
new file mode 100644
index 0000000..22015ff
--- /dev/null
+++ b/src/timer.cpp
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2006 International Business Machines Corporation. *
+ * All rights reserved. This program and the accompanying materials *
+ * are made available under the terms of the Common Public License v1.0 *
+ * which accompanies this distribution, and is available at *
+ * http://www.opensource.org/licenses/cpl1.0.php *
+ * *
+ * Contributors: *
+ * Douglas M. Pase - initial API and implementation *
+ *******************************************************************************/
+
+//
+// Configuration
+//
+
+// Implementation header
+#include "timer.h"
+
+// System includes
+#include <cstdio>
+#include <sys/time.h>
+
+static int64 read_rtc();
+static void calibrate_rtc(int n);
+static double wall_seconds();
+
+static int wall_ticks = -1;
+static int rtc_ticks = -1;
+static double wall_elapsed = -1;
+static int64 rtc_elapsed = -1;
+static double time_factor = -1;
+
+#if !defined(RTC) && !defined(GTOD)
+#define RTC
+#endif
+
+
+//
+// Implementation
+//
+
+#if defined(RTC)
+
+double Timer::seconds() {
+ return (double) read_rtc() * time_factor;
+}
+
+int64 Timer::ticks() {
+ // See pg. 406 of the AMD x86-64 Architecture
+ // Programmer's Manual, Volume 2, System Programming
+ unsigned int eax = 0, edx = 0;
+
+ __asm__ __volatile__(
+ "rdtsc ;"
+ "movl %%eax,%0;"
+ "movl %%edx,%1;"
+ ""
+ : "=r"(eax), "=r"(edx)
+ :
+ : "%eax", "%edx"
+ );
+
+ return ((int64) edx << 32) | (int64) eax;
+}
+
+static int64 read_rtc() {
+ // See pg. 406 of the AMD x86-64 Architecture
+ // Programmer's Manual, Volume 2, System Programming
+ unsigned int eax = 0, edx = 0;
+
+ __asm__ __volatile__(
+ "rdtsc ;"
+ "movl %%eax,%0;"
+ "movl %%edx,%1;"
+ ""
+ : "=r"(eax), "=r"(edx)
+ :
+ : "%eax", "%edx"
+ );
+
+ return ((int64) edx << 32) | (int64) eax;
+}
+
+void Timer::calibrate() {
+ Timer::calibrate(1000);
+}
+
+void Timer::calibrate(int n) {
+ wall_ticks = n;
+
+ double wall_start, wall_finish, t;
+ t = wall_seconds();
+ while (t == (wall_start = wall_seconds())) {
+ ;
+ }
+ int64 rtc_start = read_rtc();
+ for (int i = 0; i < wall_ticks; i++) {
+ t = wall_seconds();
+ while (t == (wall_finish = wall_seconds())) {
+ ;
+ }
+ }
+ int64 rtc_finish = read_rtc();
+
+ wall_elapsed = wall_finish - wall_start;
+ rtc_elapsed = rtc_finish - rtc_start;
+ time_factor = wall_elapsed / (double) rtc_elapsed;
+}
+
+static double wall_seconds() {
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ return (double) t.tv_sec + (double) t.tv_usec * 1E-6;
+}
+
+#else
+
+double
+Timer::seconds()
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ return (double) t.tv_sec + (double) t.tv_usec * 1E-6;
+}
+
+int64
+Timer::ticks()
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ return 1000000 * (int64) t.tv_sec + (int64) t.tv_usec;
+}
+
+void
+Timer::calibrate()
+{
+}
+
+void
+Timer::calibrate(int n)
+{
+}
+
+#endif
+
+static double min(double v1, double v2) {
+ if (v2 < v1)
+ return v2;
+ return v1;
+}
+
+double Timer::resolution() {
+ double a, b, c = 1E9;
+ for (int i = 0; i < 10; i++) {
+ a = Timer::seconds();
+ while (a == (b = Timer::seconds()))
+ ;
+ a = Timer::seconds();
+ while (a == (b = Timer::seconds()))
+ ;
+ c = min(b - a, c);
+ }
+
+ return c;
+}