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