From 52f5ca7e286099cc8e72518baf4b7dfcf50b6be5 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 26 Jan 2021 02:20:38 +1000 Subject: [PATCH] Common/Timer: Add additional sleep functions --- src/common/timer.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++- src/common/timer.h | 9 +++- 2 files changed, 130 insertions(+), 3 deletions(-) diff --git a/src/common/timer.cpp b/src/common/timer.cpp index 84589eaf8..fd668492c 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -1,10 +1,13 @@ #include "timer.h" +#include +#include #ifdef WIN32 #include "windows_headers.h" #else #include #include +#include #endif namespace Common { @@ -45,6 +48,21 @@ double Timer::ConvertValueToSeconds(Timer::Value value) return ((static_cast(value) / s_counter_frequency) / 1000000000.0); } +Timer::Value Timer::ConvertSecondsToValue(double s) +{ + return static_cast((s * 1000000000.0) * s_counter_frequency); +} + +Timer::Value Timer::ConvertMillisecondsToValue(double ms) +{ + return static_cast((ms * 1000000.0) * s_counter_frequency); +} + +Timer::Value Timer::ConvertNanosecondsToValue(double ns) +{ + return static_cast(ns * s_counter_frequency); +} + #else #if 1 // using clock_gettime() @@ -71,6 +89,21 @@ double Timer::ConvertValueToSeconds(Timer::Value value) return (static_cast(value) / 1000000000.0); } +Timer::Value Timer::ConvertSecondsToValue(double s) +{ + return static_cast(s * 1000000000.0); +} + +Timer::Value Timer::ConvertMillisecondsToValue(double ms) +{ + return static_cast(ms * 1000000.0); +} + +Timer::Value Timer::ConvertNanosecondsToValue(double ns) +{ + return static_cast(ns); +} + #else // using gettimeofday() Timer::Value Timer::GetValue() @@ -95,6 +128,21 @@ double Timer::ConvertValueToSeconds(Timer::Value value) return ((double)value / 1000000.0); } +Timer::Value Timer::ConvertSecondsToValue(double s) +{ + return static_cast(ms * 1000000.0); +} + +Timer::Value Timer::ConvertMillisecondsToValue(double ms) +{ + return static_cast(ms * 1000.0); +} + +Timer::Value Timer::ConvertNanosecondsToValue(double ns) +{ + return static_cast(ns / 1000.0); +} + #endif #endif @@ -124,4 +172,78 @@ double Timer::GetTimeNanoseconds() const return ConvertValueToNanoseconds(GetValue() - m_tvStartValue); } -} // namespace Common \ No newline at end of file +void Timer::BusyWait(std::uint64_t ns) +{ + const Value start = GetValue(); + const Value end = start + ConvertNanosecondsToValue(static_cast(ns)); + if (end < start) + { + // overflow, unlikely + while (GetValue() > end) + ; + } + + while (GetValue() < end) + ; +} + +void Timer::HybridSleep(std::uint64_t ns, std::uint64_t min_sleep_time) +{ + const std::uint64_t start = GetValue(); + const std::uint64_t end = start + ConvertNanosecondsToValue(static_cast(ns)); + if (end < start) + { + // overflow, unlikely + while (GetValue() > end) + ; + } + + std::uint64_t current = GetValue(); + while (current < end) + { + const std::uint64_t remaining = end - current; + if (remaining >= min_sleep_time) + NanoSleep(min_sleep_time); + + current = GetValue(); + } +} + +void Timer::NanoSleep(std::uint64_t ns) +{ +#if defined(WIN32) + static HANDLE throttle_timer; + static bool throttle_timer_created = false; + if (!throttle_timer_created) + { + throttle_timer_created = true; + throttle_timer = CreateWaitableTimer(nullptr, TRUE, nullptr); + if (throttle_timer) + std::atexit([]() { CloseHandle(throttle_timer); }); + else + std::fprintf(stderr, "CreateWaitableTimer() failed, falling back to Sleep()\n"); + } + + if (throttle_timer) + { + LARGE_INTEGER due_time; + due_time.QuadPart = -static_cast(static_cast(ns) / 100u); + if (SetWaitableTimer(throttle_timer, &due_time, 0, nullptr, nullptr, FALSE)) + WaitForSingleObject(throttle_timer, INFINITE); + else + std::fprintf(stderr, "SetWaitableTimer() failed: %08X\n", GetLastError()); + } + else + { + Sleep(static_cast(ns / 1000000)); + } +#elif defined(__ANDROID__) + // Round down to the next millisecond. + usleep(static_cast((ns / 1000000) * 1000)); +#else + const struct timespec ts = {0, static_cast(ns)}; + nanosleep(&ts, nullptr); +#endif +} + +} // namespace Common diff --git a/src/common/timer.h b/src/common/timer.h index 5d105d868..3afa1e2ce 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -1,5 +1,4 @@ #pragma once -#include "types.h" #include namespace Common { @@ -7,7 +6,7 @@ namespace Common { class Timer { public: - using Value = u64; + using Value = std::uint64_t; Timer(); @@ -15,6 +14,12 @@ public: static double ConvertValueToSeconds(Value value); static double ConvertValueToMilliseconds(Value value); static double ConvertValueToNanoseconds(Value value); + static Value ConvertSecondsToValue(double s); + static Value ConvertMillisecondsToValue(double s); + static Value ConvertNanosecondsToValue(double ns); + static void BusyWait(std::uint64_t ns); + static void HybridSleep(std::uint64_t ns, std::uint64_t min_sleep_time = UINT64_C(2000000)); + static void NanoSleep(std::uint64_t ns); void Reset();