Skip to content

Commit ffaa85a

Browse files
committed
SERVER-13792 added runtime and build-time checks for POSIX monotonic clocks. de-inlined Timer::now() implementations
1 parent c4fa4dc commit ffaa85a

File tree

7 files changed

+97
-236
lines changed

7 files changed

+97
-236
lines changed

SConstruct

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,32 @@ def doConfigure(myenv):
13431343
posix_system = conf.CheckPosixSystem()
13441344
conf.Finish()
13451345

1346+
# Check if we are on a system that support the POSIX clock_gettime function
1347+
# and the "monotonic" clock.
1348+
posix_monotonic_clock = False
1349+
if posix_system:
1350+
def CheckPosixMonotonicClock(context):
1351+
1352+
test_body = """
1353+
#include <unistd.h>
1354+
#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0)
1355+
#error POSIX clock_gettime not supported
1356+
#elif !(defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0)
1357+
#error POSIX monotonic clock not supported
1358+
#endif
1359+
"""
1360+
1361+
context.Message('Checking if the POSIX monotonic clock is supported... ')
1362+
ret = context.TryCompile(textwrap.dedent(test_body), ".c")
1363+
context.Result(ret)
1364+
return ret
1365+
1366+
conf = Configure(myenv, help=False, custom_tests = {
1367+
'CheckPosixMonotonicClock' : CheckPosixMonotonicClock,
1368+
})
1369+
posix_monotonic_clock = conf.CheckPosixMonotonicClock()
1370+
conf.Finish()
1371+
13461372
if has_option('sanitize'):
13471373

13481374
if not (using_clang() or using_gcc()):
@@ -1615,6 +1641,9 @@ def doConfigure(myenv):
16151641
conf.CheckLib('rt')
16161642
conf.CheckLib('dl')
16171643

1644+
if posix_monotonic_clock:
1645+
conf.env.Append(CPPDEFINES=['MONGO_HAVE_POSIX_MONOTONIC_CLOCK'])
1646+
16181647
if (conf.CheckCXXHeader( "execinfo.h" ) and
16191648
conf.CheckDeclaration('backtrace', includes='#include <execinfo.h>') and
16201649
conf.CheckDeclaration('backtrace_symbols', includes='#include <execinfo.h>') and

src/mongo/util/timer-generic-inl.h

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/mongo/util/timer-inl.h

Lines changed: 0 additions & 60 deletions
This file was deleted.

src/mongo/util/timer-posixclock-inl.h

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/mongo/util/timer-win32-inl.h

Lines changed: 0 additions & 54 deletions
This file was deleted.

src/mongo/util/timer.cpp

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,25 @@
2727
* then also delete it in the license file.
2828
*/
2929

30+
#include "mongo/platform/basic.h"
31+
3032
#include "mongo/util/timer.h"
3133

34+
#include <ctime>
3235
#include <limits>
36+
#if defined(MONGO_HAVE_HEADER_UNISTD_H)
37+
#include <unistd.h>
38+
#endif
39+
40+
#include "mongo/util/assert_util.h"
41+
#include "mongo/util/time_support.h"
3342

3443
namespace mongo {
3544

36-
// default value of 1 so that during startup initialization if referenced no division by zero
37-
long long Timer::_countsPerSecond = 1;
45+
// Set default value to reflect "generic" timer implementation.
46+
// Define Timer::_countsPerSecond before static initializer "atstartuputil" to ensure correct
47+
// relative sequencing regardless of how _countsPerSecond is initialized (static or dynamic).
48+
long long Timer::_countsPerSecond = Timer::microsPerSecond;
3849

3950
namespace {
4051

@@ -43,19 +54,66 @@ namespace mongo {
4354
AtStartup();
4455
} atstartuputil;
4556

46-
#if defined(MONGO_TIMER_IMPL_WIN32)
57+
// "Generic" implementation for Timer::now().
58+
long long _timerNowGeneric() {
59+
return curTimeMicros64();
60+
}
61+
62+
// Function pointer to Timer::now() implementation.
63+
// Overridden in AtStartup() with better implementation where available.
64+
long long (*_timerNow)() = &_timerNowGeneric;
65+
66+
#if defined(_WIN32)
67+
68+
/**
69+
* Windows-specific implementation of the
70+
* Timer class. Windows selects the best available timer, in its estimation, for
71+
* measuring time at high resolution. This may be the HPET of the TSC on x86 systems,
72+
* but is promised to be synchronized across processors, barring BIOS errors.
73+
*/
74+
long long timerNowWindows() {
75+
LARGE_INTEGER i;
76+
fassert(16161, QueryPerformanceCounter(&i));
77+
return i.QuadPart;
78+
}
4779

4880
AtStartup::AtStartup() {
4981
LARGE_INTEGER x;
5082
bool ok = QueryPerformanceFrequency(&x);
5183
verify(ok);
5284
Timer::_countsPerSecond = x.QuadPart;
85+
_timerNow = &timerNowWindows;
5386
}
5487

55-
#elif defined(MONGO_TIMER_IMPL_POSIX_MONOTONIC_CLOCK)
88+
#elif defined(MONGO_HAVE_POSIX_MONOTONIC_CLOCK)
89+
90+
/**
91+
* Implementation for timer on systems that support the
92+
* POSIX clock API and CLOCK_MONOTONIC clock.
93+
*/
94+
long long timerNowPosixMonotonicClock() {
95+
timespec the_time;
96+
long long result;
97+
98+
fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time));
99+
100+
// Safe for 292 years after the clock epoch, even if we switch to a signed time value.
101+
// On Linux, the monotonic clock's epoch is the UNIX epoch.
102+
result = static_cast<long long>(the_time.tv_sec);
103+
result *= Timer::nanosPerSecond;
104+
result += static_cast<long long>(the_time.tv_nsec);
105+
return result;
106+
}
56107

57108
AtStartup::AtStartup() {
109+
// If the monotonic clock is not available at runtime (sysconf() returns 0 or -1),
110+
// do not override the generic implementation or modify Timer::_countsPerSecond.
111+
if (sysconf(_SC_MONOTONIC_CLOCK) <= 0) {
112+
return;
113+
}
114+
58115
Timer::_countsPerSecond = Timer::nanosPerSecond;
116+
_timerNow = &timerNowPosixMonotonicClock;
59117

60118
// Make sure that the current time relative to the (unspecified) epoch isn't already too
61119
// big to represent as a 64-bit count of nanoseconds.
@@ -65,17 +123,14 @@ namespace mongo {
65123
fassert(16162, !clock_gettime(CLOCK_MONOTONIC, &the_time));
66124
fassert(16163, static_cast<long long>(the_time.tv_sec) < maxSecs);
67125
}
68-
69-
#elif defined(MONGO_TIMER_IMPL_GENERIC)
70-
71-
AtStartup::AtStartup() {
72-
Timer::_countsPerSecond = Timer::microsPerSecond;
73-
}
74-
75126
#else
76-
#error "Unknown mongo::Timer implementation"
127+
AtStartup::AtStartup() { }
77128
#endif
78129

79130
} // namespace
80131

132+
long long Timer::now() const {
133+
return _timerNow();
134+
}
135+
81136
} // namespace mongo

src/mongo/util/timer.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ namespace mongo {
8585
static long long _countsPerSecond;
8686

8787
private:
88-
inline long long now() const;
88+
long long now() const;
8989

9090
long long _old;
9191
};
9292
} // namespace mongo
93-
94-
#include "mongo/util/timer-inl.h"

0 commit comments

Comments
 (0)