How to get an accurate 1 ms timer timer under WinXP

I try to call a function every 1 ms. The problem is that I like to do this with windows. So I tried the multimedia API.

Multimedia API

Source

idTimer = timeSetEvent( 1, 0, TimerProc, 0, TIME_PERIODIC|TIME_CALLBACK_FUNCTION ); 

My result was that most of the time was 1 ms, but sometimes I get a double period. Look at a little punch for about 1.95 ms multimediatimerHistogram http://www.freeimagehosting.net/uploads/8b78f2fa6d.png

My first thought was that maybe my method worked for too long. But I already measured it, and it was not.

Queue Timer API

My next attempt was to use the queud timers APIs with

 hTimerQueue = CreateTimerQueue(); if(hTimerQueue == NULL) { printf("Error creating queue: 0x%x\n", GetLastError()); } BOOL res = CreateTimerQueueTimer( &hTimer, hTimerQueue, TimerProc, NULL, 0, 1, // 1ms WT_EXECUTEDEFAULT); 

But the result was not as expected. Now I get most of the time a 2 ms loop. queuedTimer http://www.freeimagehosting.net/uploads/2a46259a15.png

Measurement

To measure time, I used the QueryPerformanceCounter and QueryPerformanceFrequency methods.

Question

So, now my question is, did someone encounter similar problems under windows and maybe even find a solution?

Thank.

+9
c ++ windows winapi timer real-time
Jul 29 '10 at 9:32
source share
3 answers

Without going into a real-time OS, you cannot expect your function to be called every 1 ms.

On Windows, which is not a real-time operating system (for Linux it looks like), a program that repeatedly reads the current time to the microsecond and saves consistent differences in the histogram has a non-empty bit for> 10 ms! This means that sometimes you will have 2 ms, but you can also get more between your calls.

+5
Jul 29 '10 at 9:47 on
source share
— -

Calling NtQueryTimerResolution() will return a value for ActualResolution. In your case, the actual resolution is almost 0.9765625 ms. This is exactly what you show in the first plot. The second case is about 1.95 ms more precisely Sleep(1) = 1.9531 ms = 2 x 0.9765625 ms

I assume that the interrupt period works for about 1 ms (0.9765625).

And now the problem begins: the timer signals when the required delay has expired.

Say that the value of ActualResolution is set to 0.9765625, the interruption of the system pulse will work with periods of 0.9765625 ms or 1024 Hz, and the Sleep call is made with the required delay of 1 ms. Two scenarios need to be considered:

  • The call was completed <1 ms (ΔT) before the next interruption. The following interrupt will not confirm that the desired time period has expired. Only the next interrupt will cause the call to return. The resulting sleep delay will be ΔT + 0.9765625 ms.
  • The call was completed> = 1ms (ΔT) before the next interruption. The next interrupt will cause the call to return. The resulting sleep delay will be ΔT.

Thus, the result depends on when the call was made, and therefore you can observe the events of 0.98 ms, as well as the events of 1.95 m.

Edit: Using CreateTimerQueueTimer will delay the observation to 1.95 because the timer (interrupt period) is 0.9765625 ms. When the interrupt occurred for the first time, the requested duration of 1 ms did not completely TimerProc , so TimerProc will only start after the second interrupt (2 x 0.9765625 ms = 1.953125 ms> 1 ms). Therefore, the queueTimer graph shows the peak at 1.953125 ms.

Note. This behavior is highly dependent on the underlying hardware.

More information can be found in Project Timestamp on Windows.

+1
Jul 12 2018-12-12T00:
source share

You can try to run timeBeginPeriod (1) at program start and timeEndPeriod(1) before exiting. This could probably increase the accuracy of the timer.

0
Jul 29 2018-10-10T00:
source share



All Articles