PDA

View Full Version : CPU clock speed


MA]Mestre
07-11-2003, 06:47 AM
Helo,

I need some help, ż someone knows how to obtain the CPU clock speed ( Programing WinX ) ? I think that Win32API don't have a api function to resolve it, but i saw very much programs that obtain it.

Thanks.

Dia Kharrat
07-11-2003, 10:49 AM
You can use assembly to calculate the CPU clock speed using the 'rdtsc' instruction.


#include <stdio.h>
#include <windows.h>

DWORD GetCPUSpeed();

int main() {
DWORD TheSpeed;

if (TheSpeed = GetCPUSpeed())
printf("CPU Speed: %u MHz\n", TheSpeed);
else
printf("Your hardware does not support a high-resolution counter.\n");

return 0;
}


DWORD GetCPUSpeed() {
LARGE_INTEGER ulFreq, ulTicks, ulValue, ulStartCounter, ulEAX_EDX;

// Query for high-resolution counter frequency (this is not the CPU frequency):
if (QueryPerformanceFrequency(&ulFreq)) {
// Query current value:
QueryPerformanceCounter(&ulTicks);
// Calculate end value (one second interval); this is (current + frequency)
ulValue.QuadPart = ulTicks.QuadPart + ulFreq.QuadPart;
// Read CPU time-stamp counter:
__asm RDTSC
// And save in ulEAX_EDX:
__asm mov ulEAX_EDX.LowPart, EAX
__asm mov ulEAX_EDX.HighPart, EDX
// Store starting counter value:
ulStartCounter.QuadPart = ulEAX_EDX.QuadPart;
// Loop for one second (measured with the high-resolution counter):
do {
QueryPerformanceCounter(&ulTicks);
} while (ulTicks.QuadPart <= ulValue.QuadPart);
// Now again read CPU time-stamp counter:
__asm RDTSC
// And save:
__asm mov ulEAX_EDX.LowPart, EAX
__asm mov ulEAX_EDX.HighPart, EDX
// Calculate number of cycles done in interval; 1000000 Hz = 1 MHz
return (DWORD) ((ulEAX_EDX.QuadPart - ulStartCounter.QuadPart) / 1000000);
} else {
// No high-resolution counter present:
return 0;
}
}

davepermen
07-11-2003, 11:24 AM
very nice piece of code.. i've played around with it (2209 MHz here..:D)

by dividing through some value, we can make it run much faster (1sec is so slow... at least, to just wait and do nothing..)

..ulValue.QuadPart = ulTicks.QuadPart + ulFreq.QuadPart/16;..
..return (DWORD)((ulEAX_EDX.QuadPart - ulStartCounter.QuadPart)*16/1000000);..

for example.. i tested it by dividing trough 256, and still got 2209 MHz.. and you could call it 256 times per second.. quite fine, not?..

just a suggestion..

you should store the value in the end anyways, and use it directly.. if you need to.

MA]Mestre
07-15-2003, 02:27 AM
:lol: great piece of code !!! Thanks apex.

Maybe u can explain me how works 'rdtsc' instruction, my assembler is old ( 8086 :P ).

I need to bring up to date about asm, some URL, pdf ?

thanks.

davepermen
07-15-2003, 02:31 AM
google("rdtsc");
RDTSC Read Time Stamp Counter

Mnemonic: RDTSC
Opcode : 0F 31
Bug in : Poorly documented for Pentium Processor

Function:
RDTSC reads a Pentium internal 64 bit register which is being incremented
from 0000 0000 0000 0000 at every CPU internal clockcycle. Note that this
gives a clockcycle-accurate timer with a range of more than 8800 years at
66 Mhz...

The instruction places the counter in the EDX:EAX register pair.


source (http://tamerlan.it.nsc.ru/~michael/x86/86bugs/bugs048.htm)

DrunkenCoder
07-30-2003, 12:51 AM
Here's my verision of GetCPUSpeed

#include <limits.h>
#include <time.h>

static const unsigned g_uClocksPerSec = CLOCKS_PER_SEC;

#if UINT_MAX == 0xFFFFFFFF
typedef unsigned uint32_t;
#else
#error can't define uint32_t
#endif

uint32_t __declspec(naked) GetCPUSpeed(void)
{
_asm
{
push ebp
call clock
mov ebp, eax

clock_align:
call clock
cmp ebp, eax
je clock_align

mov ebp, eax
rdtsc
push eax
push edx

clock_wait:
call clock
cmp ebp, eax
je clock_wait
//calculate speed
sub eax, ebp
mul g_uClocksPerSec
xchg eax, ebx
rdtsc
pop ecx
sub edx, ecx
pop ecx
sub eax, ecx
div ebx

pop ebp
ret
}
}


It doesn't require highperformance counters and at least for me it retains the
same accurcy. Also if you split it up so you put the prototype in one file and the
implementation in a seprate file the static keywords effectivly gets rid of the global outside that unit so that won't be a problem.

davepermen
07-30-2003, 02:29 AM
how accurate is clock? milliseconds?

there are such a big amount of timers out there.. though.. :D i always loved to use timeGetTime..

DrunkenCoder
07-30-2003, 02:56 AM
well have a look at CLOCKS_PER_SEC it can be anything from 18 on DOS to 1000 in most Windowses, the resolution on the system Im currently on is 10ms.

davepermen
07-30-2003, 03:09 AM
ok.. well, i think i'll code a portable one.. one with SDL_Ticks() to copy into the code snippets finally.. and some other changes, possibly.. you'll see..

DrunkenCoder
07-30-2003, 05:22 AM
:blink: :unsure: :blink:
say what? the hard part about making it cross-platform is
the inline asm I guess doesn't GCC use AT&T syntax
I think the easiest part would actually be to port it over to
nasm and change the function prototype to:

uint32_t GetCPUSpeed( uint32_t (*timer_fun), uint32_t uScaleFactor);

then the user can freely choose to use clock, timeGetTime, SDL_Ticks
or whatnot, and also have full control (via his/her own timer function) over
how long time it takes to execute and precision.

Looking forward to see what you come up with

davepermen
07-30-2003, 05:52 AM
uhm, i ment crossplatform, not crosscompiler:D there's an intel c++ compiler for windows, and one for linux.. thats enough support for the major os on x86, on others you need another asm anyways:D

hehe:D

i just write a clean version, and i'll use the sdl timer for it.. there is not much not clean here, but why not rewriting while i don't have anything else to do? :D

DrunkenCoder
07-30-2003, 06:10 AM
While basicly correct Im quite sure that the Linux crowd would kill you for making them use a propitary compiler ;)

But Im eagerly awaiting your new version

davepermen
07-30-2003, 06:22 AM
linux is proprietary anyways.. just some tools here, and some tools there, hacked together.. :D (i think i could get shot for that, couldn't i?:D)

no, sure.. but i think every modern compiler should allow __asm {} blocks. they are so handy..

DrunkenCoder
07-30-2003, 06:25 AM
don't quote me on this but I think GCC understands _asm("asm here");
the problem being that it uses AT&T syntax

but stop posting and get working on that updated version Im curious ;)

davepermen
07-30-2003, 06:40 AM
AT&T syntax?

DrunkenCoder
07-30-2003, 06:44 AM
basicly it's like Intel syntax with everything in reverse and $% stuff littred
everywhere.

In general Intel syntax look like this:

mnemoic dst, src

while AT&T looks like this:
mnemonic src, dst

most motorola assemblers tend to use the AT&T syntax GAS and GCC does
to, or at least did the last time I checked.

davepermen
07-30-2003, 06:51 AM
urgh..

DrunkenCoder
07-30-2003, 07:29 AM
urgh..
Well I can't do much else than to agree with you there :rolleyes:

davepermen
07-30-2003, 07:41 AM
great..

(*URGH*)

zenogais
08-09-2004, 10:41 AM
Sorry to revive an old thread, but here's a version I worked on with a bit less assembly. This snippet is from a dynamic recompiler for a emulator I was working on, its nice because its also cross-platform:



// Type Definitions (From Header)
#if defined(__WIN32__)

...
typedef __int32 ChipRec_s32; ///< 32 bit signed integer
typedef __int64 ChipRec_s64; ///< 64 bit signed integer
...
typedef unsigned __int32 ChipRec_u32; ///< 32 bit unsigned integer
typedef unsigned __int64 ChipRec_u64; ///< 64 bit unsigned integer
...

#elif defined(__LINUX__)

...
typedef long ChipRec_s32; ///< 32 bit signed integer
typedef long long ChipRec_s64; ///< 64 bit signed integer
...
typedef unsigned long ChipRec_u32; ///< 32 bit unsigned integer
typedef unsigned long long ChipRec_u64; ///< 64 bit unsigned integer
...

#endif

// Source File

ChipRec_s64 getCPUTick() const
{
//================================================== =
// Use RDTSC To Read CPU Time Stamp Counter
//================================================== =
#if defined (__WIN32__)
__asm rdtsc;
#elif defined (__LINUX__)
ChipRec_s64 s64Ret;
__asm__ __volatile__ ("rdtsc" : "=A"(s64Ret):);
return s64Ret;
#endif
}

#ifdef __LINUX__

#include <sys/time.h>

ChipRec_u32 timeGetTime( void )
{
//================================================== =
// Using Linux Time Functions To Determine Time
//================================================== =
struct timeval tv;
gettimeofday( &tv, 0 );
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

#endif

int getCPUSpeed(ChipRec_s32 nTime)
{
//================================================== =
// Check If Process Time Stamp Counter Is Supported
//================================================== =
ChipRec_s64 timeStart, timeStop;
ChipRec_s64 startTick, endTick;
ChipRec_s64 overhead;

if(!sX86ProcessorInfo.hasTimeStampCounter)
{
return 0;
}

//================================================== =
// Calculate CPU Tick Function Call Overhead
//================================================== =
overhead = getCPUTick() - getCPUTick();

//================================================== =
// Calculate Starting Time And Start Tick
//================================================== =
timeStart = timeGetTime();
while(timeGetTime() == timeStart)
{
timeStart = timeGetTime();
}

while(1)
{
timeStop = timeGetTime();
if((timeStop - timeStart) > 1)
{
startTick = getCPUTick();
break;
}
}

//================================================== =
// Calculate Stop Time And End Tick
//================================================== =
timeStart = timeStop;
while(1)
{
timeStop = timeGetTime();
if((timeStop - timeStart) > nTime)
{
endTick = getCPUTick();
break;
}
}

//================================================== =
// Return The Processors Speed In Hertz
//================================================== =
return (int)((endTick - startTick) + (overhead));
}


The variable sX86ProcessorInfo.hasTimeStampCounter is read from the processor using the CPUID instruction. It doesn't really have to be checked, as the only CPUs without the time-stamp counter, are pre-pentium chips IIRC.

swamisniper
03-29-2007, 03:26 PM
can u give us a code for linux? i tryed to compile ur code with gcc ...but it gives errors...i think is because of the asm and how is used in the .c file :) tank u
i searchd all the internet for a code for calculating cpu frequency and when i found it...damn:)

Reedbeta
03-29-2007, 04:00 PM
What errors are you getting? As you can see, that code snippet has conditional compilation sections for Linux...

You didn't forget to remove the '...'s did you? ;)

swamisniper
03-29-2007, 07:49 PM
ggg.c:26: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘getCPUTick’
ggg.c:56: error: expected ‘)’ before ‘nTime’

swamisniper
03-29-2007, 07:50 PM
did u tryed to compile it like it is?

Reedbeta
03-29-2007, 09:56 PM
Oh, I think I see the problem - there's an extra 'const' after the parameter list of getCPUTick, which doesn't make sense in this context.

Remove that, and the only error you get is about 'sX86ProcessorInfo.hasTimeStampCounter', which as zenogais points out doesn't really need to be checked these days (that whole if statement can be dropped).

swamisniper
03-30-2007, 02:47 AM
damn...i removed both the const and the test for that X86 and i have the same problems

.oisyn
03-30-2007, 04:08 AM
Old post, but:

You can use assembly to calculate the CPU clock speed using the 'rdtsc' instruction.
Of course nowadays, with dual core and even quad core processors becoming mainstream, this code is pretty unsafe as each core has it's own TSC register. If a thread switch happens during measurement and your thread continues to run on a different CPU, the determined speed is just bogus.

To circumvent, you should set the thread affinity mask to the CPU you wish to measure :)

Reedbeta
03-30-2007, 09:00 AM
It compiles fine for me. Maybe your gcc is broken? Also, you didn't forget to remove the lines that say '...' did you?

swamisniper
03-30-2007, 06:03 PM
ggggg.c:15: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘getCPUTick’
ggggg.c:40: error: expected ‘)’ before ‘nTime’

same problems...i removed the const thing and the dots...and nothing...:|
what distro do u use?