Add more accurate sleep function (well, not more accurate on Windows unfortunately)

This commit is contained in:
Henrik Rydgård committed 2025-10-21 12:11:23 +02:00
1 parent 29032f4a70
commit 7cc4a0f3a3
6 files changed
+37 -15

No files matched your search

-2
View File
@@ -882,8 +882,6 @@ private:
std::mutex syncMutex_;
std::condition_variable syncCondVar_;
bool firstFrame_ = true;
bool vrRenderStarted_ = false;
bool syncDone_ = false;
GLDeleter deleter_;
+27 -4
View File
@@ -253,8 +253,12 @@ double Instant::ElapsedSeconds() const {
#endif
#define SLEEP_LOG_ENABLED 0
void sleep_ms(int ms, const char *reason) {
// INFO_LOG(Log::System, "Sleep %d ms: %s", ms, reason);
#if SLEEP_LOG_ENABLED
INFO_LOG(Log::System, "Sleep %d ms: %s", ms, reason);
#endif
#ifdef _WIN32
Sleep(ms);
#elif defined(HAVE_LIBNX)
@@ -266,10 +270,29 @@ void sleep_ms(int ms, const char *reason) {
#endif
}
void sleep_precise(double seconds) {
void sleep_us(int us, const char *reason) {
#if SLEEP_LOG_ENABLED
INFO_LOG(Log::System, "Sleep %d us: %s", us, reason);
#endif
#ifdef _WIN32
Sleep(us / 1000);
#elif defined(HAVE_LIBNX)
svcSleepThread(us * 1000);
#elif defined(__EMSCRIPTEN__)
emscripten_sleep(us / 1000);
#else
usleep(us);
#endif
}
// This can be a little more expensive in some circumstances, so only use when necessary.
void sleep_precise(double seconds, const char *reason) {
if (seconds <= 0.0) {
return;
}
#if SLEEP_LOG_ENABLED
INFO_LOG(Log::System, "Sleep precise %f s: %s", seconds, reason);
#endif
#ifdef _WIN32
// Precise Windows sleep function from: https://github.com/blat-blatnik/Snippets/blob/main/precise_sleep.c
// Described in: https://blog.bearcats.nl/perfect-sleep-function/
@@ -347,7 +370,7 @@ void GetCurrentTimeFormatted(char formattedTime[13]) {
// We don't even bother synchronizing this, it's fine if threads stomp a bit.
static GMRng g_sleepRandom;
void sleep_random(double minSeconds, double maxSeconds) {
void sleep_random(double minSeconds, double maxSeconds, const char *reason) {
const double waitSeconds = minSeconds + (maxSeconds - minSeconds) * g_sleepRandom.F();
sleep_precise(waitSeconds);
sleep_precise(waitSeconds, reason);
}
+5 -4
View File
@@ -17,16 +17,17 @@ double from_time_raw_relative(uint64_t raw_time);
// Seconds, Unix UTC time
double time_now_unix_utc();
// Sleep. Does not necessarily have millisecond granularity, especially on Windows.
// Sleep for milliseconds. Does not necessarily have millisecond granularity, especially on Windows.
// Requires a "reason" since sleeping generally should be very sparingly used. This
// can be logged if desired to figure out where we're wasting time.
void sleep_ms(int ms, const char *reason);
// Sleep for microseconds. Does not necessarily have microsecond granularity, especially on Windows.
void sleep_us(int us, const char *reason);
// Precise sleep. Can consume a little bit of CPU on Windows at least.
void sleep_precise(double seconds);
void sleep_precise(double seconds, const char *reason);
// Random sleep, used for debugging.
void sleep_random(double minSeconds, double maxSeconds);
void sleep_random(double minSeconds, double maxSeconds, const char *reason);
// Yield. Signals that this thread is busy-waiting but wants to allow other hyperthreads to run.
void yield();
+1 -1
View File
@@ -39,7 +39,7 @@ FrameTiming g_frameTiming;
void WaitUntil(double now, double timestamp, const char *reason) {
#if 1
// Use precise timing.
sleep_precise(timestamp - now);
sleep_precise(timestamp - now, reason);
#else
#if PPSSPP_PLATFORM(WINDOWS)
+1 -1
View File
@@ -477,7 +477,7 @@ int upnpService(const unsigned int timeout) {
// Service Loop
while (upnpServiceRunning) {
// Sleep for 1ms for faster response if active, otherwise sleep longer (TODO: Improve on this).
sleep_ms(g_Config.bEnableUPnP ? 1 : 100, "upnp-poll");
sleep_ms(g_Config.bEnableUPnP ? 1 : 500, "upnp-poll");
// Attempts to reconnect if not connected yet or got disconnected
if (g_Config.bEnableUPnP && g_PortManager.GetInitState() == UPNP_INITSTATE_NONE) {
+3 -3
View File
@@ -1251,9 +1251,9 @@ void NativeFrame(GraphicsContext *graphicsContext) {
// Simple throttling to not burn the GPU in the menu.
// TODO: This is only necessary in MAILBOX or IMMEDIATE presentation modes.
double diffTime = time_now_d() - startTime;
int sleepTime = (int)(1000.0 / refreshRate) - (int)(diffTime * 1000.0);
if (sleepTime > 0)
sleep_ms(sleepTime, "fallback-throttle");
int sleepTimeUs = (int)(1000000 * ((1.0 / refreshRate) - diffTime));
if (sleepTimeUs > 0)
sleep_us(sleepTimeUs, "fallback-throttle");
}
}