summaryrefslogtreecommitdiffstats
path: root/src/uscxml/concurrency/Timer.cpp
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2016-01-08 22:15:37 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2016-01-08 22:15:37 (GMT)
commit9f4d810400550d1b98ab944cd96f937720eb6b0d (patch)
treea30226ae642e54e217c9b89523d75f1346d5f7cb /src/uscxml/concurrency/Timer.cpp
parentf9eb54fc9c17116954846133b33f7a241e662cbc (diff)
downloaduscxml-9f4d810400550d1b98ab944cd96f937720eb6b0d.zip
uscxml-9f4d810400550d1b98ab944cd96f937720eb6b0d.tar.gz
uscxml-9f4d810400550d1b98ab944cd96f937720eb6b0d.tar.bz2
Fixed compilation for gcc on Linux again
Diffstat (limited to 'src/uscxml/concurrency/Timer.cpp')
-rw-r--r--src/uscxml/concurrency/Timer.cpp116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/uscxml/concurrency/Timer.cpp b/src/uscxml/concurrency/Timer.cpp
new file mode 100644
index 0000000..b05a907
--- /dev/null
+++ b/src/uscxml/concurrency/Timer.cpp
@@ -0,0 +1,116 @@
+// Copyright 2013 Alex Reece.
+//
+// A cross platform monotonic timer.
+
+// see https://github.com/awreece/monotonic_timer
+
+#include <unistd.h>
+#include "Timer.h"
+
+#define NANOS_PER_SECF 1000000000.0
+#define USECS_PER_SEC 1000000
+
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
+ // If we have it, use clock_gettime and CLOCK_MONOTONIC.
+
+ #include <time.h>
+
+ double uscxml::Timer::monotonic_seconds() {
+ struct timespec time;
+ // Note: Make sure to link with -lrt to define clock_gettime.
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ return ((double) time.tv_sec) + ((double) time.tv_nsec / (NANOS_PER_SECF));
+ }
+
+#elif defined(__APPLE__)
+ // If we don't have CLOCK_MONOTONIC, we might be on a Mac. There we instead
+ // use mach_absolute_time().
+
+ #include <mach/mach_time.h>
+
+ static mach_timebase_info_data_t info;
+ static void __attribute__((constructor)) init_info() {
+ mach_timebase_info(&info);
+ }
+
+ double uscxml::Timer::monotonic_seconds() {
+ uint64_t time = mach_absolute_time();
+ double dtime = (double) time;
+ dtime *= (double) info.numer;
+ dtime /= (double) info.denom;
+ return dtime / NANOS_PER_SECF;
+ }
+
+#elif defined(_MSC_VER)
+ // On Windows, use QueryPerformanceCounter and QueryPerformanceFrequency.
+
+ #include <windows.h>
+
+ static double PCFreq = 0.0;
+
+ // According to http://stackoverflow.com/q/1113409/447288, this will
+ // make this function a constructor.
+ // TODO(awreece) Actually attempt to compile on windows.
+ static void __cdecl init_pcfreq();
+ __declspec(allocate(".CRT$XCU")) void (__cdecl*init_pcfreq_)() = init_pcfreq;
+ static void __cdecl init_pcfreq() {
+ // Accoring to http://stackoverflow.com/a/1739265/447288, this will
+ // properly initialize the QueryPerformanceCounter.
+ LARGE_INTEGER li;
+ int has_qpc = QueryPerformanceFrequency(&li);
+ assert(has_qpc);
+
+ PCFreq = ((double) li.QuadPart) / 1000.0;
+ }
+
+ double uscxml::Timer::monotonic_seconds() {
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return ((double) li.QuadPart) / PCFreq;
+ }
+
+#else
+ // Fall back to rdtsc. The reason we don't use clock() is this scary message
+ // from the man page:
+ // "On several other implementations, the value returned by clock() also
+ // includes the times of any children whose status has been collected via
+ // wait(2) (or another wait-type call)."
+ //
+ // Also, clock() only has microsecond accuracy.
+ //
+ // This whitepaper offered excellent advice on how to use rdtscp for
+ // profiling: http://download.intel.com/embedded/software/IA/324264.pdf
+ //
+ // Unfortunately, we can't follow its advice exactly with our semantics,
+ // so we're just going to use rdtscp with cpuid.
+ //
+ // Note that rdtscp will only be available on new processors.
+
+ #include <stdint.h>
+
+ static inline uint64_t rdtsc() {
+ uint32_t hi, lo;
+ asm volatile("rdtscp\n"
+ "movl %%edx, %0\n"
+ "movl %%eax, %1\n"
+ "cpuid"
+ : "=r" (hi), "=r" (lo) : : "%rax", "%rbx", "%rcx", "%rdx");
+ return (((uint64_t)hi) << 32) | (uint64_t)lo;
+ }
+
+ static uint64_t rdtsc_per_sec = 0;
+ static void __attribute__((constructor)) init_rdtsc_per_sec() {
+ uint64_t before, after;
+
+ before = rdtsc();
+ usleep(USECS_PER_SEC);
+ after = rdtsc();
+
+ rdtsc_per_sec = after - before;
+ }
+
+ double uscxml::Timer::monotonic_seconds() {
+ return (double) rdtsc() / (double) rdtsc_per_sec;
+ }
+
+#endif