diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/core_timing.cpp | 55 | ||||
| -rw-r--r-- | src/core/core_timing.h | 6 | ||||
| -rw-r--r-- | src/core/hardware_properties.h | 8 |
3 files changed, 41 insertions, 28 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 3a63b52e3..742cfb996 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <tuple> | 7 | #include <tuple> |
| 8 | 8 | ||
| 9 | #ifdef _WIN32 | ||
| 10 | #include "common/windows/timer_resolution.h" | ||
| 11 | #endif | ||
| 12 | |||
| 9 | #include "common/microprofile.h" | 13 | #include "common/microprofile.h" |
| 10 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 11 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| @@ -38,7 +42,8 @@ struct CoreTiming::Event { | |||
| 38 | }; | 42 | }; |
| 39 | 43 | ||
| 40 | CoreTiming::CoreTiming() | 44 | CoreTiming::CoreTiming() |
| 41 | : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} | 45 | : cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)}, |
| 46 | event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} | ||
| 42 | 47 | ||
| 43 | CoreTiming::~CoreTiming() { | 48 | CoreTiming::~CoreTiming() { |
| 44 | Reset(); | 49 | Reset(); |
| @@ -185,15 +190,15 @@ void CoreTiming::ResetTicks() { | |||
| 185 | } | 190 | } |
| 186 | 191 | ||
| 187 | u64 CoreTiming::GetCPUTicks() const { | 192 | u64 CoreTiming::GetCPUTicks() const { |
| 188 | if (is_multicore) { | 193 | if (is_multicore) [[likely]] { |
| 189 | return clock->GetCPUCycles(); | 194 | return cpu_clock->GetCPUCycles(); |
| 190 | } | 195 | } |
| 191 | return ticks; | 196 | return ticks; |
| 192 | } | 197 | } |
| 193 | 198 | ||
| 194 | u64 CoreTiming::GetClockTicks() const { | 199 | u64 CoreTiming::GetClockTicks() const { |
| 195 | if (is_multicore) { | 200 | if (is_multicore) [[likely]] { |
| 196 | return clock->GetClockCycles(); | 201 | return cpu_clock->GetClockCycles(); |
| 197 | } | 202 | } |
| 198 | return CpuCyclesToClockCycles(ticks); | 203 | return CpuCyclesToClockCycles(ticks); |
| 199 | } | 204 | } |
| @@ -252,21 +257,20 @@ void CoreTiming::ThreadLoop() { | |||
| 252 | const auto next_time = Advance(); | 257 | const auto next_time = Advance(); |
| 253 | if (next_time) { | 258 | if (next_time) { |
| 254 | // There are more events left in the queue, wait until the next event. | 259 | // There are more events left in the queue, wait until the next event. |
| 255 | const auto wait_time = *next_time - GetGlobalTimeNs().count(); | 260 | auto wait_time = *next_time - GetGlobalTimeNs().count(); |
| 256 | if (wait_time > 0) { | 261 | if (wait_time > 0) { |
| 257 | #ifdef _WIN32 | 262 | #ifdef _WIN32 |
| 258 | // Assume a timer resolution of 1ms. | 263 | const auto timer_resolution_ns = |
| 259 | static constexpr s64 TimerResolutionNS = 1000000; | 264 | Common::Windows::GetCurrentTimerResolution().count(); |
| 260 | 265 | ||
| 261 | // Sleep in discrete intervals of the timer resolution, and spin the rest. | 266 | while (!paused && !event.IsSet() && wait_time > 0) { |
| 262 | const auto sleep_time = wait_time - (wait_time % TimerResolutionNS); | 267 | wait_time = *next_time - GetGlobalTimeNs().count(); |
| 263 | if (sleep_time > 0) { | ||
| 264 | event.WaitFor(std::chrono::nanoseconds(sleep_time)); | ||
| 265 | } | ||
| 266 | 268 | ||
| 267 | while (!paused && !event.IsSet() && GetGlobalTimeNs().count() < *next_time) { | 269 | if (wait_time >= timer_resolution_ns) { |
| 268 | // Yield to reduce thread starvation. | 270 | Common::Windows::SleepForOneTick(); |
| 269 | std::this_thread::yield(); | 271 | } else { |
| 272 | std::this_thread::yield(); | ||
| 273 | } | ||
| 270 | } | 274 | } |
| 271 | 275 | ||
| 272 | if (event.IsSet()) { | 276 | if (event.IsSet()) { |
| @@ -285,9 +289,9 @@ void CoreTiming::ThreadLoop() { | |||
| 285 | } | 289 | } |
| 286 | 290 | ||
| 287 | paused_set = true; | 291 | paused_set = true; |
| 288 | clock->Pause(true); | 292 | event_clock->Pause(true); |
| 289 | pause_event.Wait(); | 293 | pause_event.Wait(); |
| 290 | clock->Pause(false); | 294 | event_clock->Pause(false); |
| 291 | } | 295 | } |
| 292 | } | 296 | } |
| 293 | 297 | ||
| @@ -303,16 +307,23 @@ void CoreTiming::Reset() { | |||
| 303 | has_started = false; | 307 | has_started = false; |
| 304 | } | 308 | } |
| 305 | 309 | ||
| 310 | std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const { | ||
| 311 | if (is_multicore) [[likely]] { | ||
| 312 | return cpu_clock->GetTimeNS(); | ||
| 313 | } | ||
| 314 | return CyclesToNs(ticks); | ||
| 315 | } | ||
| 316 | |||
| 306 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { | 317 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { |
| 307 | if (is_multicore) { | 318 | if (is_multicore) [[likely]] { |
| 308 | return clock->GetTimeNS(); | 319 | return event_clock->GetTimeNS(); |
| 309 | } | 320 | } |
| 310 | return CyclesToNs(ticks); | 321 | return CyclesToNs(ticks); |
| 311 | } | 322 | } |
| 312 | 323 | ||
| 313 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { | 324 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { |
| 314 | if (is_multicore) { | 325 | if (is_multicore) [[likely]] { |
| 315 | return clock->GetTimeUS(); | 326 | return event_clock->GetTimeUS(); |
| 316 | } | 327 | } |
| 317 | return CyclesToUs(ticks); | 328 | return CyclesToUs(ticks); |
| 318 | } | 329 | } |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index da366637b..4b89c0c39 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -122,6 +122,9 @@ public: | |||
| 122 | /// Returns current time in emulated in Clock cycles | 122 | /// Returns current time in emulated in Clock cycles |
| 123 | u64 GetClockTicks() const; | 123 | u64 GetClockTicks() const; |
| 124 | 124 | ||
| 125 | /// Returns current time in nanoseconds. | ||
| 126 | std::chrono::nanoseconds GetCPUTimeNs() const; | ||
| 127 | |||
| 125 | /// Returns current time in microseconds. | 128 | /// Returns current time in microseconds. |
| 126 | std::chrono::microseconds GetGlobalTimeUs() const; | 129 | std::chrono::microseconds GetGlobalTimeUs() const; |
| 127 | 130 | ||
| @@ -139,7 +142,8 @@ private: | |||
| 139 | 142 | ||
| 140 | void Reset(); | 143 | void Reset(); |
| 141 | 144 | ||
| 142 | std::unique_ptr<Common::WallClock> clock; | 145 | std::unique_ptr<Common::WallClock> cpu_clock; |
| 146 | std::unique_ptr<Common::WallClock> event_clock; | ||
| 143 | 147 | ||
| 144 | s64 global_timer = 0; | 148 | s64 global_timer = 0; |
| 145 | 149 | ||
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 45567b840..191c28bb4 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h | |||
| @@ -13,11 +13,9 @@ namespace Core { | |||
| 13 | 13 | ||
| 14 | namespace Hardware { | 14 | namespace Hardware { |
| 15 | 15 | ||
| 16 | // The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz | 16 | constexpr u64 BASE_CLOCK_RATE = 1'020'000'000; // Default CPU Frequency = 1020 MHz |
| 17 | // The exact value used is of course unverified. | 17 | constexpr u64 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz |
| 18 | constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked | 18 | constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores |
| 19 | constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed | ||
| 20 | constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores | ||
| 21 | 19 | ||
| 22 | // Virtual to Physical core map. | 20 | // Virtual to Physical core map. |
| 23 | constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ | 21 | constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ |