From 096c168dd7afe82a174e4df1bf548ba495672624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 7 Aug 2023 21:38:03 +0200 Subject: [PATCH] Add yield() function to tell the CPU that we're busy-waiting (rare) (#17862) * Add yield() function to tell the CPU that we're busy-waiting (rare) Use it only for the busy-wait in lag sync, which only happens in Windows. * Buildfix attempt --- Common/TimeUtil.cpp | 22 +++++++++++++++++++++- Common/TimeUtil.h | 3 +++ Core/HLE/sceDisplay.cpp | 2 ++ UI/EmuScreen.cpp | 2 +- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp index b149d1634572..099f026e3ce7 100644 --- a/Common/TimeUtil.cpp +++ b/Common/TimeUtil.cpp @@ -17,6 +17,12 @@ #include #include #endif + +// for _mm_pause +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) +#include +#endif + #include // TODO: https://github.com/floooh/sokol/blob/9a6237fcdf213e6da48e4f9201f144bcb2dcb46f/sokol_time.h#L229-L248 @@ -24,7 +30,7 @@ static const double micros = 1000000.0; static const double nanos = 1000000000.0; -#ifdef _WIN32 +#if PPSSPP_PLATFORM(WINDOWS) static LARGE_INTEGER frequency; static double frequencyMult; @@ -58,6 +64,10 @@ double from_time_raw_relative(uint64_t raw_time) { return from_time_raw(raw_time); } +void yield() { + YieldProcessor(); +} + #elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) // The only intended use is to match the timings in VK_GOOGLE_display_timing @@ -85,6 +95,14 @@ double from_time_raw_relative(uint64_t raw_time) { return (double)raw_time * (1.0 / nanos); } +void yield() { +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) + _mm_pause(); +#elif PPSSPP_ARCH(ARM64) + __builtin_arm_isb(15); +#endif +} + #else double time_now_d() { @@ -110,6 +128,8 @@ double from_time_raw_relative(uint64_t raw_time) { return from_time_raw(raw_time); } +void yield() {} + #endif void sleep_ms(int ms) { diff --git a/Common/TimeUtil.h b/Common/TimeUtil.h index 0ba1d52adf2c..a0701ae097e7 100644 --- a/Common/TimeUtil.h +++ b/Common/TimeUtil.h @@ -16,6 +16,9 @@ double from_time_raw_relative(uint64_t raw_time); // Sleep. Does not necessarily have millisecond granularity, especially on Windows. void sleep_ms(int ms); +// Yield. Signals that this thread is busy-waiting but wants to allow other hyperthreads to run. +void yield(); + void GetTimeFormatted(char formattedTime[13]); // Rust-style Instant for clear and easy timing. diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index be8551c7fd17..5d907d475c0a 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -718,6 +718,8 @@ void hleLagSync(u64 userdata, int cyclesLate) { #ifndef _WIN32 const double left = goal - now; usleep((long)(left * 1000000.0)); +#else + yield(); #endif now = time_now_d(); } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 85cf652041c2..66bb14a849d7 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -898,7 +898,7 @@ static UI::AnchorLayoutParams *AnchorInCorner(const Bounds &bounds, int corner, switch ((ScreenEdgePosition)g_Config.iChatButtonPosition) { case ScreenEdgePosition::BOTTOM_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, NONE, NONE, yOffset, true); case ScreenEdgePosition::BOTTOM_CENTER: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), NONE, NONE, yOffset, true); - case ScreenEdgePosition::BOTTOM_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, NONE, xOffset, yOffset, true); + case ScreenEdgePosition::BOTTOM_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, NONE, xOffset, yOffset, true); case ScreenEdgePosition::TOP_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, yOffset, NONE, NONE, true); case ScreenEdgePosition::TOP_CENTER: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), yOffset, NONE, NONE, true); case ScreenEdgePosition::TOP_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, yOffset, xOffset, NONE, true);