Common/Timer: Add a SteadyAwakeClock class which counts non-suspended system running time.

This commit is contained in:
Jordan Woyak 2025-07-23 23:51:45 -05:00
commit 62c773ac75
2 changed files with 49 additions and 0 deletions

View file

@ -5,6 +5,7 @@
#include <chrono>
#include <thread>
#include "Common/CommonFuncs.h"
#ifdef _WIN32
#include <Windows.h>
@ -194,4 +195,37 @@ void PrecisionTimer::SleepUntil(Clock::time_point target)
}
}
// Results are appropriately slewed on Linux, but not on Windows, macOS, or FreeBSD.
// Clocks with that functionality seem to not be available there.
auto SteadyAwakeClock::now() -> time_point
{
#if defined(_WIN32)
// The count is system time "in units of 100 nanoseconds".
using InterruptDuration = std::chrono::duration<ULONGLONG, std::ratio<100, std::nano::den>::type>;
ULONGLONG interrupt_time{};
if (!QueryUnbiasedInterruptTime(&interrupt_time))
ERROR_LOG_FMT(COMMON, "QueryUnbiasedInterruptTime");
return time_point{InterruptDuration{interrupt_time}};
#else
// Note that Linux's CLOCK_MONOTONIC "does not count time that the system is suspended".
// This is in contrast to the behavior on macOS and FreeBSD.
static constexpr auto clock_id =
#if defined(__linux__)
CLOCK_MONOTONIC;
#elif defined(__APPLE__)
CLOCK_UPTIME_RAW;
#else
CLOCK_UPTIME;
#endif
timespec ts{};
if (clock_gettime(clock_id, &ts) != 0)
ERROR_LOG_FMT(COMMON, "clock_gettime: {}", LastStrerrorString());
return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
#endif
}
} // Namespace Common

View file

@ -50,4 +50,19 @@ private:
#endif
};
// Similar to std::chrono::steady_clock except this clock
// specifically does *not* count time while the system is suspended.
class SteadyAwakeClock
{
public:
using rep = s64;
using period = std::nano;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<SteadyAwakeClock>;
static constexpr bool is_steady = true;
static time_point now();
};
} // Namespace Common