3

I have a application where I use the MinGW implementation of gettimeofday to achieve "precise" timing (~1ms precision) on Win7. It works fine.

However, when using the same code (and even the same *.exe) on Win10, the precision drops drastically to the famous 15.6ms precision, which is not enough for me.

Two questions: - do you know what can be the root for such discrepancies? (is it a OS config/"features"?) - how can I fix it ? or, better, is there a precise timer agnostic to the OS config?

NB: std::chrono::high_resolution_clock seems to have the same issue (at least it does show the 15.6ms limit on Win10).

cyrobin
  • 146
  • 1
  • 11
  • 2
    15.6 is the normal value, it is your Win7 install that was misbehaving. Call timeBeginPeriod() or use QueryPerformanceCounter() to get sub-microsecond resolution. QPF is best. – Hans Passant Apr 18 '16 at 15:25
  • How can a "misbehaviour" perform better? Does this come from a configuration option? – cyrobin Apr 18 '16 at 16:12
  • 1
    Normal and "better" have opposing goals. It is rough on power usage, you'll drain a laptop battery in a hurry. Not configuration, usually a program or driver that calls timeBeginPeriod(). [Chrome is notorious for doing this](http://blog.codinghorror.com/why-does-windows-have-terrible-battery-life/). Run powercfg -energy to find the troublemaker on Win7. – Hans Passant Apr 18 '16 at 16:18
  • Oh, the power usage settings make sense from what I know of the various distinct computer configurations I have tested. Your combined comments answer all aspects of my problem. Thank you. – cyrobin Apr 18 '16 at 16:23

1 Answers1

3

From Hans Passant comments and additional tests on my side, here is a sounder answer:

The 15.6ms (1/64 second) limit is well-known on Windows and is the default behavior. It is possible to lower the limit (e.g. to 1ms, through a call to timeBeginPeriod()) though we are not advise to do so, because this affects the global system timer resolution and the resulting power consumption. For instance, Chrome is notorious for doing this‌​. Hence, due to the global aspect of the timer resolution, one may observe a 1ms precision without explicitly asking for, because of third party programs.

Besides, be aware that std::chrono::high_resolution_clock does not have a valid behavior on windows (both in Visual Studio or MinGW context). So you cannot expect this interface to be a cross-platform solution, and the 15.625ms limit still applies.

Knowing that, how can we deal with it? Well, one can use the timeBeginPeriod() thing to increase precision of some timers but, again, we are not advise to do so: it seems better to use QueryPerformanceCounter() (QPC), which is the primary API for native code looking forward to acquire high-resolution time stamps or measure time intervals according to Microsoft. Note that GPC does count elapsed time (and not CPU cycles). Here is a usage example:

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

QueryPerformanceFrequency(&Frequency); 
QueryPerformanceCounter(&StartingTime);

// Activity to be timed

QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;


//
// We now have the elapsed number of ticks, along with the
// number of ticks-per-second. We use these values
// to convert to the number of elapsed microseconds.
// To guard against loss-of-precision, we convert
// to microseconds *before* dividing by ticks-per-second.
//

ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

According to Microsoft, QPC is also suitable in a multicore/multithread context, though it can be less precise/ambiguous:

When you compare performance counter results that are acquired from different threads, consider values that differ by ± 1 tick to have an ambiguous ordering. If the time stamps are taken from the same thread, this ± 1 tick uncertainty doesn't apply. In this context, the term tick refers to a period of time equal to 1 ÷ (the frequency of the performance counter obtained from QueryPerformanceFrequency).

As additional resources, MS also provides an FAQ on how/why use QPC and an explanation on clock/timing in Windows.

Community
  • 1
  • 1
cyrobin
  • 146
  • 1
  • 11