Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CPUTest

0.00/5 (No votes)
18 Apr 2001 1  
Simple class to calculate the frequency of the CPU in MHz

Sample Image - CPUTest.gif

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.

// Delays for the specified amount of milliseconds

static	void	_Delay(unsigned int ms)
{
   LARGE_INTEGER	freq, c1, c2;
	__int64		x;

   // Get High-Res Timer frequency

	if (!QueryPerformanceFrequency(&freq))	
		return;
		
	// Convert ms to High-Res Timer value

	x = freq.QuadPart/1000*ms;		

   // Get first snapshot of High-Res Timer value

	QueryPerformanceCounter(&c1);		
	do
	{
            // Get second snapshot

	    QueryPerformanceCounter(&c2);	
	}while(c2.QuadPart-c1.QuadPart < x);
	// Loop while (second-first < 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:

// The TSC is 64 bit. This function returns the low part

static unsigned int ReadTimeStampCounterLow();

// This returns the high part

static unsigned int ReadTimeStampCounterHigh();

// Returns the TSC, as an unsigned __int64

static unsigned __int64 ReadTimeStampCounter();

// Puts TSC in uHigh and uLow

static void ReadTimeStampCounter(unsigned int *uHigh, unsigned int *uLow);

// This will call the function 'func' with parameter 'param' and 

// return the difference in clock cycles.

// 'func' must be a pointer to function of this type: 

// void my_func(unsigned int param);

static __int64 GetCyclesDifference(CCPU_FUNC func, unsigned int param);

//

// Returns the MHz of the CPU

//

// Parameter             Description

// ------------------    ---------------------------------------------------

//    uTimes             The number of times to run the test. The function

//                       runs the test this number of times and returns the

//                       average. Defaults to 1.

//    uMsecPerTime       Milliseconds each test will run. Defaults to 50.

//    nThreadPriority    If different than THREAD_PRIORITY_ERROR_RETURN,

//                       it will set the current thread's priority to

//                       this value, and will restore it when the tests

//                       finish. Defaults to THREAD_PRIORITY_TIME_CRITICAL.

//    dwPriorityClass    If different than 0, it will set the current

//                       process's priority class to this value, and will

//                       restore it when the tests finish.

//                       Defaults to REALTIME_PRIORITY_CLASS.

//

// Notes

// -------------------------------------------------------------------------

// 1. The default parameter values should be ok.

//    However, the result may be wrong if (for example) the cache

//    is flushing to the hard disk at the time of the test.

// 2. Requires a Pentium+ class processor (RDTSC)

// 3. Requires support of high resolution timer. Most (if not all) Windows

//    machines are ok.

//

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here