Click to See Complete Forum and Search --> : [RESOLVED] CPU Clock Frequency


ovidiucucu
August 22nd, 2004, 08:08 AM
Next function uses high-resolution performance counter and RDTSC (read time-stamp counter) instruction to get the CPU frequency.
UINT CPU::GetCPUFrequency()
{
LARGE_INTEGER nCntFrequency;
if(!::QueryPerformanceFrequency(&nCntFrequency))
{
return 0; // high-resolution performance counter
// not supported
}
LARGE_INTEGER nCnt0, nCnt1;
ULONG nTs0, nTs1;

HANDLE hThread = ::GetCurrentThread();
int nPriority = ::GetThreadPriority(hThread);
::SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
::QueryPerformanceCounter(&nCnt1);

__asm
{
_emit 0x0f _asm _emit 0x31 // RDTSC
MOV nTs0, EAX
}
nCnt0.LowPart = nCnt1.LowPart;

while(((ULONG)nCnt1.LowPart - (ULONG)nCnt0.LowPart) < 10000)
{
::QueryPerformanceCounter(&nCnt1);
__asm
{
_emit 0x0f _asm _emit 0x31 // RDTSC
MOV nTs1, EAX
}
}
::SetThreadPriority(hThread, nPriority);

ULONG nCycles = nTs1 - nTs0;
ULONG nTicks = (ULONG)nCnt1.LowPart - nCnt0.LowPart;
nTicks *= 10000;
nTicks /= (nCntFrequency.LowPart / 100);

UINT nFrequency = nCycles / nTicks;
return nFrequency; // MHz
}
The problem is that from some reasons the result is not exact.
QUESTION: Does anybody know if there is another more accurate method, i.e. to read the exact frequency from somewhere?

indiocolifa
August 22nd, 2004, 04:17 PM
what do you mean with not exact?

ovidiucucu
August 25th, 2004, 03:12 AM
what do you mean with not exact?
Well, in my question, "not exact" it's a little bit "not corect". Sorry!

So reformulating:
Just... does anybody know another method(s) to get the processor frequency?

marsh_pottaye
September 9th, 2004, 03:42 AM
Next function uses high-resolution performance counter and RDTSC (read time-stamp counter) instruction to get the CPU frequency.
UINT CPU::GetCPUFrequency()
{
LARGE_INTEGER nCntFrequency;
if(!::QueryPerformanceFrequency(&nCntFrequency))
{
return 0; // high-resolution performance counter
// not supported
}
LARGE_INTEGER nCnt0, nCnt1;
ULONG nTs0, nTs1;

HANDLE hThread = ::GetCurrentThread();
int nPriority = ::GetThreadPriority(hThread);
::SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
::QueryPerformanceCounter(&nCnt1);

__asm
{
_emit 0x0f _asm _emit 0x31 // RDTSC
MOV nTs0, EAX
}
nCnt0.LowPart = nCnt1.LowPart;

while(((ULONG)nCnt1.LowPart - (ULONG)nCnt0.LowPart) < 10000)
{
::QueryPerformanceCounter(&nCnt1);
__asm
{
_emit 0x0f _asm _emit 0x31 // RDTSC
MOV nTs1, EAX
}
}
::SetThreadPriority(hThread, nPriority);

ULONG nCycles = nTs1 - nTs0;
ULONG nTicks = (ULONG)nCnt1.LowPart - nCnt0.LowPart;
nTicks *= 10000;
nTicks /= (nCntFrequency.LowPart / 100);

UINT nFrequency = nCycles / nTicks;
return nFrequency; // MHz
}
The problem is that from some reasons the result is not exact.
QUESTION: Does anybody know if there is another more accurate method, i.e. to read the exact frequency from somewhere?
I have tested your function and the result was exact as expected :thumb:

ovidiucucu
September 9th, 2004, 08:19 AM
I have tested your function and the result was exact as expected :thumb:
Well, I have already said...
Anyhow, thanks for testing ;) :thumb:

janwas
October 3rd, 2004, 10:17 PM
Discussion here, on the Win32asm board: http://board.win32asmcommunity.net/viewtopic.php?t=10495

HTH

neolox
April 8th, 2005, 03:49 AM
Hi,

Here are several ideas:

1. To correct result move RDTSC from "while" cycle like this

while(((ULONG)nCnt1.LowPart - (ULONG)nCnt0.LowPart) < 10000)
{
::QueryPerformanceCounter(&nCnt1);
}
__asm
{
_emit 0x0f _asm _emit 0x31 // RDTSC
MOV nTs1, EAX
}

2. Use Sleep function when QueryPerformanceFrequency fails

3. For Windows NT such an info can be found in HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0

texasdiaz
May 19th, 2005, 01:42 PM
1. To correct result move RDTSC from "while" cycle like this

while(((ULONG)nCnt1.LowPart - (ULONG)nCnt0.LowPart) < 10000)
{
::QueryPerformanceCounter(&nCnt1);
}
__asm
{
_emit 0x0f _asm _emit 0x31 // RDTSC
MOV nTs1, EAX
}

That's even worse. What you want is to grab the RDTSC as fast as possible so that your cycle measurement and RDTSC value is read as close as possible - that's the whole reason for making the thread a TIME_CRITICAL thread in the first place, so you're not preempted between calls. The problem with your solution is branch prediction; in all Intel chipsets you pay a high price when branch prediction fails which will cause the read of the cycles and read of the RDTSC to be even further away from one another. Remember, the point isn't to get as close to 10000 cycles as possible, it's to get enough time elapsed such that the frequency calculation actually means something.



2. Use Sleep function when QueryPerformanceFrequency fails

All Sleep functions are based on timer interrupts; timer interrupts occur in the system excruciatingly far apart from one another, sometimes between 10 and 20 milliseconds apart. Sleep functions would do you no good to find anything out about the processor frequency.



3. For Windows NT such an info can be found in HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0
Interesting. I didn't know about this key, too bad other OS's don't have this for each processor.

The kicker is that there is a skew between processors in a multiprocessor system, so you still need to know which processor it is you're taking information from. One thread can be assigned to one processor, another thread using that data can be assigned to a different processor. Also, you must be careful, laptop systems and some chips with smart power management will actually slow down when they get hot or they go to sleep. When they wake back up, there's a "leap" the processor makes in the "cycles" to compensate for the time it was down. This "leap" might make you think you've got more time than there really was between two reads of the RDTSC.

Does anyone have a better solution for a high performance counter than this (other than a hardware solution from a plug-in card)?

ovidiucucu
July 10th, 2005, 10:35 AM
Resolved. :)