summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-10 11:20:40 -0400
committerGravatar Fernando Sahmkow2020-06-18 16:29:18 -0400
commite3524d114246a9221c766bdf1992777b208cbd67 (patch)
tree1454fe38bdafd94ada74ae5f1209a7466bbf4e78 /src
parentCommon: Implement WallClock Interface and implement a native clock for x64 (diff)
downloadyuzu-e3524d114246a9221c766bdf1992777b208cbd67.tar.gz
yuzu-e3524d114246a9221c766bdf1992777b208cbd67.tar.xz
yuzu-e3524d114246a9221c766bdf1992777b208cbd67.zip
Common: Refactor & Document Wall clock.
Diffstat (limited to 'src')
-rw-r--r--src/common/uint128.cpp22
-rw-r--r--src/common/uint128.h3
-rw-r--r--src/common/wall_clock.cpp13
-rw-r--r--src/common/wall_clock.h13
-rw-r--r--src/common/x64/native_clock.cpp47
-rw-r--r--src/core/host_timing.cpp3
6 files changed, 50 insertions, 51 deletions
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp
index 32bf56730..7e77588db 100644
--- a/src/common/uint128.cpp
+++ b/src/common/uint128.cpp
@@ -6,12 +6,34 @@
6#include <intrin.h> 6#include <intrin.h>
7 7
8#pragma intrinsic(_umul128) 8#pragma intrinsic(_umul128)
9#pragma intrinsic(_udiv128)
9#endif 10#endif
10#include <cstring> 11#include <cstring>
11#include "common/uint128.h" 12#include "common/uint128.h"
12 13
13namespace Common { 14namespace Common {
14 15
16#ifdef _MSC_VER
17
18u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
19 u128 r{};
20 r[0] = _umul128(a, b, &r[1]);
21 u64 remainder;
22 return _udiv128(r[1], r[0], d, &remainder);
23}
24
25#else
26
27u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
28 const u64 diva = a / d;
29 const u64 moda = a % d;
30 const u64 divb = b / d;
31 const u64 modb = b % d;
32 return diva * b + moda * divb + moda * modb / d;
33}
34
35#endif
36
15u128 Multiply64Into128(u64 a, u64 b) { 37u128 Multiply64Into128(u64 a, u64 b) {
16 u128 result; 38 u128 result;
17#ifdef _MSC_VER 39#ifdef _MSC_VER
diff --git a/src/common/uint128.h b/src/common/uint128.h
index a3be2a2cb..503cd2d0c 100644
--- a/src/common/uint128.h
+++ b/src/common/uint128.h
@@ -9,6 +9,9 @@
9 9
10namespace Common { 10namespace Common {
11 11
12// This function multiplies 2 u64 values and divides it by a u64 value.
13u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
14
12// This function multiplies 2 u64 values and produces a u128 value; 15// This function multiplies 2 u64 values and produces a u128 value;
13u128 Multiply64Into128(u64 a, u64 b); 16u128 Multiply64Into128(u64 a, u64 b);
14 17
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index eabbba9da..8f5e17fa4 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -58,7 +58,7 @@ private:
58 58
59#ifdef ARCHITECTURE_x86_64 59#ifdef ARCHITECTURE_x86_64
60 60
61WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency) { 61std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency) {
62 const auto& caps = GetCPUCaps(); 62 const auto& caps = GetCPUCaps();
63 u64 rtsc_frequency = 0; 63 u64 rtsc_frequency = 0;
64 if (caps.invariant_tsc) { 64 if (caps.invariant_tsc) {
@@ -70,19 +70,16 @@ WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_cloc
70 } 70 }
71 } 71 }
72 if (rtsc_frequency == 0) { 72 if (rtsc_frequency == 0) {
73 return static_cast<WallClock*>( 73 return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency);
74 new StandardWallClock(emulated_cpu_frequency, emulated_clock_frequency));
75 } else { 74 } else {
76 return static_cast<WallClock*>( 75 return std::make_unique<X64::NativeClock>(emulated_cpu_frequency, emulated_clock_frequency, rtsc_frequency);
77 new X64::NativeClock(emulated_cpu_frequency, emulated_clock_frequency, rtsc_frequency));
78 } 76 }
79} 77}
80 78
81#else 79#else
82 80
83WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency) { 81std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency) {
84 return static_cast<WallClock*>( 82 return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency);
85 new StandardWallClock(emulated_cpu_frequency, emulated_clock_frequency));
86} 83}
87 84
88#endif 85#endif
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 6f763d74b..fc34429bb 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <chrono> 7#include <chrono>
8#include <memory>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
@@ -12,10 +13,20 @@ namespace Common {
12 13
13class WallClock { 14class WallClock {
14public: 15public:
16
17 /// Returns current wall time in nanoseconds
15 virtual std::chrono::nanoseconds GetTimeNS() = 0; 18 virtual std::chrono::nanoseconds GetTimeNS() = 0;
19
20 /// Returns current wall time in microseconds
16 virtual std::chrono::microseconds GetTimeUS() = 0; 21 virtual std::chrono::microseconds GetTimeUS() = 0;
22
23 /// Returns current wall time in milliseconds
17 virtual std::chrono::milliseconds GetTimeMS() = 0; 24 virtual std::chrono::milliseconds GetTimeMS() = 0;
25
26 /// Returns current wall time in emulated clock cycles
18 virtual u64 GetClockCycles() = 0; 27 virtual u64 GetClockCycles() = 0;
28
29 /// Returns current wall time in emulated cpu cycles
19 virtual u64 GetCPUCycles() = 0; 30 virtual u64 GetCPUCycles() = 0;
20 31
21 /// Tells if the wall clock, uses the host CPU's hardware clock 32 /// Tells if the wall clock, uses the host CPU's hardware clock
@@ -35,6 +46,6 @@ private:
35 bool is_native; 46 bool is_native;
36}; 47};
37 48
38WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency); 49std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency);
39 50
40} // namespace Common 51} // namespace Common
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index c799111fd..26d4d0ba6 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -11,44 +11,11 @@
11#include <x86intrin.h> 11#include <x86intrin.h>
12#endif 12#endif
13 13
14#include "common/uint128.h"
14#include "common/x64/native_clock.h" 15#include "common/x64/native_clock.h"
15 16
16namespace Common { 17namespace Common {
17 18
18#ifdef _MSC_VER
19
20namespace {
21
22struct uint128 {
23 u64 low;
24 u64 high;
25};
26
27u64 umuldiv64(u64 a, u64 b, u64 d) {
28 uint128 r{};
29 r.low = _umul128(a, b, &r.high);
30 u64 remainder;
31 return _udiv128(r.high, r.low, d, &remainder);
32}
33
34} // namespace
35
36#else
37
38namespace {
39
40u64 umuldiv64(u64 a, u64 b, u64 d) {
41 const u64 diva = a / d;
42 const u64 moda = a % d;
43 const u64 divb = b / d;
44 const u64 modb = b % d;
45 return diva * b + moda * divb + moda * modb / d;
46}
47
48} // namespace
49
50#endif
51
52u64 EstimateRDTSCFrequency() { 19u64 EstimateRDTSCFrequency() {
53 const auto milli_10 = std::chrono::milliseconds{10}; 20 const auto milli_10 = std::chrono::milliseconds{10};
54 // get current time 21 // get current time
@@ -70,7 +37,7 @@ u64 EstimateRDTSCFrequency() {
70 const u64 timer_diff = 37 const u64 timer_diff =
71 std::chrono::duration_cast<std::chrono::nanoseconds>(endTime - startTime).count(); 38 std::chrono::duration_cast<std::chrono::nanoseconds>(endTime - startTime).count();
72 const u64 tsc_diff = tscEnd - tscStart; 39 const u64 tsc_diff = tscEnd - tscStart;
73 const u64 tsc_freq = umuldiv64(tsc_diff, 1000000000ULL, timer_diff); 40 const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
74 return tsc_freq; 41 return tsc_freq;
75} 42}
76 43
@@ -100,27 +67,27 @@ u64 NativeClock::GetRTSC() {
100 67
101std::chrono::nanoseconds NativeClock::GetTimeNS() { 68std::chrono::nanoseconds NativeClock::GetTimeNS() {
102 const u64 rtsc_value = GetRTSC(); 69 const u64 rtsc_value = GetRTSC();
103 return std::chrono::nanoseconds{umuldiv64(rtsc_value, 1000000000, rtsc_frequency)}; 70 return std::chrono::nanoseconds{MultiplyAndDivide64(rtsc_value, 1000000000, rtsc_frequency)};
104} 71}
105 72
106std::chrono::microseconds NativeClock::GetTimeUS() { 73std::chrono::microseconds NativeClock::GetTimeUS() {
107 const u64 rtsc_value = GetRTSC(); 74 const u64 rtsc_value = GetRTSC();
108 return std::chrono::microseconds{umuldiv64(rtsc_value, 1000000, rtsc_frequency)}; 75 return std::chrono::microseconds{MultiplyAndDivide64(rtsc_value, 1000000, rtsc_frequency)};
109} 76}
110 77
111std::chrono::milliseconds NativeClock::GetTimeMS() { 78std::chrono::milliseconds NativeClock::GetTimeMS() {
112 const u64 rtsc_value = GetRTSC(); 79 const u64 rtsc_value = GetRTSC();
113 return std::chrono::milliseconds{umuldiv64(rtsc_value, 1000, rtsc_frequency)}; 80 return std::chrono::milliseconds{MultiplyAndDivide64(rtsc_value, 1000, rtsc_frequency)};
114} 81}
115 82
116u64 NativeClock::GetClockCycles() { 83u64 NativeClock::GetClockCycles() {
117 const u64 rtsc_value = GetRTSC(); 84 const u64 rtsc_value = GetRTSC();
118 return umuldiv64(rtsc_value, emulated_clock_frequency, rtsc_frequency); 85 return MultiplyAndDivide64(rtsc_value, emulated_clock_frequency, rtsc_frequency);
119} 86}
120 87
121u64 NativeClock::GetCPUCycles() { 88u64 NativeClock::GetCPUCycles() {
122 const u64 rtsc_value = GetRTSC(); 89 const u64 rtsc_value = GetRTSC();
123 return umuldiv64(rtsc_value, emulated_cpu_frequency, rtsc_frequency); 90 return MultiplyAndDivide64(rtsc_value, emulated_cpu_frequency, rtsc_frequency);
124} 91}
125 92
126} // namespace X64 93} // namespace X64
diff --git a/src/core/host_timing.cpp b/src/core/host_timing.cpp
index ef9977b76..4ccf7c6c1 100644
--- a/src/core/host_timing.cpp
+++ b/src/core/host_timing.cpp
@@ -36,8 +36,7 @@ struct CoreTiming::Event {
36}; 36};
37 37
38CoreTiming::CoreTiming() { 38CoreTiming::CoreTiming() {
39 Common::WallClock* wall = Common::CreateBestMatchingClock(Core::Timing::BASE_CLOCK_RATE, Core::Timing::CNTFREQ); 39 clock = Common::CreateBestMatchingClock(Core::Timing::BASE_CLOCK_RATE, Core::Timing::CNTFREQ);
40 clock = std::unique_ptr<Common::WallClock>(wall);
41} 40}
42 41
43CoreTiming::~CoreTiming() = default; 42CoreTiming::~CoreTiming() = default;