diff options
author | Benety Goh <benety@mongodb.com> | 2014-06-03 16:52:03 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2014-06-05 23:03:50 -0400 |
commit | ffaa85ae89335efbef26338a12cc41b351fc8bda (patch) | |
tree | b59b9b5f116ecf25f05f5855e749ec66363b4fc9 /src/mongo/util/timer.cpp | |
parent | c4fa4dc85aec3b8dfd9ada7a58521d8f1bbf4fff (diff) | |
download | mongo-ffaa85ae89335efbef26338a12cc41b351fc8bda.tar.gz |
SERVER-13792 added runtime and build-time checks for POSIX monotonic clocks. de-inlined Timer::now() implementations
Diffstat (limited to 'src/mongo/util/timer.cpp')
-rw-r--r-- | src/mongo/util/timer.cpp | 79 |
1 files changed, 67 insertions, 12 deletions
diff --git a/src/mongo/util/timer.cpp b/src/mongo/util/timer.cpp index 597c4e15aa5..90e61b55423 100644 --- a/src/mongo/util/timer.cpp +++ b/src/mongo/util/timer.cpp @@ -27,14 +27,25 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/util/timer.h" +#include <ctime> #include <limits> +#if defined(MONGO_HAVE_HEADER_UNISTD_H) +#include <unistd.h> +#endif + +#include "mongo/util/assert_util.h" +#include "mongo/util/time_support.h" namespace mongo { - // default value of 1 so that during startup initialization if referenced no division by zero - long long Timer::_countsPerSecond = 1; + // Set default value to reflect "generic" timer implementation. + // Define Timer::_countsPerSecond before static initializer "atstartuputil" to ensure correct + // relative sequencing regardless of how _countsPerSecond is initialized (static or dynamic). + long long Timer::_countsPerSecond = Timer::microsPerSecond; namespace { @@ -43,19 +54,66 @@ namespace mongo { AtStartup(); } atstartuputil; -#if defined(MONGO_TIMER_IMPL_WIN32) + // "Generic" implementation for Timer::now(). + long long _timerNowGeneric() { + return curTimeMicros64(); + } + + // Function pointer to Timer::now() implementation. + // Overridden in AtStartup() with better implementation where available. + long long (*_timerNow)() = &_timerNowGeneric; + +#if defined(_WIN32) + + /** + * Windows-specific implementation of the + * Timer class. Windows selects the best available timer, in its estimation, for + * measuring time at high resolution. This may be the HPET of the TSC on x86 systems, + * but is promised to be synchronized across processors, barring BIOS errors. + */ + long long timerNowWindows() { + LARGE_INTEGER i; + fassert(16161, QueryPerformanceCounter(&i)); + return i.QuadPart; + } AtStartup::AtStartup() { LARGE_INTEGER x; bool ok = QueryPerformanceFrequency(&x); verify(ok); Timer::_countsPerSecond = x.QuadPart; + _timerNow = &timerNowWindows; } -#elif defined(MONGO_TIMER_IMPL_POSIX_MONOTONIC_CLOCK) +#elif defined(MONGO_HAVE_POSIX_MONOTONIC_CLOCK) + + /** + * Implementation for timer on systems that support the + * POSIX clock API and CLOCK_MONOTONIC clock. + */ + long long timerNowPosixMonotonicClock() { + timespec the_time; + long long result; + + fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time)); + + // Safe for 292 years after the clock epoch, even if we switch to a signed time value. + // On Linux, the monotonic clock's epoch is the UNIX epoch. + result = static_cast<long long>(the_time.tv_sec); + result *= Timer::nanosPerSecond; + result += static_cast<long long>(the_time.tv_nsec); + return result; + } AtStartup::AtStartup() { + // If the monotonic clock is not available at runtime (sysconf() returns 0 or -1), + // do not override the generic implementation or modify Timer::_countsPerSecond. + if (sysconf(_SC_MONOTONIC_CLOCK) <= 0) { + return; + } + Timer::_countsPerSecond = Timer::nanosPerSecond; + _timerNow = &timerNowPosixMonotonicClock; // Make sure that the current time relative to the (unspecified) epoch isn't already too // big to represent as a 64-bit count of nanoseconds. @@ -65,17 +123,14 @@ namespace mongo { fassert(16162, !clock_gettime(CLOCK_MONOTONIC, &the_time)); fassert(16163, static_cast<long long>(the_time.tv_sec) < maxSecs); } - -#elif defined(MONGO_TIMER_IMPL_GENERIC) - - AtStartup::AtStartup() { - Timer::_countsPerSecond = Timer::microsPerSecond; - } - #else -#error "Unknown mongo::Timer implementation" + AtStartup::AtStartup() { } #endif } // namespace + long long Timer::now() const { + return _timerNow(); + } + } // namespace mongo |