From 37edcce1fa3f87cf982dd166cb441787d9ec0e2d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 4 Oct 2025 02:03:11 +0600 Subject: [PATCH] Call timeBeginPeriod only once on startup (#6273) Use SetProcessInformation to make the OS better handle our threads on big/small cores --- src/qt/qt_main.cpp | 9 +++++ src/qt/qt_platform.cpp | 78 ++++++++++++++++++++++++++++++++++++------ src/qt/qt_ui.cpp | 4 --- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 8fbcfe7d3..5f9101d47 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -98,6 +98,7 @@ extern "C" { #include <86box/timer.h> #include <86box/nvr.h> extern int qt_nvr_save(void); +extern void exit_pause(void); bool cpu_thread_running = false; } @@ -753,6 +754,14 @@ main(int argc, char *argv[]) discord_load(); #endif +#ifdef Q_OS_WINDOWS + // On Win32 the accuracy of Sleep() depends on the timer resolution, which can be set by calling timeBeginPeriod + // https://learn.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timebeginperiod + exit_pause(); + timeBeginPeriod(1); + atexit([] () -> void { timeEndPeriod(1); }); +#endif + main_window = new MainWindow(); if (startMaximized) { main_window->showMaximized(); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index ad49e5e7c..6b60adffa 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -453,6 +453,65 @@ plat_munmap(void *ptr, size_t size) } extern bool cpu_thread_running; + +#ifdef Q_OS_WINDOWS +/* SetThreadDescription was added in 14393 and SetProcessInformation in 8. Revisit if we ever start requiring 10. */ +static void *kernel32_handle = NULL; +static HRESULT(WINAPI *pSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription) = NULL; +static HRESULT(WINAPI *pSetProcessInformation)(HANDLE hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, LPVOID ProcessInformation, DWORD ProcessInformationSize) = NULL; +static dllimp_t kernel32_imports[] = { + // clang-format off + { "SetThreadDescription", &pSetThreadDescription }, + { "SetProcessInformation", &pSetProcessInformation }, + { NULL, NULL } + // clang-format on +}; + +static void +enter_pause(void) +{ + PROCESS_POWER_THROTTLING_STATE state{}; + state.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; + state.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION; + state.StateMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION; + + if (!kernel32_handle) { + kernel32_handle = dynld_module("kernel32.dll", kernel32_imports); + if (!kernel32_handle) { + kernel32_handle = kernel32_imports; /* store dummy pointer to avoid trying again */ + pSetThreadDescription = NULL; + pSetProcessInformation = NULL; + } + } + + if (pSetProcessInformation) { + pSetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, (LPVOID)&state, sizeof(state)); + } +} + +void +exit_pause(void) +{ + PROCESS_POWER_THROTTLING_STATE state{}; + state.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; + state.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION; + state.StateMask = 0; + + if (!kernel32_handle) { + kernel32_handle = dynld_module("kernel32.dll", kernel32_imports); + if (!kernel32_handle) { + kernel32_handle = kernel32_imports; /* store dummy pointer to avoid trying again */ + pSetThreadDescription = NULL; + pSetProcessInformation = NULL; + } + } + + if (pSetProcessInformation) { + pSetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, (LPVOID)&state, sizeof(state)); + } +} +#endif + void plat_pause(int p) { @@ -477,6 +536,14 @@ plat_pause(int p) if ((p == 0) && (time_sync & TIME_SYNC_ENABLED)) nvr_time_sync(); +#ifdef Q_OS_WINDOWS + if (p) { + enter_pause(); + } else { + exit_pause(); + } +#endif + do_pause(p); if (p) { if (mouse_capture) @@ -842,21 +909,12 @@ void plat_set_thread_name(void *thread, const char *name) { #ifdef Q_OS_WINDOWS - /* SetThreadDescription was added in 14393. Revisit if we ever start requiring 10. */ - static void *kernel32_handle = NULL; - static HRESULT(WINAPI *pSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription) = NULL; - static dllimp_t kernel32_imports[] = { - // clang-format off - { "SetThreadDescription", &pSetThreadDescription }, - { NULL, NULL } - // clang-format on - }; - if (!kernel32_handle) { kernel32_handle = dynld_module("kernel32.dll", kernel32_imports); if (!kernel32_handle) { kernel32_handle = kernel32_imports; /* store dummy pointer to avoid trying again */ pSetThreadDescription = NULL; + pSetProcessInformation = NULL; } } diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index d4a257887..e93ed9786 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -65,11 +65,7 @@ void plat_delay_ms(uint32_t count) { #ifdef Q_OS_WINDOWS - // On Win32 the accuracy of Sleep() depends on the timer resolution, which can be set by calling timeBeginPeriod - // https://learn.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timebeginperiod - timeBeginPeriod(1); Sleep(count); - timeEndPeriod(1); #else QThread::msleep(count); #endif