This simple little C++ class wraps Kernel32's QueryPerformanceCounter API.
Usage is straightforward:
CHiResTimer hrt; hrt.Start(); DoSomethingLengthy(); hrt.Stop(); printf("%I64u", hrt.GetElapsedMicroseconds());
The hi-res timer API deals in unsigned, 64-bit integer values, so the problem of rollover (or "lapping") is not really an issue -- even on a box with a 1GHz timer frequency, 500 years will pass by before the counter laps its start position.
However, not all systems support the hi-res timer API (pre-Pentium II? non-Intel?). The IsSupported method can be used to determine this, at run-time.
Finally, because it can be somewhat awkward to comment-out all of the references to CHiResTimer (4 non-contiguous lines, in the above trivial example!) I've included a handy preprocessor symbol (NOTIMER) to render the class inert.
#pragma once
namespace Util
{
class CHiResTimer
{
// Construction
public:
CHiResTimer()
{
#ifndef NOTIMER
a = b = 0Ui64;
::QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>(&f));
#endif
}
// Properties
public:
bool IsSupported() const
{ return ( ( f == 0) ? false : true); }
unsigned __int64 GetElapsedTicks() const
#ifndef NOTIMER
{ return (b-a); }
#else
{ return 0Ui64; }
#endif
unsigned __int64 GetElapsedMicroseconds() const
#ifndef NOTIMER
{
unsigned __int64 d = (b-a);
if (d < 0x10c6f7a0b5edUi64) // 2^64 / 1e6
return (d*1000000Ui64)/f;
else
return (d/f)*1000000Ui64;
}
#else
{ return 0Ui64; }
#endif
unsigned __int64 GetFrequency() const
#ifndef NOTIMER
{ return f; }
#else
{ return 1Ui64; }
#endif
// Methods
public:
void Start()
{
#ifndef NOTIMER
::Sleep(0);
::QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>(&a));
#endif
}
unsigned __int64 Stop()
{
#ifndef NOTIMER
::QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>(&b));
return GetElapsedTicks();
#else
return 0Ui64;
#endif
}
// Implementation
protected:
#ifndef NOTIMER
__int64 a, b, f;
#endif
};
}
