diff options
author | Jan Niklas Hasse <jhasse@bixense.com> | 2024-04-11 16:44:05 (GMT) |
---|---|---|
committer | Jan Niklas Hasse <jhasse@bixense.com> | 2024-04-11 16:44:05 (GMT) |
commit | 65d0dfcbbea6b8ca7d8a3a0f673ecb522379e43c (patch) | |
tree | 7b30fc5f0a477efd075ab0f8eead78aa7554869b /src/metrics.cc | |
parent | 448ae1ccacd17025457ace965d78a45a113c70c6 (diff) | |
parent | 1dcebc6399dc76a9bdf643ad9722d7f2d7fee51c (diff) | |
download | Ninja-1.12.0.zip Ninja-1.12.0.tar.gz Ninja-1.12.0.tar.bz2 |
v1.12.0v1.12.0
Diffstat (limited to 'src/metrics.cc')
-rw-r--r-- | src/metrics.cc | 77 |
1 files changed, 35 insertions, 42 deletions
diff --git a/src/metrics.cc b/src/metrics.cc index dbaf221..632ae43 100644 --- a/src/metrics.cc +++ b/src/metrics.cc @@ -18,13 +18,8 @@ #include <stdio.h> #include <string.h> -#ifndef _WIN32 -#include <sys/time.h> -#else -#include <windows.h> -#endif - #include <algorithm> +#include <chrono> #include "util.h" @@ -34,49 +29,40 @@ Metrics* g_metrics = NULL; namespace { -#ifndef _WIN32 /// Compute a platform-specific high-res timer value that fits into an int64. int64_t HighResTimer() { - timeval tv; - if (gettimeofday(&tv, NULL) < 0) - Fatal("gettimeofday: %s", strerror(errno)); - return (int64_t)tv.tv_sec * 1000*1000 + tv.tv_usec; + auto now = chrono::steady_clock::now(); + return chrono::duration_cast<chrono::steady_clock::duration>( + now.time_since_epoch()) + .count(); } -/// Convert a delta of HighResTimer() values to microseconds. -int64_t TimerToMicros(int64_t dt) { - // No conversion necessary. - return dt; -} -#else -int64_t LargeIntegerToInt64(const LARGE_INTEGER& i) { - return ((int64_t)i.HighPart) << 32 | i.LowPart; -} - -int64_t HighResTimer() { - LARGE_INTEGER counter; - if (!QueryPerformanceCounter(&counter)) - Fatal("QueryPerformanceCounter: %s", GetLastErrorString().c_str()); - return LargeIntegerToInt64(counter); +constexpr int64_t GetFrequency() { + // If numerator isn't 1 then we lose precision and that will need to be + // assessed. + static_assert(std::chrono::steady_clock::period::num == 1, + "Numerator must be 1"); + return std::chrono::steady_clock::period::den / + std::chrono::steady_clock::period::num; } int64_t TimerToMicros(int64_t dt) { - static int64_t ticks_per_sec = 0; - if (!ticks_per_sec) { - LARGE_INTEGER freq; - if (!QueryPerformanceFrequency(&freq)) - Fatal("QueryPerformanceFrequency: %s", GetLastErrorString().c_str()); - ticks_per_sec = LargeIntegerToInt64(freq); - } + // dt is in ticks. We want microseconds. + return chrono::duration_cast<chrono::microseconds>( + std::chrono::steady_clock::duration{ dt }) + .count(); +} +int64_t TimerToMicros(double dt) { // dt is in ticks. We want microseconds. - return (dt * 1000000) / ticks_per_sec; + using DoubleSteadyClock = + std::chrono::duration<double, std::chrono::steady_clock::period>; + return chrono::duration_cast<chrono::microseconds>(DoubleSteadyClock{ dt }) + .count(); } -#endif } // anonymous namespace - ScopedMetric::ScopedMetric(Metric* metric) { metric_ = metric; if (!metric_) @@ -87,7 +73,9 @@ ScopedMetric::~ScopedMetric() { if (!metric_) return; metric_->count++; - int64_t dt = TimerToMicros(HighResTimer() - start_); + // Leave in the timer's natural frequency to avoid paying the conversion cost + // on every measurement. + int64_t dt = HighResTimer() - start_; metric_->sum += dt; } @@ -112,18 +100,23 @@ void Metrics::Report() { for (vector<Metric*>::iterator i = metrics_.begin(); i != metrics_.end(); ++i) { Metric* metric = *i; - double total = metric->sum / (double)1000; - double avg = metric->sum / (double)metric->count; + uint64_t micros = TimerToMicros(metric->sum); + double total = micros / (double)1000; + double avg = micros / (double)metric->count; printf("%-*s\t%-6d\t%-8.1f\t%.1f\n", width, metric->name.c_str(), metric->count, avg, total); } } -uint64_t Stopwatch::Now() const { - return TimerToMicros(HighResTimer()); +double Stopwatch::Elapsed() const { + // Convert to micros after converting to double to minimize error. + return 1e-6 * TimerToMicros(static_cast<double>(NowRaw() - started_)); +} + +uint64_t Stopwatch::NowRaw() const { + return HighResTimer(); } int64_t GetTimeMillis() { return TimerToMicros(HighResTimer()) / 1000; } - |