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.cpp64
1 files changed, 43 insertions, 21 deletions
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 347e41efc..1b7194503 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -1,6 +1,5 @@
1// Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#include <array> 4#include <array>
6#include <chrono> 5#include <chrono>
@@ -10,25 +9,49 @@
10#include "common/uint128.h" 9#include "common/uint128.h"
11#include "common/x64/native_clock.h" 10#include "common/x64/native_clock.h"
12 11
12#ifdef _MSC_VER
13#include <intrin.h>
14#endif
15
13namespace Common { 16namespace Common {
14 17
18#ifdef _MSC_VER
19__forceinline static u64 FencedRDTSC() {
20 _mm_lfence();
21 _ReadWriteBarrier();
22 const u64 result = __rdtsc();
23 _mm_lfence();
24 _ReadWriteBarrier();
25 return result;
26}
27#else
28static u64 FencedRDTSC() {
29 u64 result;
30 asm volatile("lfence\n\t"
31 "rdtsc\n\t"
32 "shl $32, %%rdx\n\t"
33 "or %%rdx, %0\n\t"
34 "lfence"
35 : "=a"(result)
36 :
37 : "rdx", "memory", "cc");
38 return result;
39}
40#endif
41
15u64 EstimateRDTSCFrequency() { 42u64 EstimateRDTSCFrequency() {
16 // Discard the first result measuring the rdtsc. 43 // Discard the first result measuring the rdtsc.
17 _mm_mfence(); 44 FencedRDTSC();
18 __rdtsc();
19 std::this_thread::sleep_for(std::chrono::milliseconds{1}); 45 std::this_thread::sleep_for(std::chrono::milliseconds{1});
20 _mm_mfence(); 46 FencedRDTSC();
21 __rdtsc();
22 47
23 // Get the current time. 48 // Get the current time.
24 const auto start_time = std::chrono::steady_clock::now(); 49 const auto start_time = std::chrono::steady_clock::now();
25 _mm_mfence(); 50 const u64 tsc_start = FencedRDTSC();
26 const u64 tsc_start = __rdtsc();
27 // Wait for 200 milliseconds. 51 // Wait for 200 milliseconds.
28 std::this_thread::sleep_for(std::chrono::milliseconds{200}); 52 std::this_thread::sleep_for(std::chrono::milliseconds{200});
29 const auto end_time = std::chrono::steady_clock::now(); 53 const auto end_time = std::chrono::steady_clock::now();
30 _mm_mfence(); 54 const u64 tsc_end = FencedRDTSC();
31 const u64 tsc_end = __rdtsc();
32 // Calculate differences. 55 // Calculate differences.
33 const u64 timer_diff = static_cast<u64>( 56 const u64 timer_diff = static_cast<u64>(
34 std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); 57 std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
@@ -42,8 +65,7 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
42 u64 rtsc_frequency_) 65 u64 rtsc_frequency_)
43 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ 66 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
44 rtsc_frequency_} { 67 rtsc_frequency_} {
45 _mm_mfence(); 68 time_point.inner.last_measure = FencedRDTSC();
46 time_point.inner.last_measure = __rdtsc();
47 time_point.inner.accumulated_ticks = 0U; 69 time_point.inner.accumulated_ticks = 0U;
48 ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); 70 ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
49 us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); 71 us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
@@ -55,10 +77,10 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
55u64 NativeClock::GetRTSC() { 77u64 NativeClock::GetRTSC() {
56 TimePoint new_time_point{}; 78 TimePoint new_time_point{};
57 TimePoint current_time_point{}; 79 TimePoint current_time_point{};
80
81 current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());
58 do { 82 do {
59 current_time_point.pack = time_point.pack; 83 const u64 current_measure = FencedRDTSC();
60 _mm_mfence();
61 const u64 current_measure = __rdtsc();
62 u64 diff = current_measure - current_time_point.inner.last_measure; 84 u64 diff = current_measure - current_time_point.inner.last_measure;
63 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) 85 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
64 new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure 86 new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure
@@ -66,7 +88,7 @@ u64 NativeClock::GetRTSC() {
66 : current_time_point.inner.last_measure; 88 : current_time_point.inner.last_measure;
67 new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; 89 new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff;
68 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, 90 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
69 current_time_point.pack)); 91 current_time_point.pack, current_time_point.pack));
70 /// The clock cannot be more precise than the guest timer, remove the lower bits 92 /// The clock cannot be more precise than the guest timer, remove the lower bits
71 return new_time_point.inner.accumulated_ticks & inaccuracy_mask; 93 return new_time_point.inner.accumulated_ticks & inaccuracy_mask;
72} 94}
@@ -75,13 +97,13 @@ void NativeClock::Pause(bool is_paused) {
75 if (!is_paused) { 97 if (!is_paused) {
76 TimePoint current_time_point{}; 98 TimePoint current_time_point{};
77 TimePoint new_time_point{}; 99 TimePoint new_time_point{};
100
101 current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());
78 do { 102 do {
79 current_time_point.pack = time_point.pack;
80 new_time_point.pack = current_time_point.pack; 103 new_time_point.pack = current_time_point.pack;
81 _mm_mfence(); 104 new_time_point.inner.last_measure = FencedRDTSC();
82 new_time_point.inner.last_measure = __rdtsc();
83 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, 105 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
84 current_time_point.pack)); 106 current_time_point.pack, current_time_point.pack));
85 } 107 }
86} 108}
87 109