summaryrefslogtreecommitdiffstats
path: root/src/common/x64/native_clock.cpp
diff options
context:
space:
mode:
authorFernando Sahmkow <fsahmkow27@gmail.com>2020-02-09 21:53:22 +0100
committerFernando Sahmkow <fsahmkow27@gmail.com>2020-06-18 22:29:17 +0200
commit234b5ff6a999d7d69cdcdf214e0c3984cdab11cf (patch)
tree4f0ef41d7738b53d1b81ac2f7072bec1ba5fe8f1 /src/common/x64/native_clock.cpp
parentTests: Add base tests to host timing (diff)
downloadyuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.tar
yuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.tar.gz
yuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.tar.bz2
yuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.tar.lz
yuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.tar.xz
yuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.tar.zst
yuzu-234b5ff6a999d7d69cdcdf214e0c3984cdab11cf.zip
Diffstat (limited to 'src/common/x64/native_clock.cpp')
-rw-r--r--src/common/x64/native_clock.cpp128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
new file mode 100644
index 000000000..c799111fd
--- /dev/null
+++ b/src/common/x64/native_clock.cpp
@@ -0,0 +1,128 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <chrono>
+#include <thread>
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
+#include <x86intrin.h>
+#endif
+
+#include "common/x64/native_clock.h"
+
+namespace Common {
+
+#ifdef _MSC_VER
+
+namespace {
+
+struct uint128 {
+ u64 low;
+ u64 high;
+};
+
+u64 umuldiv64(u64 a, u64 b, u64 d) {
+ uint128 r{};
+ r.low = _umul128(a, b, &r.high);
+ u64 remainder;
+ return _udiv128(r.high, r.low, d, &remainder);
+}
+
+} // namespace
+
+#else
+
+namespace {
+
+u64 umuldiv64(u64 a, u64 b, u64 d) {
+ const u64 diva = a / d;
+ const u64 moda = a % d;
+ const u64 divb = b / d;
+ const u64 modb = b % d;
+ return diva * b + moda * divb + moda * modb / d;
+}
+
+} // namespace
+
+#endif
+
+u64 EstimateRDTSCFrequency() {
+ const auto milli_10 = std::chrono::milliseconds{10};
+ // get current time
+ _mm_mfence();
+ const u64 tscStart = __rdtsc();
+ const auto startTime = std::chrono::high_resolution_clock::now();
+ // wait roughly 3 seconds
+ while (true) {
+ auto milli = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::high_resolution_clock::now() - startTime);
+ if (milli.count() >= 3000)
+ break;
+ std::this_thread::sleep_for(milli_10);
+ }
+ const auto endTime = std::chrono::high_resolution_clock::now();
+ _mm_mfence();
+ const u64 tscEnd = __rdtsc();
+ // calculate difference
+ const u64 timer_diff =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(endTime - startTime).count();
+ const u64 tsc_diff = tscEnd - tscStart;
+ const u64 tsc_freq = umuldiv64(tsc_diff, 1000000000ULL, timer_diff);
+ return tsc_freq;
+}
+
+namespace X64 {
+NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency,
+ u64 rtsc_frequency)
+ : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{
+ rtsc_frequency} {
+ _mm_mfence();
+ last_measure = __rdtsc();
+ accumulated_ticks = 0U;
+}
+
+u64 NativeClock::GetRTSC() {
+ rtsc_serialize.lock();
+ _mm_mfence();
+ const u64 current_measure = __rdtsc();
+ u64 diff = current_measure - last_measure;
+ diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
+ if (current_measure > last_measure) {
+ last_measure = current_measure;
+ }
+ accumulated_ticks += diff;
+ rtsc_serialize.unlock();
+ return accumulated_ticks;
+}
+
+std::chrono::nanoseconds NativeClock::GetTimeNS() {
+ const u64 rtsc_value = GetRTSC();
+ return std::chrono::nanoseconds{umuldiv64(rtsc_value, 1000000000, rtsc_frequency)};
+}
+
+std::chrono::microseconds NativeClock::GetTimeUS() {
+ const u64 rtsc_value = GetRTSC();
+ return std::chrono::microseconds{umuldiv64(rtsc_value, 1000000, rtsc_frequency)};
+}
+
+std::chrono::milliseconds NativeClock::GetTimeMS() {
+ const u64 rtsc_value = GetRTSC();
+ return std::chrono::milliseconds{umuldiv64(rtsc_value, 1000, rtsc_frequency)};
+}
+
+u64 NativeClock::GetClockCycles() {
+ const u64 rtsc_value = GetRTSC();
+ return umuldiv64(rtsc_value, emulated_clock_frequency, rtsc_frequency);
+}
+
+u64 NativeClock::GetCPUCycles() {
+ const u64 rtsc_value = GetRTSC();
+ return umuldiv64(rtsc_value, emulated_cpu_frequency, rtsc_frequency);
+}
+
+} // namespace X64
+
+} // namespace Common