Call timeBeginPeriod only once on startup (#6273)

Use SetProcessInformation to make the OS better handle our threads on big/small cores
This commit is contained in:
Cacodemon345
2025-10-04 02:03:11 +06:00
committed by GitHub
parent da018531e0
commit 37edcce1fa
3 changed files with 77 additions and 14 deletions

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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