diff --git a/SConstruct b/SConstruct index 091650b3420..e13aa882360 100644 --- a/SConstruct +++ b/SConstruct @@ -1343,6 +1343,32 @@ def doConfigure(myenv): posix_system = conf.CheckPosixSystem() conf.Finish() + # Check if we are on a system that support the POSIX clock_gettime function + # and the "monotonic" clock. + posix_monotonic_clock = False + if posix_system: + def CheckPosixMonotonicClock(context): + + test_body = """ + #include + #if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) + #error POSIX clock_gettime not supported + #elif !(defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) + #error POSIX monotonic clock not supported + #endif + """ + + context.Message('Checking if the POSIX monotonic clock is supported... ') + ret = context.TryCompile(textwrap.dedent(test_body), ".c") + context.Result(ret) + return ret + + conf = Configure(myenv, help=False, custom_tests = { + 'CheckPosixMonotonicClock' : CheckPosixMonotonicClock, + }) + posix_monotonic_clock = conf.CheckPosixMonotonicClock() + conf.Finish() + if has_option('sanitize'): if not (using_clang() or using_gcc()): @@ -1615,6 +1641,9 @@ def doConfigure(myenv): conf.CheckLib('rt') conf.CheckLib('dl') + if posix_monotonic_clock: + conf.env.Append(CPPDEFINES=['MONGO_HAVE_POSIX_MONOTONIC_CLOCK']) + if (conf.CheckCXXHeader( "execinfo.h" ) and conf.CheckDeclaration('backtrace', includes='#include ') and conf.CheckDeclaration('backtrace_symbols', includes='#include ') and diff --git a/src/mongo/util/timer-generic-inl.h b/src/mongo/util/timer-generic-inl.h deleted file mode 100644 index c0b07c563d7..00000000000 --- a/src/mongo/util/timer-generic-inl.h +++ /dev/null @@ -1,49 +0,0 @@ -// @file mongo/util/timer-generic-inl.h - -/* Copyright 2010 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -/** - * Inline function implementations for the "generic" implementation of the - * Timer class. This implementation often has pretty poor resolution, but is available - * on all supported platforms. - * - * This file should only be included through timer-inl.h, which selects the - * particular implementation based on target platform. - */ - -#pragma once - -#define MONGO_TIMER_IMPL_GENERIC - -#include "mongo/util/time_support.h" - -namespace mongo { - - long long Timer::now() const { return curTimeMicros64(); } - -} // namespace mongo diff --git a/src/mongo/util/timer-inl.h b/src/mongo/util/timer-inl.h deleted file mode 100644 index d4e037e2e96..00000000000 --- a/src/mongo/util/timer-inl.h +++ /dev/null @@ -1,60 +0,0 @@ -// @file mongo/util/timer-inl.h - -/* Copyright 2010 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -/** - * Inline function implementations for the Timer class. This file simply selects - * the platform-appropriate inline functions to include. - * - * This file should only be included through timer-inl.h, which selects the - * particular implementation based on target platform. - */ - -#pragma once - -#if defined(MONGO_HAVE_HEADER_UNISTD_H) -#include -#endif - -#if defined(_WIN32) - -// On Windows, prefer the Windows-specific implementation, which employs QueryPerformanceCounter. -#include "mongo/util/timer-win32-inl.h" - -#elif defined(_POSIX_TIMERS) and _POSIX_TIMERS > 0 and defined(_POSIX_MONOTONIC_CLOCK) and _POSIX_MONOTONIC_CLOCK > 0 - -// On systems that support the POSIX clock_gettime function, and the "monotonic" clock, -// use those. -#include "mongo/util/timer-posixclock-inl.h" - -#else - -// If all else fails, fall back to a generic implementation. Performance may suffer. -#include "mongo/util/timer-generic-inl.h" - -#endif diff --git a/src/mongo/util/timer-posixclock-inl.h b/src/mongo/util/timer-posixclock-inl.h deleted file mode 100644 index a171c25ab0d..00000000000 --- a/src/mongo/util/timer-posixclock-inl.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2010 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -/** - * Inline function implementations for timers on systems that support the - * POSIX clock API and CLOCK_MONOTONIC clock. - * - * This file should only be included through timer-inl.h, which selects the - * particular implementation based on target platform. - */ - -#define MONGO_TIMER_IMPL_POSIX_MONOTONIC_CLOCK - -#include - -#include "mongo/util/assert_util.h" - -namespace mongo { - - long long Timer::now() const { - 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(the_time.tv_sec); - result *= nanosPerSecond; - result += static_cast(the_time.tv_nsec); - return result; - } - -} // namespace mongo diff --git a/src/mongo/util/timer-win32-inl.h b/src/mongo/util/timer-win32-inl.h deleted file mode 100644 index dedf77ca385..00000000000 --- a/src/mongo/util/timer-win32-inl.h +++ /dev/null @@ -1,54 +0,0 @@ -// @file mongo/util/timer-win32-inl.h - -/* Copyright 2010 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -/** - * Inline function implementations for the 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. - * - * Do not include directly. Include "mongo/util/timer.h". - */ - -#pragma once - -#define MONGO_TIMER_IMPL_WIN32 - -#include "mongo/platform/windows_basic.h" -#include "mongo/util/assert_util.h" - -namespace mongo { - - long long Timer::now() const { - LARGE_INTEGER i; - fassert(16161, QueryPerformanceCounter(&i)); - return i.QuadPart; - } - -} // namespace mongo 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 #include +#if defined(MONGO_HAVE_HEADER_UNISTD_H) +#include +#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(the_time.tv_sec); + result *= Timer::nanosPerSecond; + result += static_cast(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(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 diff --git a/src/mongo/util/timer.h b/src/mongo/util/timer.h index 0d5a5e97ebc..b28db52d703 100644 --- a/src/mongo/util/timer.h +++ b/src/mongo/util/timer.h @@ -85,10 +85,8 @@ namespace mongo { static long long _countsPerSecond; private: - inline long long now() const; + long long now() const; long long _old; }; } // namespace mongo - -#include "mongo/util/timer-inl.h"