summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Morph2023-03-01 21:06:19 -0500
committerGravatar Morph2023-03-05 02:36:31 -0500
commitbff14532825e7517882ca913738347059f73cf7f (patch)
treef21f509d4c7458a79e2fc399c1de3036a7efd51d
parentmain: (Windows) Set the current timer resolution to the maximum (diff)
downloadyuzu-bff14532825e7517882ca913738347059f73cf7f.tar.gz
yuzu-bff14532825e7517882ca913738347059f73cf7f.tar.xz
yuzu-bff14532825e7517882ca913738347059f73cf7f.zip
core_timing: Use higher precision sleeps on Windows
The precision of sleep_for and wait_for is limited to 1-1.5ms on Windows. Using SleepForOneTick() allows us to sleep for exactly one interval of the current timer resolution. This allows us to take advantage of systems that have a timer resolution of 0.5ms to reduce CPU overhead in the event loop.
Diffstat (limited to '')
-rw-r--r--src/common/wall_clock.cpp5
-rw-r--r--src/common/wall_clock.h3
-rw-r--r--src/core/core_timing.cpp55
-rw-r--r--src/core/core_timing.h6
-rw-r--r--src/video_core/gpu.cpp2
5 files changed, 47 insertions, 24 deletions
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index 6d972d136..817e71d52 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -81,4 +81,9 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
81 81
82#endif 82#endif
83 83
84std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency,
85 u64 emulated_clock_frequency) {
86 return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency);
87}
88
84} // namespace Common 89} // namespace Common
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 828a523a8..157ec5eae 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -55,4 +55,7 @@ private:
55[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, 55[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
56 u64 emulated_clock_frequency); 56 u64 emulated_clock_frequency);
57 57
58[[nodiscard]] std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency,
59 u64 emulated_clock_frequency);
60
58} // namespace Common 61} // namespace Common
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
40CoreTiming::CoreTiming() 44CoreTiming::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
43CoreTiming::~CoreTiming() { 48CoreTiming::~CoreTiming() {
44 Reset(); 49 Reset();
@@ -185,15 +190,15 @@ void CoreTiming::ResetTicks() {
185} 190}
186 191
187u64 CoreTiming::GetCPUTicks() const { 192u64 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
194u64 CoreTiming::GetClockTicks() const { 199u64 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
310std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const {
311 if (is_multicore) [[likely]] {
312 return cpu_clock->GetTimeNS();
313 }
314 return CyclesToNs(ticks);
315}
316
306std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { 317std::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
313std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { 324std::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/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 7024a19cf..2e7f9c5ed 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -197,7 +197,7 @@ struct GPU::Impl {
197 constexpr u64 gpu_ticks_num = 384; 197 constexpr u64 gpu_ticks_num = 384;
198 constexpr u64 gpu_ticks_den = 625; 198 constexpr u64 gpu_ticks_den = 625;
199 199
200 u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count(); 200 u64 nanoseconds = system.CoreTiming().GetCPUTimeNs().count();
201 if (Settings::values.use_fast_gpu_time.GetValue()) { 201 if (Settings::values.use_fast_gpu_time.GetValue()) {
202 nanoseconds /= 256; 202 nanoseconds /= 256;
203 } 203 }