Skip to content

Commit

Permalink
[hal] Windows sim: enable HighQoS and honor timer resolution requests
Browse files Browse the repository at this point in the history
By default on Windows 11, power throttling will increase timer resolution
if a window is occluded.  Disable that behavior.  Also enable high QOS to
achieve maximum performance and turn off power saving.

Also use internal APIs to set timer precision to 500 us if available.
  • Loading branch information
PeterJohnson committed Aug 1, 2024
1 parent 685c732 commit 65d622b
Showing 1 changed file with 51 additions and 13 deletions.
64 changes: 51 additions & 13 deletions hal/src/main/native/sim/HAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#ifdef _WIN32
#include <Windows.h>
#pragma comment(lib, "Winmm.lib")
#endif // _WIN32

#include "ErrorsInternal.h"
Expand All @@ -27,6 +26,14 @@
#include "hal/simulation/SimCallbackRegistry.h"
#include "mockdata/RoboRioDataInternal.h"

#ifdef _WIN32
extern "C" NTSYSAPI NTSTATUS NTAPI NtSetTimerResolution(
ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution);
extern "C" NTSYSAPI NTSTATUS NTAPI
NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution,
PULONG CurrentResolution);
#endif // _WIN32

using namespace hal;

namespace {
Expand Down Expand Up @@ -364,19 +371,50 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {

initialized = true;

// Set Timer Precision to 1ms on Windows
// Set Timer Precision to 0.5ms on Windows
#ifdef _WIN32
TIMECAPS tc;
if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
UINT target = (std::min)(static_cast<UINT>(1), tc.wPeriodMin);
timeBeginPeriod(target);
std::atexit([]() {
TIMECAPS tc;
if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
UINT target = (std::min)(static_cast<UINT>(1), tc.wPeriodMin);
timeEndPeriod(target);
}
});
// https://stackoverflow.com/questions/3141556/how-to-setup-timer-resolution-to-0-5-ms
ULONG min, max, current;
NtQueryTimerResolution(&min, &max, &current);

static ULONG currentRes;
NtSetTimerResolution(max, TRUE, &currentRes);
std::atext([]() {
ULONG ignore;
NtSetTimerResolution(currentRes, TRUE, &ignore);
});

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessinformation
// Enable HighQoS to achieve maximum performance, and turn off power saving.
{
PROCESS_POWER_THROTTLING_STATE PowerThrottling{};
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
PowerThrottling.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED;
PowerThrottling.StateMask = 0;

SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling,
&PowerThrottling, sizeof(PowerThrottling));
}

// https://forums.oculusvr.com/t5/General/SteamVR-has-fixed-the-problems-with-Windows-11/td-p/956413
// Always honor Timer Resolution Requests. This is to ensure that the timer
// resolution set-up above sticks through transitions of the main window (eg:
// minimization).
{
// This setting was introduced in Windows 11 and the definition is not
// available in older headers.
#ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION
const auto PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION = 0x4U;
#endif

PROCESS_POWER_THROTTLING_STATE PowerThrottling{};
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
PowerThrottling.ControlMask =
PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
PowerThrottling.StateMask = 0;

SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling,
&PowerThrottling, sizeof(PowerThrottling));
}
#endif // _WIN32

Expand Down

0 comments on commit 65d622b

Please sign in to comment.