diff options
| author | 2023-06-07 21:38:28 -0400 | |
|---|---|---|
| committer | 2023-06-07 21:44:42 -0400 | |
| commit | 2e1e7254436b032f133372c76d9484aa756d56df (patch) | |
| tree | ce55efc11d5dee53a87532b77ce85d3e0d2b2a76 | |
| parent | (wall, native)_clock: Add GetGPUTick (diff) | |
| download | yuzu-2e1e7254436b032f133372c76d9484aa756d56df.tar.gz yuzu-2e1e7254436b032f133372c76d9484aa756d56df.tar.xz yuzu-2e1e7254436b032f133372c76d9484aa756d56df.zip | |
core_timing: Fix SingleCore cycle timer
| -rw-r--r-- | src/common/wall_clock.h | 36 | ||||
| -rw-r--r-- | src/core/core_timing.cpp | 26 | ||||
| -rw-r--r-- | src/core/core_timing.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_tick.cpp | 10 |
4 files changed, 31 insertions, 43 deletions
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index fcfdd637c..f45d3d8c5 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h | |||
| @@ -13,8 +13,9 @@ namespace Common { | |||
| 13 | 13 | ||
| 14 | class WallClock { | 14 | class WallClock { |
| 15 | public: | 15 | public: |
| 16 | static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz | 16 | static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz |
| 17 | static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz | 17 | static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz |
| 18 | static constexpr u64 CPUTickFreq = 1'020'000'000; // T210/4 A57 CPU Tick Frequency = 1020.0 MHz | ||
| 18 | 19 | ||
| 19 | virtual ~WallClock() = default; | 20 | virtual ~WallClock() = default; |
| 20 | 21 | ||
| @@ -46,28 +47,26 @@ public: | |||
| 46 | return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; | 47 | return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | static inline u64 USToCNTPCT(u64 us) { | ||
| 50 | return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den; | ||
| 51 | } | ||
| 52 | |||
| 53 | static inline u64 NSToGPUTick(u64 ns) { | 50 | static inline u64 NSToGPUTick(u64 ns) { |
| 54 | return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den; | 51 | return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den; |
| 55 | } | 52 | } |
| 56 | 53 | ||
| 57 | static inline u64 CNTPCTToNS(u64 cntpct) { | 54 | // Cycle Timing |
| 58 | return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num; | 55 | |
| 56 | static inline u64 CPUTickToNS(u64 cpu_tick) { | ||
| 57 | return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den; | ||
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | static inline u64 CNTPCTToUS(u64 cntpct) { | 60 | static inline u64 CPUTickToUS(u64 cpu_tick) { |
| 62 | return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num; | 61 | return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den; |
| 63 | } | 62 | } |
| 64 | 63 | ||
| 65 | static inline u64 GPUTickToNS(u64 gpu_tick) { | 64 | static inline u64 CPUTickToCNTPCT(u64 cpu_tick) { |
| 66 | return gpu_tick * NsToGPUTickRatio::den / NsToGPUTickRatio::num; | 65 | return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den; |
| 67 | } | 66 | } |
| 68 | 67 | ||
| 69 | static inline u64 CNTPCTToGPUTick(u64 cntpct) { | 68 | static inline u64 CPUTickToGPUTick(u64 cpu_tick) { |
| 70 | return cntpct * CNTPCTToGPUTickRatio::num / CNTPCTToGPUTickRatio::den; | 69 | return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den; |
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | protected: | 72 | protected: |
| @@ -78,9 +77,14 @@ protected: | |||
| 78 | using NsToUsRatio = std::ratio_divide<std::nano, std::micro>; | 77 | using NsToUsRatio = std::ratio_divide<std::nano, std::micro>; |
| 79 | using NsToMsRatio = std::ratio_divide<std::nano, std::milli>; | 78 | using NsToMsRatio = std::ratio_divide<std::nano, std::milli>; |
| 80 | using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>; | 79 | using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>; |
| 81 | using UsToCNTPCTRatio = std::ratio<CNTFRQ, std::micro::den>; | ||
| 82 | using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>; | 80 | using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>; |
| 83 | using CNTPCTToGPUTickRatio = std::ratio<GPUTickFreq, CNTFRQ>; | 81 | |
| 82 | // Cycle Timing | ||
| 83 | |||
| 84 | using CPUTickToNsRatio = std::ratio<std::nano::den, CPUTickFreq>; | ||
| 85 | using CPUTickToUsRatio = std::ratio<std::micro::den, CPUTickFreq>; | ||
| 86 | using CPUTickToCNTPCTRatio = std::ratio<CNTFRQ, CPUTickFreq>; | ||
| 87 | using CPUTickToGPUTickRatio = std::ratio<GPUTickFreq, CPUTickFreq>; | ||
| 84 | }; | 88 | }; |
| 85 | 89 | ||
| 86 | std::unique_ptr<WallClock> CreateOptimalClock(); | 90 | std::unique_ptr<WallClock> CreateOptimalClock(); |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index e57bca70a..4f0a3f8ea 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | namespace Core::Timing { | 21 | namespace Core::Timing { |
| 22 | 22 | ||
| 23 | constexpr s64 MAX_SLICE_LENGTH = 4000; | 23 | constexpr s64 MAX_SLICE_LENGTH = 10000; |
| 24 | 24 | ||
| 25 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { | 25 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { |
| 26 | return std::make_shared<EventType>(std::move(callback), std::move(name)); | 26 | return std::make_shared<EventType>(std::move(callback), std::move(name)); |
| @@ -65,7 +65,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { | |||
| 65 | on_thread_init = std::move(on_thread_init_); | 65 | on_thread_init = std::move(on_thread_init_); |
| 66 | event_fifo_id = 0; | 66 | event_fifo_id = 0; |
| 67 | shutting_down = false; | 67 | shutting_down = false; |
| 68 | ticks = 0; | 68 | cpu_ticks = 0; |
| 69 | const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) | 69 | const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) |
| 70 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; | 70 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; |
| 71 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); | 71 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); |
| @@ -170,20 +170,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, | |||
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | void CoreTiming::AddTicks(u64 ticks_to_add) { | 172 | void CoreTiming::AddTicks(u64 ticks_to_add) { |
| 173 | ticks += ticks_to_add; | 173 | cpu_ticks += ticks_to_add; |
| 174 | downcount -= static_cast<s64>(ticks); | 174 | downcount -= static_cast<s64>(cpu_ticks); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | void CoreTiming::Idle() { | 177 | void CoreTiming::Idle() { |
| 178 | if (!event_queue.empty()) { | 178 | cpu_ticks += 1000U; |
| 179 | const u64 next_event_time = event_queue.front().time; | ||
| 180 | const u64 next_ticks = Common::WallClock::NSToCNTPCT(next_event_time) + 10U; | ||
| 181 | if (next_ticks > ticks) { | ||
| 182 | ticks = next_ticks; | ||
| 183 | } | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | ticks += 1000U; | ||
| 187 | } | 179 | } |
| 188 | 180 | ||
| 189 | void CoreTiming::ResetTicks() { | 181 | void CoreTiming::ResetTicks() { |
| @@ -194,14 +186,14 @@ u64 CoreTiming::GetClockTicks() const { | |||
| 194 | if (is_multicore) [[likely]] { | 186 | if (is_multicore) [[likely]] { |
| 195 | return clock->GetCNTPCT(); | 187 | return clock->GetCNTPCT(); |
| 196 | } | 188 | } |
| 197 | return ticks; | 189 | return Common::WallClock::CPUTickToCNTPCT(cpu_ticks); |
| 198 | } | 190 | } |
| 199 | 191 | ||
| 200 | u64 CoreTiming::GetGPUTicks() const { | 192 | u64 CoreTiming::GetGPUTicks() const { |
| 201 | if (is_multicore) [[likely]] { | 193 | if (is_multicore) [[likely]] { |
| 202 | return clock->GetGPUTick(); | 194 | return clock->GetGPUTick(); |
| 203 | } | 195 | } |
| 204 | return Common::WallClock::CNTPCTToGPUTick(ticks); | 196 | return Common::WallClock::CPUTickToGPUTick(cpu_ticks); |
| 205 | } | 197 | } |
| 206 | 198 | ||
| 207 | std::optional<s64> CoreTiming::Advance() { | 199 | std::optional<s64> CoreTiming::Advance() { |
| @@ -314,14 +306,14 @@ std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { | |||
| 314 | if (is_multicore) [[likely]] { | 306 | if (is_multicore) [[likely]] { |
| 315 | return clock->GetTimeNS(); | 307 | return clock->GetTimeNS(); |
| 316 | } | 308 | } |
| 317 | return std::chrono::nanoseconds{Common::WallClock::CNTPCTToNS(ticks)}; | 309 | return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)}; |
| 318 | } | 310 | } |
| 319 | 311 | ||
| 320 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { | 312 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { |
| 321 | if (is_multicore) [[likely]] { | 313 | if (is_multicore) [[likely]] { |
| 322 | return clock->GetTimeUS(); | 314 | return clock->GetTimeUS(); |
| 323 | } | 315 | } |
| 324 | return std::chrono::microseconds{Common::WallClock::CNTPCTToUS(ticks)}; | 316 | return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)}; |
| 325 | } | 317 | } |
| 326 | 318 | ||
| 327 | } // namespace Core::Timing | 319 | } // namespace Core::Timing |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 1873852c4..10db1de55 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -167,7 +167,7 @@ private: | |||
| 167 | s64 pause_end_time{}; | 167 | s64 pause_end_time{}; |
| 168 | 168 | ||
| 169 | /// Cycle timing | 169 | /// Cycle timing |
| 170 | u64 ticks{}; | 170 | u64 cpu_ticks{}; |
| 171 | s64 downcount{}; | 171 | s64 downcount{}; |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
diff --git a/src/core/hle/kernel/svc/svc_tick.cpp b/src/core/hle/kernel/svc/svc_tick.cpp index 561336482..7dd7c6e51 100644 --- a/src/core/hle/kernel/svc/svc_tick.cpp +++ b/src/core/hle/kernel/svc/svc_tick.cpp | |||
| @@ -12,16 +12,8 @@ namespace Kernel::Svc { | |||
| 12 | int64_t GetSystemTick(Core::System& system) { | 12 | int64_t GetSystemTick(Core::System& system) { |
| 13 | LOG_TRACE(Kernel_SVC, "called"); | 13 | LOG_TRACE(Kernel_SVC, "called"); |
| 14 | 14 | ||
| 15 | auto& core_timing = system.CoreTiming(); | ||
| 16 | |||
| 17 | // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) | 15 | // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) |
| 18 | const u64 result{core_timing.GetClockTicks()}; | 16 | return static_cast<int64_t>(system.CoreTiming().GetClockTicks()); |
| 19 | |||
| 20 | if (!system.Kernel().IsMulticore()) { | ||
| 21 | core_timing.AddTicks(400U); | ||
| 22 | } | ||
| 23 | |||
| 24 | return static_cast<int64_t>(result); | ||
| 25 | } | 17 | } |
| 26 | 18 | ||
| 27 | int64_t GetSystemTick64(Core::System& system) { | 19 | int64_t GetSystemTick64(Core::System& system) { |