summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Source/Core/Common/Timer.cpp34
-rw-r--r--Source/Core/Common/Timer.h15
-rw-r--r--Source/Core/Core/HW/CPU.cpp4
3 files changed, 51 insertions, 2 deletions
diff --git a/Source/Core/Common/Timer.cpp b/Source/Core/Common/Timer.cpp
index 0a23080c6f..0e260b833c 100644
--- a/Source/Core/Common/Timer.cpp
+++ b/Source/Core/Common/Timer.cpp
@@ -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
diff --git a/Source/Core/Common/Timer.h b/Source/Core/Common/Timer.h
index d49a599015..3f5a51ad7f 100644
--- a/Source/Core/Common/Timer.h
+++ b/Source/Core/Common/Timer.h
@@ -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
diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp
index 568e3b3894..82b0cb9c4b 100644
--- a/Source/Core/Core/HW/CPU.cpp
+++ b/Source/Core/Core/HW/CPU.cpp
@@ -72,8 +72,8 @@ void CPUManager::StartTimePlayedTimer()
{
Common::SetCurrentThreadName("Play Time Tracker");
- // Steady clock for greater accuracy of timing
- std::chrono::steady_clock timer;
+ // Use a clock that will appropriately ignore suspended system time.
+ Common::SteadyAwakeClock timer;
auto prev_time = timer.now();
while (true)