| |
| |
|
|
| #include <windows.h> |
|
|
| #include "common/windows/timer_resolution.h" |
|
|
| extern "C" { |
| |
| NTSYSAPI LONG NTAPI NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution, |
| PULONG CurrentResolution); |
|
|
| |
| NTSYSAPI LONG NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, |
| PULONG CurrentResolution); |
|
|
| |
| NTSYSAPI LONG NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval); |
| } |
|
|
| |
|
|
| #ifndef PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
| #define PROCESS_POWER_THROTTLING_EXECUTION_SPEED 0x1 |
| #endif |
| #ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION |
| #define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x4 |
| #endif |
|
|
| namespace Common::Windows { |
|
|
| namespace { |
|
|
| using namespace std::chrono; |
|
|
| constexpr nanoseconds ToNS(ULONG hundred_ns) { |
| return nanoseconds{hundred_ns * 100}; |
| } |
|
|
| constexpr ULONG ToHundredNS(nanoseconds ns) { |
| return static_cast<ULONG>(ns.count()) / 100; |
| } |
|
|
| struct TimerResolution { |
| std::chrono::nanoseconds minimum; |
| std::chrono::nanoseconds maximum; |
| std::chrono::nanoseconds current; |
| }; |
|
|
| TimerResolution GetTimerResolution() { |
| ULONG MinimumTimerResolution; |
| ULONG MaximumTimerResolution; |
| ULONG CurrentTimerResolution; |
| NtQueryTimerResolution(&MinimumTimerResolution, &MaximumTimerResolution, |
| &CurrentTimerResolution); |
| return { |
| .minimum{ToNS(MinimumTimerResolution)}, |
| .maximum{ToNS(MaximumTimerResolution)}, |
| .current{ToNS(CurrentTimerResolution)}, |
| }; |
| } |
|
|
| void SetHighQoS() { |
| |
| PROCESS_POWER_THROTTLING_STATE PowerThrottling{ |
| .Version{PROCESS_POWER_THROTTLING_CURRENT_VERSION}, |
| .ControlMask{PROCESS_POWER_THROTTLING_EXECUTION_SPEED | |
| PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION}, |
| .StateMask{}, |
| }; |
| SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling, |
| sizeof(PROCESS_POWER_THROTTLING_STATE)); |
| } |
|
|
| } |
|
|
| nanoseconds GetMinimumTimerResolution() { |
| return GetTimerResolution().minimum; |
| } |
|
|
| nanoseconds GetMaximumTimerResolution() { |
| return GetTimerResolution().maximum; |
| } |
|
|
| nanoseconds GetCurrentTimerResolution() { |
| return GetTimerResolution().current; |
| } |
|
|
| nanoseconds SetCurrentTimerResolution(nanoseconds timer_resolution) { |
| |
| const auto DesiredTimerResolution = ToHundredNS(timer_resolution); |
| ULONG CurrentTimerResolution; |
| NtSetTimerResolution(DesiredTimerResolution, TRUE, &CurrentTimerResolution); |
| return ToNS(CurrentTimerResolution); |
| } |
|
|
| nanoseconds SetCurrentTimerResolutionToMaximum() { |
| SetHighQoS(); |
| return SetCurrentTimerResolution(GetMaximumTimerResolution()); |
| } |
|
|
| void SleepForOneTick() { |
| LARGE_INTEGER DelayInterval{ |
| .QuadPart{-1}, |
| }; |
| NtDelayExecution(FALSE, &DelayInterval); |
| } |
|
|
| } |
|
|