diff options
| author | 2020-02-10 11:20:40 -0400 | |
|---|---|---|
| committer | 2020-06-18 16:29:18 -0400 | |
| commit | e3524d114246a9221c766bdf1992777b208cbd67 (patch) | |
| tree | 1454fe38bdafd94ada74ae5f1209a7466bbf4e78 /src | |
| parent | Common: Implement WallClock Interface and implement a native clock for x64 (diff) | |
| download | yuzu-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.cpp | 22 | ||||
| -rw-r--r-- | src/common/uint128.h | 3 | ||||
| -rw-r--r-- | src/common/wall_clock.cpp | 13 | ||||
| -rw-r--r-- | src/common/wall_clock.h | 13 | ||||
| -rw-r--r-- | src/common/x64/native_clock.cpp | 47 | ||||
| -rw-r--r-- | src/core/host_timing.cpp | 3 |
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 | ||
| 13 | namespace Common { | 14 | namespace Common { |
| 14 | 15 | ||
| 16 | #ifdef _MSC_VER | ||
| 17 | |||
| 18 | u64 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 | |||
| 27 | u64 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 | |||
| 15 | u128 Multiply64Into128(u64 a, u64 b) { | 37 | u128 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 | ||
| 10 | namespace Common { | 10 | namespace Common { |
| 11 | 11 | ||
| 12 | // This function multiplies 2 u64 values and divides it by a u64 value. | ||
| 13 | u64 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; |
| 13 | u128 Multiply64Into128(u64 a, u64 b); | 16 | u128 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 | ||
| 61 | WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency) { | 61 | std::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 | ||
| 83 | WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency) { | 81 | std::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 | ||
| 13 | class WallClock { | 14 | class WallClock { |
| 14 | public: | 15 | public: |
| 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 | ||
| 38 | WallClock* CreateBestMatchingClock(u32 emulated_cpu_frequency, u32 emulated_clock_frequency); | 49 | std::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 | ||
| 16 | namespace Common { | 17 | namespace Common { |
| 17 | 18 | ||
| 18 | #ifdef _MSC_VER | ||
| 19 | |||
| 20 | namespace { | ||
| 21 | |||
| 22 | struct uint128 { | ||
| 23 | u64 low; | ||
| 24 | u64 high; | ||
| 25 | }; | ||
| 26 | |||
| 27 | u64 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 | |||
| 38 | namespace { | ||
| 39 | |||
| 40 | u64 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 | |||
| 52 | u64 EstimateRDTSCFrequency() { | 19 | u64 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 | ||
| 101 | std::chrono::nanoseconds NativeClock::GetTimeNS() { | 68 | std::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 | ||
| 106 | std::chrono::microseconds NativeClock::GetTimeUS() { | 73 | std::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 | ||
| 111 | std::chrono::milliseconds NativeClock::GetTimeMS() { | 78 | std::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 | ||
| 116 | u64 NativeClock::GetClockCycles() { | 83 | u64 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 | ||
| 121 | u64 NativeClock::GetCPUCycles() { | 88 | u64 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 | ||
| 38 | CoreTiming::CoreTiming() { | 38 | CoreTiming::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 | ||
| 43 | CoreTiming::~CoreTiming() = default; | 42 | CoreTiming::~CoreTiming() = default; |