Page 2 of 2
Posted: Thu Sep 25, 2003 11:50 am
by freak
The problem is, that all values here are 64bit values, but the
calculations are only done with the lowpart of them. So the negative
values are simply the result of too big numbers.
I made a version of the code that calculates everything in 64bit.
Unfortunalety, on about every 2nd call, it returns a wrong value.
(always the same wrong value.)
Do you guys get the same? And does anybody have an idea why?
Here comes the code:
Code: Select all
Structure bit64
LowPart.l
HighPart.l
EndStructure
Procedure CPUSpeed()
DefType.bit64 ulValue, ulTicks, ulFreq, ulStart
QueryPerformanceFrequency_(ulFreq)
QueryPerformanceCounter_(ulTicks)
; ulValue = ulTicks
ulValue\LowPart = ulTicks\LowPart
ulValue\HighPart = ulTicks\HighPart
; ulValue + ulFreq
MOV eax, ulFreq\LowPart
MOV edx, ulFreq\HighPart
ADD ulValue\LowPart, eax
ADC ulValue\HighPart, edx
; ulStart = Processor Timestamp
!RDTSC
MOV ulStart\LowPart, eax
MOV ulStart\HighPart, edx
; While ulTicks <= ulValue
CPU_Loop_Start:
MOV eax, ulTicks\HighPart
CMP eax, ulValue\HighPart
JG l_CPU_Loop_End
JNE l_CPU_Loop_Run
MOV eax, ulTicks\LowPart
CMP eax, ulValue\LowPart
JG l_CPU_Loop_End
CPU_Loop_Run:
QueryPerformanceCounter_(ulTicks)
JMP l_CPU_Loop_Start
CPU_Loop_End:
; eax:edx = Processor Timestamp
; eax:edx - ulStart
!RDTSC
SUB eax, ulStart\LowPart
SBB edx, ulStart\HighPart
; lStart\LowPart = eax:edx / 1000000
MOV ebx, dword 1000000
DIV ebx
MOV ulStart\LowPart, eax
ProcedureReturn ulStart\LowPart
EndProcedure; Takes 1 second to calculate...
For i = 1 To 20
Debug CPUSpeed()
Next i
Timo
Posted: Thu Sep 25, 2003 2:47 pm
by blueb
Timo,
Hmmm... Running your sample I get an error message:
Invalid name: Same as an external command.
I must have a command named CPUSpeed() in one of my libraries... don't know which one.
Renamed it to CPUSpeed2 and got the same as you did: (except the pattern isn't same as yours)
I get:
1707
6002
1707
1707
6002
1707
6002
1707
1707
6002
repeats....
Notice the pattern is: 1, 2, 1, 2, etc.
I commented out your procedure and tried CPUSpeed() (located in one of my libraries) and it returned:
1707
1707, etc. etc.
On another forum, I had read that 'QueryPerformanceCounter' used signed 64-bits of precision, but I'm not sure. This may account for the 1, 2 pattern.
P4 - 1.7 and Win XP Pro
blueb
Posted: Thu Sep 25, 2003 6:11 pm
by jack
for people getting negative results, please try this.
Code: Select all
; from PB forums by Hi-Toro
; post http://jconserv.net/purebasic/viewtopic.php?t=3811&highlight=utility
Structure bit64
LowPart.l
HighPart.l
EndStructure
Procedure CPUSpeed()
DefType.bit64 ulEAX_EDX, ulFreq, ulTicks, ulValue, ulStartCounter, ulResult
QueryPerformanceFrequency_(ulFreq)
QueryPerformanceCounter_(ulTicks)
ulValue\LowPart = ulTicks\LowPart + ulFreq\LowPart
! RDTSC
MOV ulEAX_EDX\LowPart, eax
MOV ulEAX_EDX\HighPart, edx
ulStartCounter\LowPart = ulEAX_EDX\LowPart
While (ulTicks\LowPart <= ulValue\LowPart)
QueryPerformanceCounter_(ulTicks)
Wend
! RDTSC
MOV ulEAX_EDX\LowPart, eax
MOV ulEAX_EDX\HighPart, edx
ulResult\LowPart = ulEAX_EDX\LowPart - ulStartCounter\LowPart
ProcedureReturn ulResult\LowPart / 1000000
EndProcedure; Takes 1 second to calculate...
mhz = CPUSpeed()&$FFFFFFFF
MessageRequester("CPU Speed", "CPU speed: " + Str (mhz) + " MHz", #MB_ICONINFORMATION)
notice that i only changed the line: mhz = CPUSpeed()
to mhz = CPUSpeed()&$FFFFFFFF
Posted: Thu Sep 25, 2003 7:37 pm
by freak
jack:
What should be the effect of those changes?
The number is still negative, and wrong. Even using Stru() helps nothing
here, because the numbers are 64bit, not 32bit.
blueb:
QueryPerformanceCounter_() uses ULARGE_INTEGER, which is defined
as 2 longs or one quad, so it is 64bit.
I can't explain these strange results though.
You have an idea who wrote the lib where your command is in?
Or where to get it?
I'd like to test it to see if the results are correct.
This lib here also containes such a command, and it is right in general,
but the results also are different with each call.
http://www.purearea.net/pb/download/use ... nHware.zip
Timo
Posted: Thu Sep 25, 2003 10:10 pm
by jack
freak you are absolutly right
maybe this will work:
Code: Select all
; from PB forums by Hi-Toro
; post http://jconserv.net/purebasic/viewtopic.php?t=3811&highlight=utility
; inline asm by jack
Structure bit64
LowPart.l
HighPart.l
EndStructure
Procedure CPUSpeed()
OneMillion.l=1000000
DefType.bit64 ulEAX_EDX, ulFreq, ulTicks, ulValue, ulStartCounter, ulResult
QueryPerformanceFrequency_(ulFreq)
QueryPerformanceCounter_(ulTicks)
! fild qword [esp+12] ;ulFreq
! fild qword [esp+20] ;ulTicks
! faddp st1,st0 ;ST0=ulFreq+ulTicks
! fistp qword [esp+28];ST0->ulValue
;ulValue\LowPart = ulTicks\LowPart + ulFreq\LowPart
! RDTSC
! MOV [esp+4], eax ;MOV ulEAX_EDX\LowPart, eax
! MOV [esp+8], edx ;MOV ulEAX_EDX\HighPart,edx
! fild qword [esp+4] ;ulEAX_EDX
! fistp qword [esp+36];ulStartCounter
;ulStartCounter\LowPart = ulEAX_EDX\LowPart
! fild qword [esp+28] ;ulValue
startloop:
! fild qword [esp+20] ;ulTicks
! FCOMP
! FNSTSW ax
! SAHF
! JAE l_endloop
;While (ulTicks\LowPart <= ulValue\LowPart)
QueryPerformanceCounter_(ulTicks)
;Wend
Goto startloop
endloop:
! fstp st0
! RDTSC
! MOV [esp+4], eax ;MOV ulEAX_EDX\LowPart, eax
! MOV [esp+8], edx ;MOV ulEAX_EDX\HighPart,edx
! fild qword [esp+4] ;ulEAX_EDX
! fild qword [esp+36] ;ulStartCounter
! fsubp st1,st0 ;ST0=ulEAX_EDX - ulStartCounter
! fild dword [esp] ;OneMillion
! fdivp st1,st0 ;ST0=(ulEAX_EDX - ulStartCounter)/1000000
! fistp qword [esp+44];ST0->ulResult
;ulResult\LowPart = (ulEAX_EDX\LowPart - ulStartCounter\LowPart)/1000000
ProcedureReturn ulResult\LowPart-2; / 1000000
EndProcedure; Takes 1 second to calculate...
mhz = CPUSpeed()
MessageRequester("CPU Speed", "CPU speed: " + Str (mhz) + " MHz", #MB_ICONINFORMATION)
Posted: Thu Sep 25, 2003 10:57 pm
by Pupil
If you run a loop calling the procedure you trash the FPU stack as you're not POP:ing all the stuff you put on there, so eventully you'll get the wrong results. You can fix this by poping the FPU stack one more time in the 'endloop:' section.
Posted: Thu Sep 25, 2003 11:05 pm
by jack
thanks Pupil

Posted: Fri Sep 26, 2003 3:02 pm
by blueb
Freak:
You have an idea who wrote the lib where your command is in?
Or where to get it?
I'd like to test it to see if the results are correct.
I located the command in the UserLibrary file: HelpFuncs
Don't know who wrote it, but when I opened it in an editor the coder who wrote it spells 'convert' as 'konvert' as in: konvert a Long to a binary
I suspect it is someone from the german forum.... just a guess
HTH,
blueb
Final version?
Posted: Sat Sep 27, 2003 6:03 pm
by Hi-Toro
Could someone post a final working version? I don't really know assembly, so I have no idea how to 'pop a stack'...

Re: Final version?
Posted: Sat Sep 27, 2003 8:16 pm
by Pupil
Hi-Toro wrote:Could someone post a final working version? I don't really know assembly, so I have no idea how to 'pop a stack'...

jack edited the code in his previous post so it all should work fine now, no need for you to pop anything

Cool
Posted: Sun Sep 28, 2003 2:44 am
by Hi-Toro
Thanks all -- see how we all benefit by sharing stuff?

Posted: Sat Mar 26, 2005 12:49 pm
by Rescator
Here is a alternative to the above routine.
Seems to work pretty accurately!
Lemme know if it matches what you think the CPU speed in Mhz is.
NOTE! You will get various results due to the overhead of actually calling procedures/functions like Delay() etc.
But the result variations should be within a few MHz, like most Mhz results.
(This is no exact sience
Code: Select all
Procedure.l GetCpuMhz()
Global int64val.LARGE_INTEGER
!FINIT
!rdtsc
!MOV dword [v_int64val+4],Edx
!MOV dword [v_int64val],Eax
!FILD qword [v_int64val]
Delay(1000)
!rdtsc
!MOV dword [v_int64val+4],Edx
!MOV dword [v_int64val],Eax
!FILD qword [v_int64val]
!FSUBR st1,st0
int64val\HighPart=0
int64val\LowPart=1000000
!FILD qword [v_int64val]
!FDIVR st0,st2
!fistp qword [v_int64val]
ProcedureReturn int64val\LowPart
EndProcedure
Debug GetCpuMhz() ;This should be the aprox CPU cycles that occured during the last second.
Debug GetCpuMhz()
Debug GetCpuMhz()
Debug GetCpuMhz()
Posted: Sat Mar 26, 2005 1:04 pm
by Rescator
Here's a fun test to run with the above routine:
Code: Select all
Debug "Doing 60 speed checks, should take aprox 1 minute."
c=0
For i=1 To 60
Debug i
c=c+GetCpuMhz()
Next
Debug ""
Debug "Cpu average speed: "+Str(c/60)+" Mhz"
Modern cpu's can change their speeds.
So if you makea game or program that depends on the cpu's speed.
Checking the Mhz at statup, but also now and again during (or between) certain tasks
should ensure that the cpu hasn't throttled down,
and if it has then you'll know it at least and can adapt the code to the lower speed
