summaryrefslogtreecommitdiff
path: root/src/common/x64
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2021-01-02 02:24:49 +0100
committerGravatar Fernando Sahmkow2021-01-02 04:00:27 +0100
commit53d92318b82cd4a9e08f814fcb8aab624d795c6c (patch)
tree4f5236ffebdcf947297d8ace42151b36810f3144 /src/common/x64
parentX86/NativeClock: Improve performance of clock calculations on hot path. (diff)
downloadyuzu-53d92318b82cd4a9e08f814fcb8aab624d795c6c.tar.gz
yuzu-53d92318b82cd4a9e08f814fcb8aab624d795c6c.tar.xz
yuzu-53d92318b82cd4a9e08f814fcb8aab624d795c6c.zip
X86/NativeClock: Reimplement RTDSC access to be lock free.
Diffstat (limited to 'src/common/x64')
-rw-r--r--src/common/x64/native_clock.cpp41
-rw-r--r--src/common/x64/native_clock.h22
2 files changed, 41 insertions, 22 deletions
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index e246432d0..a65f6b832 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -17,6 +17,7 @@
17#include <x86intrin.h> 17#include <x86intrin.h>
18#endif 18#endif
19 19
20#include "common/atomic_ops.h"
20#include "common/uint128.h" 21#include "common/uint128.h"
21#include "common/x64/native_clock.h" 22#include "common/x64/native_clock.h"
22 23
@@ -102,8 +103,8 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
102 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ 103 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
103 rtsc_frequency_} { 104 rtsc_frequency_} {
104 _mm_mfence(); 105 _mm_mfence();
105 last_measure = __rdtsc(); 106 time_point.inner.last_measure = __rdtsc();
106 accumulated_ticks = 0U; 107 time_point.inner.accumulated_ticks = 0U;
107 ns_rtsc_factor = GetFixedPoint64Factor(1000000000, rtsc_frequency); 108 ns_rtsc_factor = GetFixedPoint64Factor(1000000000, rtsc_frequency);
108 us_rtsc_factor = GetFixedPoint64Factor(1000000, rtsc_frequency); 109 us_rtsc_factor = GetFixedPoint64Factor(1000000, rtsc_frequency);
109 ms_rtsc_factor = GetFixedPoint64Factor(1000, rtsc_frequency); 110 ms_rtsc_factor = GetFixedPoint64Factor(1000, rtsc_frequency);
@@ -112,23 +113,35 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
112} 113}
113 114
114u64 NativeClock::GetRTSC() { 115u64 NativeClock::GetRTSC() {
115 std::scoped_lock scope{rtsc_serialize}; 116 TimePoint new_time_point{};
116 _mm_mfence(); 117 TimePoint current_time_point{};
117 const u64 current_measure = __rdtsc(); 118 do {
118 u64 diff = current_measure - last_measure; 119 current_time_point.pack = time_point.pack;
119 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) 120 _mm_mfence();
120 if (current_measure > last_measure) { 121 const u64 current_measure = __rdtsc();
121 last_measure = current_measure; 122 u64 diff = current_measure - current_time_point.inner.last_measure;
122 } 123 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
123 accumulated_ticks += diff; 124 new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure
125 ? current_measure
126 : current_time_point.inner.last_measure;
127 new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff;
128 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
129 current_time_point.pack));
124 /// The clock cannot be more precise than the guest timer, remove the lower bits 130 /// The clock cannot be more precise than the guest timer, remove the lower bits
125 return accumulated_ticks & inaccuracy_mask; 131 return new_time_point.inner.accumulated_ticks & inaccuracy_mask;
126} 132}
127 133
128void NativeClock::Pause(bool is_paused) { 134void NativeClock::Pause(bool is_paused) {
129 if (!is_paused) { 135 if (!is_paused) {
130 _mm_mfence(); 136 TimePoint current_time_point{};
131 last_measure = __rdtsc(); 137 TimePoint new_time_point{};
138 do {
139 current_time_point.pack = time_point.pack;
140 new_time_point.pack = current_time_point.pack;
141 _mm_mfence();
142 new_time_point.inner.last_measure = __rdtsc();
143 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
144 current_time_point.pack));
132 } 145 }
133} 146}
134 147
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index a7b1ee9e0..7cbd400d2 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -6,7 +6,6 @@
6 6
7#include <optional> 7#include <optional>
8 8
9#include "common/spin_lock.h"
10#include "common/wall_clock.h" 9#include "common/wall_clock.h"
11 10
12namespace Common { 11namespace Common {
@@ -32,22 +31,29 @@ public:
32private: 31private:
33 u64 GetRTSC(); 32 u64 GetRTSC();
34 33
34 union alignas(16) TimePoint {
35 TimePoint() : pack{} {}
36 u128 pack{};
37 struct Inner {
38 u64 last_measure{};
39 u64 accumulated_ticks{};
40 } inner;
41 };
42
35 /// value used to reduce the native clocks accuracy as some apss rely on 43 /// value used to reduce the native clocks accuracy as some apss rely on
36 /// undefined behavior where the level of accuracy in the clock shouldn't 44 /// undefined behavior where the level of accuracy in the clock shouldn't
37 /// be higher. 45 /// be higher.
38 static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1); 46 static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1);
39 47
40 SpinLock rtsc_serialize{}; 48 TimePoint time_point;
41 u64 last_measure{};
42 u64 accumulated_ticks{};
43 u64 rtsc_frequency;
44
45 // factors 49 // factors
50 u64 clock_rtsc_factor{};
51 u64 cpu_rtsc_factor{};
46 u64 ns_rtsc_factor{}; 52 u64 ns_rtsc_factor{};
47 u64 us_rtsc_factor{}; 53 u64 us_rtsc_factor{};
48 u64 ms_rtsc_factor{}; 54 u64 ms_rtsc_factor{};
49 u64 clock_rtsc_factor{}; 55
50 u64 cpu_rtsc_factor{}; 56 u64 rtsc_frequency;
51}; 57};
52} // namespace X64 58} // namespace X64
53 59