summaryrefslogtreecommitdiff
path: root/src/common/x64/native_clock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/x64/native_clock.cpp')
-rw-r--r--src/common/x64/native_clock.cpp103
1 files changed, 103 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..424b39b1f
--- /dev/null
+++ b/src/common/x64/native_clock.cpp
@@ -0,0 +1,103 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <chrono>
6#include <mutex>
7#include <thread>
8
9#ifdef _MSC_VER
10#include <intrin.h>
11#else
12#include <x86intrin.h>
13#endif
14
15#include "common/uint128.h"
16#include "common/x64/native_clock.h"
17
18namespace Common {
19
20u64 EstimateRDTSCFrequency() {
21 const auto milli_10 = std::chrono::milliseconds{10};
22 // get current time
23 _mm_mfence();
24 const u64 tscStart = __rdtsc();
25 const auto startTime = std::chrono::high_resolution_clock::now();
26 // wait roughly 3 seconds
27 while (true) {
28 auto milli = std::chrono::duration_cast<std::chrono::milliseconds>(
29 std::chrono::high_resolution_clock::now() - startTime);
30 if (milli.count() >= 3000)
31 break;
32 std::this_thread::sleep_for(milli_10);
33 }
34 const auto endTime = std::chrono::high_resolution_clock::now();
35 _mm_mfence();
36 const u64 tscEnd = __rdtsc();
37 // calculate difference
38 const u64 timer_diff =
39 std::chrono::duration_cast<std::chrono::nanoseconds>(endTime - startTime).count();
40 const u64 tsc_diff = tscEnd - tscStart;
41 const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
42 return tsc_freq;
43}
44
45namespace X64 {
46NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency,
47 u64 rtsc_frequency)
48 : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{
49 rtsc_frequency} {
50 _mm_mfence();
51 last_measure = __rdtsc();
52 accumulated_ticks = 0U;
53}
54
55u64 NativeClock::GetRTSC() {
56 std::scoped_lock scope{rtsc_serialize};
57 _mm_mfence();
58 const u64 current_measure = __rdtsc();
59 u64 diff = current_measure - last_measure;
60 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
61 if (current_measure > last_measure) {
62 last_measure = current_measure;
63 }
64 accumulated_ticks += diff;
65 /// The clock cannot be more precise than the guest timer, remove the lower bits
66 return accumulated_ticks & inaccuracy_mask;
67}
68
69void NativeClock::Pause(bool is_paused) {
70 if (!is_paused) {
71 _mm_mfence();
72 last_measure = __rdtsc();
73 }
74}
75
76std::chrono::nanoseconds NativeClock::GetTimeNS() {
77 const u64 rtsc_value = GetRTSC();
78 return std::chrono::nanoseconds{MultiplyAndDivide64(rtsc_value, 1000000000, rtsc_frequency)};
79}
80
81std::chrono::microseconds NativeClock::GetTimeUS() {
82 const u64 rtsc_value = GetRTSC();
83 return std::chrono::microseconds{MultiplyAndDivide64(rtsc_value, 1000000, rtsc_frequency)};
84}
85
86std::chrono::milliseconds NativeClock::GetTimeMS() {
87 const u64 rtsc_value = GetRTSC();
88 return std::chrono::milliseconds{MultiplyAndDivide64(rtsc_value, 1000, rtsc_frequency)};
89}
90
91u64 NativeClock::GetClockCycles() {
92 const u64 rtsc_value = GetRTSC();
93 return MultiplyAndDivide64(rtsc_value, emulated_clock_frequency, rtsc_frequency);
94}
95
96u64 NativeClock::GetCPUCycles() {
97 const u64 rtsc_value = GetRTSC();
98 return MultiplyAndDivide64(rtsc_value, emulated_cpu_frequency, rtsc_frequency);
99}
100
101} // namespace X64
102
103} // namespace Common