Monotonic Clocks – the Right Way to Determine Elapsed Time

If you want to display the time to a user of your program, you query the time of day. However, if your program needs to measure elapsed time, you need a timer that will give the right answer even if the user changes the time on the system clock.

The familiar system clock which tells the time of day is referred to as a real-time clock or a wall-clock. The time on this clock will jump when changed. Relying on the wall-clock to find out how much time has passed since a previous event is a bug waiting to happen.

For example, suppose your application carries out an operation in response to some event, but it only does that operation if it is more than an hour since the last time it carried out that operation, otherwise it does nothing. Maybe the operation is some kind of clean-up task. Suppose the user made a typo and set the wrong month on the system clock before your program started; they might then later fix that. Suppose the date is now a month earlier than when your program started, it will be a month until your program thinks that it should carry out its clean-up operations again!

To safely measure elapsed time in a program, you need a clock that ticks out time continuously, without any jumps when a user sets the system time. This kind of clock is called a monotonic clock. This article takes a look at the different monotonic clock functions available in the Windows and POSIX APIs, and the cross-platform routines introduced in C++11.

Windows

 High Resolution Timer

The QueryPerformanceCounter() function is used to determine elapsed time to a high resolution on Windows. The units of this timer are system-dependent, and must be determined using the QueryPerformanceFrequency function to translate into seconds, though better than microsecond resolution can be expected. The accuracy may not be as good as the resolution implies, but nonetheless QueryPerformanceCounter is one of the better options for precision timing on Windows.

On my PC the frequency is reported as 2734443, which is low enough that you won’t have to worry about the ticker wrapping around to zero again during the life of your application. The value reported by QueryPerformanceFrequency() should be cached in performance-critical contexts as it takes relatively long to compute. You will find suggestions in some places that multi-core or multi-CPU environments might report different QueryPerformanceFrequency() frequencies on different cores/CPUs, but this seems to be a problem only on older versions of Windows, according to this MSDN page on the subject.

Milliseconds Timer

The GetTickCount64 function uses constant units of milliseconds. Whilst the resolution isn’t as good as QueryPerformanceCounter(), it is more convenient for typical scenarios where you only need the elapsed time to, for example, the nearest second. Do NOT use GetTickCount() (note the lack of “64”) which uses a 32-bit unsigned integer for the counter, and so wraps around every 49 or so days! If you are using GetTickCount() in your existing code, you might want to replace it with GetTickCount64() (and adjust as necessary for the changed integer return type) or else you may get some difficult-to-debug errors occurring every few weeks.

POSIX

On POSIX, you’ll want the clock_gettime() function. clock_gettime() can be used to retrieve the time from various clocks, including the real-time clock. The clocks are identified by a clockid_t which is the first parameter of the function. For our purposes, we’re interested mainly in CLOCK_MONOTONIC, but on your POSIX system there may be other clocks that are appropriate for your use case.

For example, on Linux you may want to consider whether to use CLOCK_MONOTONIC_RAW as it is not subject to NTP adjustments, but note that CLOCK_MONOTONIC is only subject to incremental corrections, not sudden jumps, so CLOCK_MONOTONIC_RAW would be relevant mainly to cases where more accurate time is wanted over very short intervals, and CLOCK_MONOTONIC would be preferable for longer-term timers measured in minutes, hours or days.

C++ Standard Library

C++11 has brought us a selection of new clock routines, including the monotonic steady_clock class. This has the advantage over the Windows- or POSIX-specific approaches that you only need to code one solution that will work on all platforms.

However, the implementation of steady_clock in Visual Studio is NOT monotonic (though apparently this bug is slated to be fixed in the next release after Visual Studio 2013), which rather undermines the cross-platform advantage for now.

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someonePrint this page

Comments are closed