summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/benchmark/src/walltime.cc
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/benchmark/src/walltime.cc')
-rw-r--r--3rdparty/benchmark/src/walltime.cc263
1 files changed, 263 insertions, 0 deletions
diff --git a/3rdparty/benchmark/src/walltime.cc b/3rdparty/benchmark/src/walltime.cc
new file mode 100644
index 00000000000..4bdbaa59859
--- /dev/null
+++ b/3rdparty/benchmark/src/walltime.cc
@@ -0,0 +1,263 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "benchmark/macros.h"
+#include "internal_macros.h"
+#include "walltime.h"
+
+#if defined(BENCHMARK_OS_WINDOWS)
+#include <time.h>
+#include <winsock.h> // for timeval
+#else
+#include <sys/time.h>
+#endif
+
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+
+#include <atomic>
+#include <chrono>
+#include <limits>
+
+#include "arraysize.h"
+#include "check.h"
+#include "cycleclock.h"
+#include "log.h"
+#include "sysinfo.h"
+
+namespace benchmark {
+namespace walltime {
+
+namespace {
+
+#if defined(HAVE_STEADY_CLOCK)
+template <bool HighResIsSteady = std::chrono::high_resolution_clock::is_steady>
+struct ChooseSteadyClock {
+ typedef std::chrono::high_resolution_clock type;
+};
+
+template <>
+struct ChooseSteadyClock<false> {
+ typedef std::chrono::steady_clock type;
+};
+#endif
+
+struct ChooseClockType {
+#if defined(HAVE_STEADY_CLOCK)
+ typedef ChooseSteadyClock<>::type type;
+#else
+ typedef std::chrono::high_resolution_clock type;
+#endif
+};
+
+class WallTimeImp
+{
+public:
+ WallTime Now();
+
+ static WallTimeImp& GetWallTimeImp() {
+ static WallTimeImp* imp = new WallTimeImp();
+ return *imp;
+ }
+
+private:
+ WallTimeImp();
+ // Helper routines to load/store a float from an AtomicWord. Required because
+ // g++ < 4.7 doesn't support std::atomic<float> correctly. I cannot wait to
+ // get rid of this horror show.
+ void SetDrift(float f) {
+ int32_t w;
+ memcpy(&w, &f, sizeof(f));
+ std::atomic_store(&drift_adjust_, w);
+ }
+
+ float GetDrift() const {
+ float f;
+ int32_t w = std::atomic_load(&drift_adjust_);
+ memcpy(&f, &w, sizeof(f));
+ return f;
+ }
+
+ WallTime Slow() const {
+ struct timeval tv;
+#if defined(BENCHMARK_OS_WINDOWS)
+ FILETIME file_time;
+ SYSTEMTIME system_time;
+ ULARGE_INTEGER ularge;
+ const unsigned __int64 epoch = 116444736000000000LL;
+
+ GetSystemTime(&system_time);
+ SystemTimeToFileTime(&system_time, &file_time);
+ ularge.LowPart = file_time.dwLowDateTime;
+ ularge.HighPart = file_time.dwHighDateTime;
+
+ tv.tv_sec = (long)((ularge.QuadPart - epoch) / (10L * 1000 * 1000));
+ tv.tv_usec = (long)(system_time.wMilliseconds * 1000);
+#else
+ gettimeofday(&tv, nullptr);
+#endif
+ return tv.tv_sec + tv.tv_usec * 1e-6;
+ }
+
+private:
+ static_assert(sizeof(float) <= sizeof(int32_t),
+ "type sizes don't allow the drift_adjust hack");
+
+ WallTime base_walltime_;
+ int64_t base_cycletime_;
+ int64_t cycles_per_second_;
+ double seconds_per_cycle_;
+ uint32_t last_adjust_time_;
+ std::atomic<int32_t> drift_adjust_;
+ int64_t max_interval_cycles_;
+
+ BENCHMARK_DISALLOW_COPY_AND_ASSIGN(WallTimeImp);
+};
+
+
+WallTime WallTimeImp::Now() {
+ WallTime now = 0.0;
+ WallTime result = 0.0;
+ int64_t ct = 0;
+ uint32_t top_bits = 0;
+ do {
+ ct = cycleclock::Now();
+ int64_t cycle_delta = ct - base_cycletime_;
+ result = base_walltime_ + cycle_delta * seconds_per_cycle_;
+
+ top_bits = static_cast<uint32_t>(uint64_t(ct) >> 32);
+ // Recompute drift no more often than every 2^32 cycles.
+ // I.e., @2GHz, ~ every two seconds
+ if (top_bits == last_adjust_time_) { // don't need to recompute drift
+ return result + GetDrift();
+ }
+
+ now = Slow();
+ } while (cycleclock::Now() - ct > max_interval_cycles_);
+ // We are now sure that "now" and "result" were produced within
+ // kMaxErrorInterval of one another.
+
+ SetDrift(static_cast<float>(now - result));
+ last_adjust_time_ = top_bits;
+ return now;
+}
+
+
+WallTimeImp::WallTimeImp()
+ : base_walltime_(0.0), base_cycletime_(0),
+ cycles_per_second_(0), seconds_per_cycle_(0.0),
+ last_adjust_time_(0), drift_adjust_(0),
+ max_interval_cycles_(0) {
+ const double kMaxErrorInterval = 100e-6;
+ cycles_per_second_ = static_cast<int64_t>(CyclesPerSecond());
+ CHECK(cycles_per_second_ != 0);
+ seconds_per_cycle_ = 1.0 / cycles_per_second_;
+ max_interval_cycles_ =
+ static_cast<int64_t>(cycles_per_second_ * kMaxErrorInterval);
+ do {
+ base_cycletime_ = cycleclock::Now();
+ base_walltime_ = Slow();
+ } while (cycleclock::Now() - base_cycletime_ > max_interval_cycles_);
+ // We are now sure that "base_walltime" and "base_cycletime" were produced
+ // within kMaxErrorInterval of one another.
+
+ SetDrift(0.0);
+ last_adjust_time_ = static_cast<uint32_t>(uint64_t(base_cycletime_) >> 32);
+}
+
+WallTime CPUWalltimeNow() {
+ static WallTimeImp& imp = WallTimeImp::GetWallTimeImp();
+ return imp.Now();
+}
+
+WallTime ChronoWalltimeNow() {
+ typedef ChooseClockType::type Clock;
+ typedef std::chrono::duration<WallTime, std::chrono::seconds::period>
+ FPSeconds;
+ static_assert(std::chrono::treat_as_floating_point<WallTime>::value,
+ "This type must be treated as a floating point type.");
+ auto now = Clock::now().time_since_epoch();
+ return std::chrono::duration_cast<FPSeconds>(now).count();
+}
+
+bool UseCpuCycleClock() {
+ bool useWallTime = !CpuScalingEnabled();
+ if (useWallTime) {
+ VLOG(1) << "Using the CPU cycle clock to provide walltime::Now().\n";
+ } else {
+ VLOG(1) << "Using std::chrono to provide walltime::Now().\n";
+ }
+ return useWallTime;
+}
+
+
+} // end anonymous namespace
+
+// WallTimeImp doesn't work when CPU Scaling is enabled. If CPU Scaling is
+// enabled at the start of the program then std::chrono::system_clock is used
+// instead.
+WallTime Now()
+{
+ static bool useCPUClock = UseCpuCycleClock();
+ if (useCPUClock) {
+ return CPUWalltimeNow();
+ } else {
+ return ChronoWalltimeNow();
+ }
+}
+
+} // end namespace walltime
+
+
+namespace {
+
+std::string DateTimeString(bool local) {
+ typedef std::chrono::system_clock Clock;
+ std::time_t now = Clock::to_time_t(Clock::now());
+ char storage[128];
+ std::size_t written;
+
+ if (local) {
+#if defined(BENCHMARK_OS_WINDOWS)
+ written = std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now));
+#else
+ std::tm timeinfo;
+ std::memset(&timeinfo, 0, sizeof(std::tm));
+ ::localtime_r(&now, &timeinfo);
+ written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
+#endif
+ } else {
+#if defined(BENCHMARK_OS_WINDOWS)
+ written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now));
+#else
+ std::tm timeinfo;
+ std::memset(&timeinfo, 0, sizeof(std::tm));
+ ::gmtime_r(&now, &timeinfo);
+ written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
+#endif
+ }
+ CHECK(written < arraysize(storage));
+ ((void)written); // prevent unused variable in optimized mode.
+ return std::string(storage);
+}
+
+} // end namespace
+
+std::string LocalDateTimeString() {
+ return DateTimeString(true);
+}
+
+} // end namespace benchmark