An Accurate Timer Class
Environment: Timers, miscellaneous
Introduction
This class supplies an accurate timer (figured in milliseconds). There are two advantages to this class instead of the normal Sleep():
- It can sleep the remaining time of a chosen period, causing exact timeframes
- It's more accurate
The need for this class lies in the fact that I needed to do an action exactly every second. In my case, it is used to communicate with a PLC, and the action has some I/O every second. This can take a considerable amount of time. But, you can use it for any purpose.
When you want something to execute every second, and your action takes 300 ms, you face the problem that with a Sleep(1000) after the action, the complete process takes more then 1300 milliseconds.
A further problem was the accuracy of a Sleep. This is not high. A Sleep of 300ms can take 310ms. a Sleep of 1ms takes at least 8ms. I did a check on different machines; it is always different and always bad.
To avoid this inaccuracy of Sleep, I only used Sleep() to approach the end time up to 15 milliseconds. In the last part, I used a dirty for() loop. Because this loop generates a big CPU usage, I only used this at the very end of the waiting time. Because of the small period, you cannot see any difference in the NT-performance meter.
When you don't need to use this level of accuracy, only the remain sleep function, InitTimer(false), will avoid this for() loop, to the disadvantage of the accuracy.
And How Does It Work Under Water?
The best way for a good timer to operate is to use the QueryPerformanceCounter(). It gives clockpulses. Because this is hardware-dependent, we need to know the frequency (how many pulses per second). This is achieved by using QueryPerformanceFrequency(). QueryPerformanceCounter() works with a struct LARGE_INTEGER, which has some disadvantages when calculating. It's no problem to use a LONGLONG (__int64) and cast it. This saves us from a lot of casting and time-consuming member accesses.
Because my app runs for long times, I looked to the maximum time it could run: We store in a __int64; its maximum val is 9.22337E+18 (=2^63). This is the maximum period we can sleep.
The frequency/divider of a P2-333 MHz is 1,193,180
The frequency/divider of a P4-2.4 GHz is 3,579,545
The worse case is P4. This means we can store a maximum of:
2,576,688,388,288 seconds
42,944,806,471 minutes
715,746,775 hours
29,822,782 days
81,706 years
This is enough for my humble program...
Internal variables are all saved as clockpulses, not in milliseconds. All user input/output is done in milliseconds and translated to/from clockpulses.
The function SleepNow() acts just as an ordinary Sleep() but when you name it the same, there is an unwanted case of recursive programming when you just need ten original Sleep() cycles.
When sleeping, it acts the same as a normal sleep: You cannot interact with the app anymore. You can put it in a separate thread to avoid this. In the test app, I didn't do this. It's just a simple test container about the use of the timer class. In your own app, it's enough to include CKETimer.cpp and CKETimer.h.
To Do
Yes, I left some ends open, so you guys (girls?) out there can extend it with your ideas:
- I don't like the for loop, but I can't think of a process that is short (<1ms) and doesn't boos CPU usage.
- Make it thread safe
- Test it on other OS/PC's (it works on Win98, 2000 and XP, all >= P2)

Comments
It's not SLEEP
Posted by hover on 10/14/2007 08:52pmHi! The for loop can not simulate the sleep(). For sleep(), the sleeping thread will give its cpu time to other threads anyway, while for loop thread will still consume cpu time until the system takes this thread's cpu time due to cpu time scheduling.
ReplyUse OnTimer event from CWnd
Posted by Legacy on 04/23/2003 12:00amOriginally posted by: Francois Cantin
Have you considered using the OnTimer event from CWnd?
ReplyI don't know if it is accurate enough for your purpose but it is very easy to use.
Multimedia Timers
Posted by Legacy on 04/17/2003 12:00amOriginally posted by: John Peloquin
Multimedia timers can also be used to provide accurate timing. Specifically, they can provide resolution of up to 1 millisecond. See the MSDN Library for information.
ReplyGood Work
Posted by Legacy on 04/16/2003 12:00amOriginally posted by: Michael Williamson
> The only thing I could suggest is a bit better
> description of what the functions do. You only call
> TimerRollOver() from your CKETimer class, and I don't
> know why I should call it, so it should be a private
> or protected member.
You are right, but TimerRollOver was only for
debugging purposes: When the timer reaches _int64 maximum, it rolls over to 0 again. this func gives you a notice
(after 82000 years)
I could have ripped it out.
> You call and store the result of CheckFreq(), but I can't
> figure out what it is for. You can never used the stored > result.
The CKETimer class was the thing I wanted to submit.
The Dlg was only meant as a test container, and I used it
for checking the functionality on other PC's and give a
quick view to the use.
> This (TimerTestDlg.cpp line 139)
> m_bAccurate?TRUE:FALSE
> is faster as simply
> m_bAccurate == TRUE
That was a small error: The correct way is:
if (!aTimer.InitTimer(m_bAccurate?true:false))
The MFC wizard binds a BOOL to a checkbox, and I prefer
Replythe use of bool, because it has less memory use and you
are warned when you try to put non-bool values in it.
But when you just mix them, you get a performance warning
when compiling.
This inline if doesn't set m_bAccurate to TRUE, but
when m_bAccurate=TRUE, then the result is true, otherwise
it's false