Introduction
CPUTest is a just a small class (CCPU
) with a few static
member functions. It calculates the frequency of the CPU in 50ms.
How it works
The idea is pretty simple, and it has been implemented many times. All modern
processors (Pentium+) have a TimeStamp Counter (TSC), which is incremented once
every clock cycle. Read the TSC, delay for some time, read the TSC again and get
the difference of the two Timestamps (the result is in clock cycles). Divide the
cycles by the delay time and you get the frequency.
What's Cool
Most Get-CPU-MHz implementations use Sleep()
to delay. The
problem with Sleep()
is that it's not so accurate, especially when
using it for small delays. You have to delay at least 1000 msecs to get a fair
result.
To overcome this problem, I used the QueryPerformanceFrequency()
and QueryPerformanceCounter()
functions.
Take a look at this function, which is a private member of CCPU.
static void _Delay(unsigned int ms)
{
LARGE_INTEGER freq, c1, c2;
__int64 x;
if (!QueryPerformanceFrequency(&freq))
return;
x = freq.QuadPart/1000*ms;
QueryPerformanceCounter(&c1);
do
{
QueryPerformanceCounter(&c2);
}while(c2.QuadPart-c1.QuadPart < x);
}
This delay function is fairly accurate, even for small periods.
Moreover, there's a _DelayOverhead()
function, which is used by GetMHz()
(see below) to calculate the overhead of calling this function and subtract it
from the result.
Also, the GetMHz()
(see below) function has the ability to change
the Process Priority Class and the Thread Priority, so the results are more
accurate. When finished, it restores the PC and TP to their previous settings.
As a result of all this, a single call to GetMHz()
is enough to get
the MHz of the CPU, and it takes only 50ms to complete!
int mhz = CCPU::GetMHz();
CCPU class Functions
There is only one class, the CCPU
class. It contains only static
member functions and no data.
The functions are:
static unsigned int ReadTimeStampCounterLow();
static unsigned int ReadTimeStampCounterHigh();
static unsigned __int64 ReadTimeStampCounter();
static void ReadTimeStampCounter(unsigned int *uHigh, unsigned int *uLow);
static __int64 GetCyclesDifference(CCPU_FUNC func, unsigned int param);
static int GetMHz(unsigned int uTimes=1, unsigned int uMsecPerTime=50,
int nThreadPriority=THREAD_PRIORITY_TIME_CRITICAL,
DWORD dwPriorityClass=REALTIME_PRIORITY_CLASS);
Conclusion
Hope you find this code useful; sure hope it works ;-).
And by the way, if you run the demo, post your CPU's frequency and the results
you get here, especially if it's totally wrong.