Created
July 31, 2021 12:54
-
-
Save Gnomorian/b62ce807e53a2764c420a3ffc09a4ba5 to your computer and use it in GitHub Desktop.
Test timer resolution on windows using TimerQueues. the regular StartTimer function has a resoltion of 15ms, this can go down to 1ms it appears
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <stdexcept> | |
#include <string> | |
#include <memory> | |
#include <vector> | |
#include <chrono> | |
#include <thread> | |
#include <iostream> | |
class TimerQueue | |
{ | |
HANDLE _queue{ getQueueHandle() }; | |
public: | |
constexpr TimerQueue() = default; | |
virtual ~TimerQueue() | |
{ | |
deleteQueueHandle(_queue); | |
} | |
HANDLE beginOneShotTimer(int period, WAITORTIMERCALLBACK callback, PVOID param) | |
{ | |
return createOneShotTimerForQueue(_queue, callback, param, period); | |
} | |
HANDLE beginContinuousTimer(int period, WAITORTIMERCALLBACK callback, PVOID param) | |
{ | |
return createContinuousTimerForQueue(_queue, callback, param, period); | |
} | |
void endTimer(HANDLE timerHandle) | |
{ | |
deleteTimer(_queue, timerHandle); | |
} | |
protected: | |
HANDLE getQueueHandle() | |
{ | |
const auto handle{ CreateTimerQueue() }; | |
if (handle == nullptr) | |
{ | |
const auto result{ GetLastError() }; | |
throw std::runtime_error("CreateTimerQueue error: " + std::to_string(result)); | |
} | |
return handle; | |
} | |
void deleteQueueHandle(HANDLE handle) | |
{ | |
const auto WaitForExecutingTimerCompletion{ INVALID_HANDLE_VALUE }; | |
(void)DeleteTimerQueueEx(handle, WaitForExecutingTimerCompletion); | |
} | |
HANDLE createContinuousTimerForQueue(HANDLE queue, WAITORTIMERCALLBACK callback, PVOID param, DWORD period) | |
{ | |
HANDLE newTimer{}; | |
if (!CreateTimerQueueTimer(&newTimer, queue, callback, param, 0, period, WT_EXECUTELONGFUNCTION)) | |
{ | |
const auto result{ GetLastError() }; | |
throw std::runtime_error("CreateTimerQueueTimer error: " + std::to_string(result)); | |
} | |
return newTimer; | |
} | |
HANDLE createOneShotTimerForQueue(HANDLE queue, WAITORTIMERCALLBACK callback, PVOID param, DWORD period) | |
{ | |
HANDLE newTimer{}; | |
if (!CreateTimerQueueTimer(&newTimer, queue, callback, param, 0, period, WT_EXECUTEONLYONCE | WT_EXECUTELONGFUNCTION)) | |
{ | |
const auto result{ GetLastError() }; | |
throw std::runtime_error("CreateTimerQueueTimer error: " + std::to_string(result)); | |
} | |
return newTimer; | |
} | |
void deleteTimer(HANDLE queue, HANDLE timer) | |
{ | |
const auto WaitForExecutingTimerCompletion{ INVALID_HANDLE_VALUE }; | |
(void)DeleteTimerQueueTimer(queue, timer, WaitForExecutingTimerCompletion); | |
} | |
}; | |
int main() | |
{ | |
auto timerCallback = [](PVOID param, BOOLEAN wait) | |
{ | |
auto events{ static_cast<std::vector<std::chrono::high_resolution_clock::time_point>*>(param) }; | |
events->push_back(std::chrono::high_resolution_clock::now()); | |
}; | |
std::vector<std::chrono::high_resolution_clock::time_point> events; | |
TimerQueue queue; | |
auto start{ std::chrono::high_resolution_clock::now() }; | |
constexpr int period{ 1 }; | |
constexpr std::chrono::seconds samplePeriod{ 1 }; | |
auto timerHandle{ queue.beginContinuousTimer(period, timerCallback, &events) }; | |
std::this_thread::sleep_for(samplePeriod); | |
queue.endTimer(timerHandle); | |
auto end{ std::chrono::high_resolution_clock::now() }; | |
std::cout << events.size() << " timers fired at " << period << "ms resolution over " << samplePeriod.count() << " seconds"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment