102

I recently decided that I needed to change from using milliseconds to microseconds for my Timer class, and after some research I've decided that QueryPerformanceCounter is probably my safest bet. (The warning on Boost::Posix that it may not works on Win32 API put me off a bit). However, I'm not really sure how to implement it.

What I'm doing is calling whatever GetTicks() esque function I'm using and assigning it to Timer's startingTicks variable. Then to find the amount of time passed I just subtract the function's return value from the startingTicks, and when I reset the timer I just call the function again and assign startingTicks to it. Unfortunately, from the code I've seen it isn't as simple as just calling QueryPerformanceCounter(), and I'm not sure what I'm supposed to pass as its argument.

Evan Carslake
  • 2,267
  • 15
  • 38
  • 56
Anonymous
  • 4,167
  • 11
  • 47
  • 52
  • 2
    I've taken Ramonster's code snippets and made them into a library here: https://gist.github.com/1153062 for followers. – rogerdpack Aug 18 '11 at 01:13
  • 3
    We've recently updated the documentation for QueryPerformanceCounter, and added additional information proper usage, and answers to FAQ. You can find the updated documentation here http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx – Ed Briggs Feb 20 '14 at 16:12
  • just like to mention [__rdtsc](https://msdn.microsoft.com/en-us/library/twchhe95.aspx), it's what QueryPerformanceCounter uses. – colin lamarre Feb 07 '17 at 22:40

4 Answers4

169
#include <windows.h>

double PCFreq = 0.0;
__int64 CounterStart = 0;

void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
    cout << "QueryPerformanceFrequency failed!\n";

    PCFreq = double(li.QuadPart)/1000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}

int main()
{
    StartCounter();
    Sleep(1000);
    cout << GetCounter() <<"\n";
    return 0;
}

This program should output a number close to 1000 (windows sleep isn't that accurate, but it should be like 999).

The StartCounter() function records the number of ticks the performance counter has in the CounterStart variable. The GetCounter() function returns the number of milliseconds since StartCounter() was last called as a double, so if GetCounter() returns 0.001 then it has been about 1 microsecond since StartCounter() was called.

If you want to have the timer use seconds instead then change

PCFreq = double(li.QuadPart)/1000.0;

to

PCFreq = double(li.QuadPart);

or if you want microseconds then use

PCFreq = double(li.QuadPart)/1000000.0;

But really it's about convenience since it returns a double.

IndustProg
  • 627
  • 1
  • 13
  • 33
Ramónster
  • 2,318
  • 3
  • 17
  • 16
  • 5
    Exactly, what is LARGE_INTEGER? – Anonymous Nov 15 '09 at 23:26
  • 6
    it's a windows type, basically a portable 64 bit integer. It's definition depends on whether the target system supports 64 bit integers or not. If the system doesn't support 64 bit ints then it's defined as 2 32 bit ints, a HighPart and a LowPart. If the system does support 64 bit ints then it's a union between the 2 32 bit ints and a 64 bit int called the QuadPart. – Ramónster Nov 15 '09 at 23:28
  • 1
    Well it returns the number of ticks on the high resolution system clock, which I think is hardware dependant, and that's why you need to use QueryPerformanceFrequency to figure out the frequency of that clock. On my system the frequency is 2,272,000 hz, or about 2.272 ticks per microsecond. – Ramónster Nov 15 '09 at 23:35
  • And I need to include Windows.h? – Anonymous Nov 15 '09 at 23:39
  • So based on your explanation, it returns the timing in milliseconds, but with microsecond precision? – Anonymous Nov 15 '09 at 23:53
  • It's precision is actually based on your system's timer, it should be a little more accurate than microseconds. But yes, the example as I list it will work fine for microsecond timing, or you can change it so 1.0 means 1 microsecond if you would rather think about microseconds. – Ramónster Nov 15 '09 at 23:55
  • I'm getting the time in seconds, but I need microsecond precision. I was using a function that returned the # of milliseconds, which I just divided by 1000 to get the time in seconds, but since I now need microseconds I either needed a timer that returned the # of microseconds or some other unit with microsecond precision. Going to try to implement it now. – Anonymous Nov 15 '09 at 23:57
  • I'm getting extremely small values (e-312). I'm reading around and does being on a laptop have something to do with it? – Anonymous Nov 16 '09 at 00:21
  • Where are you getting small values? – Ramónster Nov 16 '09 at 00:24
  • When I perform m_StartingTime - li.QuadPart (no dividing because from what you showed above it seems that the time is in seconds with a precision of microseconds). – Anonymous Nov 16 '09 at 00:26
  • if you do something like StartCounter(); cout << GetCounter(); then you should get a small value, because there wasn't much time between StartCounter() and GetCounter(). If you do StartCounter(); Sleep(1000); cout << GetCounter(); then it should be about 1 second. – Ramónster Nov 16 '09 at 00:26
  • Well you still need the division, or else you're just going to get the number of ticks the counter has done since m_StartingTime, but you want a standard unit of time. – Ramónster Nov 16 '09 at 00:29
  • If you do the division with integers though you're going to lose precision. The functions I posted handle this correctly, and in my answer I say how to modify them to use seconds as the unit but still giving high precision. – Ramónster Nov 16 '09 at 00:31
  • Ah I understand what the frequency is for now. That definitely worked, but now the difference is 975 which is way too high. I don't think what you described returns in seconds with precision to microseconds. I think it returns # of microseconds. – Anonymous Nov 16 '09 at 00:36
  • My functions as listed return milliseconds, but I say how to modify the StartCounter() function to return seconds with high precision in the answer. – Ramónster Nov 16 '09 at 00:40
  • Well for example you said to use seconds change the /1000 to just assigning PCFreq to the QueryPerformanceFrequency. When I do that I get numbers in the hundreds so that obviously can't be right. – Anonymous Nov 16 '09 at 00:44
  • Try the code sample in my answer, I edited it so if the call to QueryPerformanceFrequency fails then it prints to the screen. – Ramónster Nov 16 '09 at 00:55
  • I don't think it's failing. I've decided I'm just going to stick with milliseconds and round up to 1 millisecond whenever it's 0. The QueryPerformanceCounter is giving very unstable results, i.e the frames are very jumpy and not smooth at all. – Anonymous Nov 16 '09 at 00:58
  • 10
    This answer's badly flawed. QueryPerformanceCounter reads a core specific cycle counter register, and if the thread of execution has been rescheduled on another core, two measurements from QueryPerformanceCounter incorporate not only elapsed time, but often a fixed, large and hard to pinpoint delta between the two cores registers. So - this only works reliably as presented if your process is bound to a specific core. – Tony Delroy Mar 01 '12 at 08:36
  • 2
    I'd suggest to point out that the performance counter frequency is treated as a constant. In fact the value obtained for the frequency deviates from the `const` returned by the call to QueryPerformanceFrequency. [Learn more...](http://stackoverflow.com/a/11537483/1504523) – Arno Aug 29 '12 at 10:14
  • 16
    @TonyD: [MSDN documentation](http://msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx) says: `On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL).` This code isn't badly flawed, but some BIOS or HAL. – Lucas May 22 '13 at 10:32
  • 1
    @Lucas: yes, I've read that before - Microsoft's way of passing the blame. Writing code that relies on something which is known not to work reliably is flawed, whether the bug is in the function's implementation or the way it interacts with the firmware or hardware is irrelevant. Say you use this for frame rate calculations in a game, ship your game, 20% of firm/hardware screws up - do you think the press/customers will say "that's ok - it's a BIOS/HAL issue"? It's sometimes possible to work around this with some load-time cross-core delta measurements, but AFAIK no OSS implementation. – Tony Delroy May 22 '13 at 10:45
  • 4
    @TonyD: I just looked into this a little bit more. I added the following call into the `StartCounter` function: `old_mask = SetThreadAffinityMask(GetCurrentThread,1);` and then set it back at the end `SetThreadAffinityMask ( GetCurrentThread , old_mask ) ;`. I hope that will do the trick. This should prevent my thread from getting rescheduled to anything but the 1st CPU core. (Which is obviously only a solution for a testing environment) – Lucas May 22 '13 at 11:04
  • @Lucas: if that suits your purposes, that's great... sad that this kind of thing is an issue in this day and age, particularly with the other Windows timing functions only being good to ~15ms. – Tony Delroy May 22 '13 at 11:16
  • @TonyD: The problem is, I don't really know what my other options would be if I want to get precise timing. Also, this raises the question how the Visual Studio profiler handles this issue or if it has the same issues. – Lucas May 22 '13 at 11:24
  • @Lucas: what most people do is repeat the operation enough times that the cumulative time gets up towards/into the seconds range, then divide that time by the iteration count. I don't know what the profiler does, but if you've got integration with the OS then you can probably register for kernel info about thread scheduling - bypassing the problem... I believe Visual Studio needs local admin rights for the profiler to run, which would tie in with this. Personally, I do the up-front delta analysis I mention above... wrote it for work though so issues around sharing it. – Tony Delroy May 22 '13 at 11:35
20

I use these defines:

/** Use to init the clock */
#define TIMER_INIT \
    LARGE_INTEGER frequency; \
    LARGE_INTEGER t1,t2; \
    double elapsedTime; \
    QueryPerformanceFrequency(&frequency);


/** Use to start the performance timer */
#define TIMER_START QueryPerformanceCounter(&t1);

/** Use to stop the performance timer and output the result to the standard stream. Less verbose than \c TIMER_STOP_VERBOSE */
#define TIMER_STOP \
    QueryPerformanceCounter(&t2); \
    elapsedTime=(float)(t2.QuadPart-t1.QuadPart)/frequency.QuadPart; \
    std::wcout<<elapsedTime<<L" sec"<<endl;

Usage (brackets to prevent redefines):

TIMER_INIT

{
   TIMER_START
   Sleep(1000);
   TIMER_STOP
}

{
   TIMER_START
   Sleep(1234);
   TIMER_STOP
}

Output from usage example:

1.00003 sec
1.23407 sec
vent
  • 1,033
  • 10
  • 21
2

Assuming you're on Windows (if so you should tag your question as such!), on this MSDN page you can find the source for a simple, useful HRTimer C++ class that wraps the needed system calls to do something very close to what you require (it would be easy to add a GetTicks() method to it, in particular, to do exactly what you require).

On non-Windows platforms, there's no QueryPerformanceCounter function, so the solution won't be directly portable. However, if you do wrap it in a class such as the above-mentioned HRTimer, it will be easier to change the class's implementation to use what the current platform is indeed able to offer (maybe via Boost or whatever!).

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
1

I would extend this question with a NDIS driver example on getting time. As one knows, KeQuerySystemTime (mimicked under NdisGetCurrentSystemTime) has a low resolution above milliseconds, and there are some processes like network packets or other IRPs which may need a better timestamp;

The example is just as simple:

LONG_INTEGER data, frequency;
LONGLONG diff;
data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency)
diff = data.QuadPart / (Frequency.QuadPart/$divisor)

where divisor is 10^3, or 10^6 depending on required resolution.

kagali-san
  • 2,964
  • 7
  • 48
  • 87