on one of the other threads, we were discussing how to measure CPU freq
Edgar had a routine and i wanted to test it, so i put it with a CPU enum routine and made a program
it seems to work pretty well
we'd like to know if it works for you
http://www.masm32.com/board/index.php?action=dlattach;topic=12010.0;id=6547
Works well, well done
Works well for me too. Thanks.
it works but it freezes my system everytime I grabs the speed, which isn't enjoyable. I have some C code somewhere that doesn't freeze your system and accuracy is the same I believe, i'll look for it, thanks for contributing.
i know how to fix that
i am surprised it freezes though
if you use crt functions __kbit and __getch and get rid of my InKyb routine, it should fix it
i have been trying to find a solution to that
Works good here, even if I switch affinity to all 4 cores. CPU usage spikes from 8% to 25% and looking at it with 'process explorer' the
priority switches between 15 and 8.
Why not a window or dialog box instead of the console?
lol - i haven't got that far yet, Sinsi
i have much to learn :'(
Problem seems to be donkeys cpu speed function.
here's 1 that doesnt freeze made by Petroizki, from this thread http://www.masm32.com/board/index.php?topic=3970.0
note I changed FREQ_DIVIDE_POWER_OF_2 to 2 from 4 as MichaelW suggested, and that fixed its slight inaccuracy.
.586
.model flat, stdcall
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
include \masm32\macros\macros.asm
.data
DIVIDOR REAL4 1000000.0
.data?
SPEED dq ?
.code
GetCPUSpeed proc uses ebx edi esi
LOCAL qwCycles:QWORD, qwTimer:QWORD
LOCAL dwPriority:DWORD, hProcess:HANDLE
FREQ_DIVIDE_POWER_OF_2 EQU <2>
lea ebx, [qwTimer]
invoke GetCurrentProcess
mov hProcess, eax
invoke GetPriorityClass, eax
mov dwPriority, eax
invoke SetPriorityClass, hProcess, HIGH_PRIORITY_CLASS
invoke QueryPerformanceFrequency, ebx
test eax, eax
jz @no_timer
mov esi, dword ptr [ebx + 4]
mov edi, dword ptr [ebx]
mov eax, esi
shr edi, FREQ_DIVIDE_POWER_OF_2
shl eax, 32-FREQ_DIVIDE_POWER_OF_2
shr esi, FREQ_DIVIDE_POWER_OF_2
or edi, eax
push ebx
rdtsc
mov dword ptr [qwCycles], eax
mov dword ptr [qwCycles + 4], edx
call QueryPerformanceCounter
add edi, dword ptr [ebx]
adc esi, dword ptr [ebx + 4]
@@: invoke QueryPerformanceCounter, ebx
cmp esi, dword ptr [ebx + 4]
jb @F
cmp edi, dword ptr [ebx]
jnb @B
@@: rdtsc
sub eax, dword ptr [qwCycles]
sbb edx, dword ptr [qwCycles + 4]
mov ecx, eax
shl edx, FREQ_DIVIDE_POWER_OF_2
shr ecx, 32-FREQ_DIVIDE_POWER_OF_2
shl eax, FREQ_DIVIDE_POWER_OF_2
or edx, ecx
mov edi, eax
mov esi, edx
invoke SetPriorityClass, hProcess, dwPriority
mov eax, edi
mov edx, esi
@no_timer:
ret
GetCPUSpeed endp
start:
print chr$("CPU Speed: ")
invoke GetCPUSpeed
mov dword ptr [SPEED], eax
mov dword ptr [SPEED + 4], edx
fild qword ptr [SPEED]
fdiv dword ptr [DIVIDOR]
fstp qword ptr [SPEED]
mov eax, dword ptr [SPEED]
mov edx, dword ptr [SPEED + 4]
invoke crt_printf,chr$("%.2f MHz%c"),edx::eax,10
inkey chr$(13,10,"Press any key to exit...")
ret
end start
i suppose it could be adopted to plug into our current program to test it
we could also replace InKyb with __kbhit and __getch to be on the safe side
you want to do that E^cube - or would you like me to ?
i had formulated another plan for running the measurement, but Edgar's seemed to work
the thing about Edgar's code is, it runs QueryPerformanceCounter in a loop to wait for time to elapse
that hogs CPU time
my plan was to use Sleep to consume the time (which allows the system to execute other code)
then, place a QueryPerformanceCounter before and after the Sleep to get the time (accurate measurement of time)
kind of a "hybrid" approach
initialization
1) use GetProcessAffinityMask, GetPriorityClass, and GetThreadPriority to save the initial settings
2) use pushfd/popfd to test bit 21 of the eflags register to verify the cpu supports cpuid
3) test cpuid function 1, edx bit 4 to verify the cpu supports rdtsc
4) test the rdtsc to verify it updates
5) use QueryPerformanceFrequency to get the frequency of the performance counter
measurement
1) use SetProcessAffinityMask to select core 0
2) use SetPriorityClass and SetThreadPriority as Edgar suggested to elevate priority
3) use cpuid function 0 to serialize instructions
4) use rdtsc to get an initial clock count (save values on the stack)
5) use QueryPerfmanceCounter to get the start time (save values on the stack)
6) use Sleep to consume some specific amount of linear time
7) use cpuid function 0 to serialize instructions
8) use rdtsc to get a terminal clock count (save values on the stack)
9) use QueryPerfmanceCounter to get the stop time (save values on the stack)
10) set thread and process priority back to initial settings
11) set affinity back to initial setting
12) recall the values from the stack
i was going to run the measurement steps repeatedly, alternating between short and long Sleep periods
then, and use the deltas to calculate frequency
it should provide great accuracy; as good as can be obtained by this type of measurement/calculation, i suspect
Quote from: E^cube on August 06, 2009, 09:44:14 AM
here's 1 that doesnt freeze made by Petroizki
CPU Speed: 1600.07 MHz
Works fine but only after I replaced all the includes on top with
include \masm32\include\masm32rt.inc
.586
With the includes by Petroizki, I get loads of error messages, e.g.
\masm32\include\windows.inc(129) : error A2004:symbol type conflict : bool
BOOL typedef DWORD
\masm32\include\windows.inc(7804) : error A2179:structure improperly initialized
SYSTEM_AUDIT_ACE STRUCT
Header ACE_HEADER <>
imask DWORD ?
SidStart DWORD ?
SYSTEM_AUDIT_ACE ENDS
Woks fine for me. Nice job.
works nicely, calculates speed of one of the cores quite accurately but does take like 30% CPU
Quoteit works but it freezes my system everytime I grabs the speed, which isn't enjoyable.
It's doing this to me too, but not every time, just once in a while.
oh i'm guessing it's not freezing my system cause i'm on dual-core but i'm experiencing similar effects. 1 core being almost completely maxed and lagging up the whole system but not to the point of freezing as it would on single-core
Slugsnack,
Well, by freezing I mean maxing out the CPU to where nothing is happening in other programs. I just happened to have some video running when I ran the program and it froze and stuttered for a second or two. I have a dual-core too.
oh that's quite odd. i guess that's occuring cause the video is running or partially doing so on the core that was maxed out running dedndave's program. that would probably make the most sense
in the current version, there is a loop that sets a count and repeatedly reads QueryPerformanceCounter until the terminal count is met
this is all happening with process priority at REALTIME_PRIORITY_CLASS and thread priority at THREAD_PRIORITY_TIME_CRITICAL
in order to give the system a breather, i put a Sleep,1000 in the key-press loop
i am working on a new version that will use Sleep to consume the time (rather than a loop) and use QueryPerformanceounter to measure
it also uses shorter test intervals
this should resolve the hang issues
i also want to use a rolling average to stabilize the readings
just for addition: In the registry you can also read out cpu's frequency. Take a look at "HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0" -> "~MHz".
qWord
that may not be the actual frequency
i am fairly certain that is the CPU's maximum spec
On my Windows 2000 system it's apparently a measured frequency (the value is ~503 MHz, where I measure 503.52 MHz). DxDiag also shows the value ~503 MHz. What does it show on a system with a variable clock speed?
that is interesting
mine says 3000 Mhz, so i just figured it was the max
i wonder if it is set one time at OS installation, or if it is updated regularly (like when the OS throttles)
or, maybe intel had a sale on MHz and Michael has a 503 Mhz chip - lol
Quote from: dedndave on August 07, 2009, 06:40:33 PM
i wonder if it is set one time at OS installation, or if it is updated regularly (like when the OS throttles)
it seems like the measurement (of maximum frequency) takes place at start up: first start: 2135MHz ,second: 2145MHz (Intel c2d)
Quote from: dedndave on August 07, 2009, 05:07:52 PM
that may not be the actual frequency
I don't think that you can measure the current frequency with an loop-based algorithm, because the workload of this algorithm force the CPU\OS to change it frequency.
we seem to have had some success in doing so
we just need to refine our techniques a little
i think the version i am working on now will be fairly accurate and shouldn't cause any system problems
well, that's what i am shooting for, at least :lol
strictly speaking, version 2 is loop-based - it does work on most machines, but hangs on a few
this new one isn't loop-based - a little better approach
don't know about 'maximum' frequency cause mine displayed higher than what it was supposed to be lol
accuracy is not critical for a cpu - variation from the oscillator design freq of +/-0.5% is not unusual
although, running faster can result in more heat, such a small variation is hardly worth mentioning
Hutch has a later version P4 that cuts back the clock frequency when it runs too hot, which is cool :lol
Well, I tried a window and get 2433.5xx/2433.6xx using WM_TIMER with a 1 second period (how accurate is that anyway?). Yours gives me 2400.6xx
I would say yours is more accurate, but it uses a lot of CPU time whereas mine uses bugger-all.
What is the best way to trigger something once a second? In dos I just reprogram the timer, but in win32 (on win64)? Wait functions, timers, ...?
edit: added the (crap) source. qnd.
[attachment deleted by admin]
you could set up a timer callback event
i don't think that is neccessary, though, nor is it going to be all that precise
if you look at my last post on the first page of this thread, you will see what i am woking toward
i am adding a few refinements, though
i intend to use a short measurement period to avoid hogging the cpu
then, i am using a rolling average to acquire accuracy, which should bring stability and resolution with it
that method also allows the display to be updated more often
depending on the rolling average length, it will appear as though the measurement has been taken over a longer period
time permitting, i may finish it today
if someone wants to play with timer events...
http://msdn.microsoft.com/en-us/library/ms644901(VS.85).aspx
Sinsi - on my machine, your program is reading 2.976 to 3.020 Ghz and jumps around quite a bit
you might try applying a rolling average - it may not be all that far off
i like the window, though :bg
i have been playing with QueryPerformanceCounter and QueryPerformanceFrequency
first, the counter is using the cput clock as a time base
second, the frequency always reports the same value, no matter what
any calculations made with those two functions are going to be boggies
i have managed to make GetSystemTimeAsFileTime give me some meaningful values (with a trick or two)
i seem to be getting fairly accurate values in 100 ms intervals
it will be nice to see how it looks with the rolling average
notice how it alternates between short and long readings (iambic)
i will use the deltas between each set to calculate a new rolling average update value
time clocks
937500 281258640
312500 93747495
937500 281262165
312500 93757388
937500 281264078
312500 93759900
937500 281253563
312500 93757470
937500 281261392
312500 93757583
937500 281262938
312500 93745283
937500 281256442
312500 93748388
937500 281265158
312500 93733035
937500 281263373
312500 93741075
937500 281260110
312500 93759442
937500 281261873
312500 93760418
Quote
first, the counter is using the cput clock as a time base
second, the frequency always reports the same value, no matter what
any calculations made with those two functions are going to be boggies
What is "cput" and why do you expect the performance frequency to vary? IIRC it's 1193182 (the nominal frequency of the PIT clock) under Windows 9x, and 3579546 (1193182*3) under Windows 2000 and later.
cput = central processing unit typo - lol
well, on my machine, for example, it reports 3000002000
if i try to calculate cpu(t) frequency using CountTSC * FrequencyHP / CountHP,
i will always wind up with 3000002000 +/- (variations in measurement code)
not really what we are after
not to worry - GetSystemTimeAsFileTime is working great
CPUFrequency proc cpu:dword
LOCAL Freq:LARGE_INTEGER, cntStart:LARGE_INTEGER, cntEnd:LARGE_INTEGER, tsc:LARGE_INTEGER
invoke GetCurrentThread
invoke SetThreadAffinityMask,eax,cpu
invoke QueryPerformanceFrequency,addr Freq
invoke QueryPerformanceCounter,addr cntStart
rdtsc
mov tsc.LowPart,eax
mov tsc.HighPart,edx
invoke Sleep,50
rdtsc
sub eax,tsc.LowPart
sbb edx,tsc.HighPart
mov tsc.LowPart,eax
mov tsc.HighPart,edx
invoke QueryPerformanceCounter,addr cntEnd
mov eax,cntEnd.LowPart
mov edx,cntEnd.HighPart
sub eax,cntStart.LowPart
sbb edx,cntStart.HighPart
mov cntEnd.LowPart,eax
mov cntEnd.HighPart,edx
fninit
fild cntEnd.QuadPart
push 1000000
fild dword ptr [esp]
fmul
fild Freq.QuadPart
fild tsc.QuadPart
fmul
fxch
fdiv
frndint
fistp dword ptr [esp]
pop eax
ret
CPUFrequency endp
this is a preliminary version of what i have been working toward
i want to clean up the documentation and, perhaps, add a feature or two
in the mean time, it would be great to know if this hangs up on anyones machine
if so, i can adjust a few equates
Works fine on my system - well done
Dave,
Yeah, that's pretty smooth on my system. CPU usage is negligible. :U
DednDave CPU Frequency
CPU 0: Intel(R) Pentium(R) D CPU 3.20GHz MMX SSE3 Cores: 2
CPU Frequency: 3196.960115 MHz
Press any key to exit
No crashes here, just a strange thing
DednDave CPU Frequency
CPU 0: Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz MMX SSSE3 Cores: 4
CPU Frequency: 2399.8145382399.676902
If I time it right when using edit>mark, the display goes a bit funny...
DednDave CPU Frequency
CPU 0: Intel(R) Core(TM)2 Quad CPU Q9550 @ 2.83GHz MMX SSE4.1 Cores: 4
CPU Frequency: 2838.725635 MHz
Press any key to exit
thanks all
yes, Sinsi - that is one of the console window bugs i have been talking about
actually, i think i know how to fix it, or, at least, make it appear to be fixed - lol
i just forgot to put that fix in - i will add it
i tried to design this program so that the user could change affinity and priority using the task manager without messing up
i see that isn't perfect, either - i will have to look into it
for a time-base, i am using GetSystemTimeAsFileTime which doesn't seem like it ought to be very stable
that part seems ok, though
Works accurate for me. (Intel(R) Pentium(R) 4 CPU 3.20GHz MMX SSE3 Cores: 2)
Very good indeed :cheekygreen:
this one should handle the select text a little better
there is no fixing the console window - only taming it slightly
if you mess around with it enough, you can always make it screw up
if you get it into a really screwed up state, you sometimes have to close and open a new window to get it right again
anyways - let me get this one documented so i can put the source up for you guys
EDIT - updated - see the next post
ok - here we go
i added a couple features JUST FOR YOU, Hutch !!! - lol
you can use the arrow keys to change the resolution
you can use the R, G, B, I keys to change the colour
it seems to work very well - i look forward to responses (good or bad - lol)
Masterpiece. :U
thanks Hutch ! :8)
I didnt look over the code so don't know the technique.. but my observations just the same
Most CPU's these days run dynamic frequencies. When under high load they cycle full blast, but when there isnt much system load they step down to a smaller multiple of the base frequency. For example, my 2Ghz Dual Core AMD64 will step down to 1Ghz if its just sitting there mostly idle.
Because of this, I cannot imagine a sampling-based technique that will work reliably that also doesnt pump up the CPU usage to 100% and keep it there for a large number of cycles (long enough for the scheduler to hand time off to the cpu drivers which will step up the processor to max)
i went out of my way to minimize cpu usage
you can observe usage by running the task manager under the performance tab
i keep it low by "consuming" time through use of the Sleep api
during execution of Sleep, the system is free to run other programs or perform house-cleaning, as needed
some of the Sleep periods are used for measurement - others are there just to burn off time
for those periods that are used for measurement, they are preceeded and followed by rdtsc instructions to get clock counts
paired with the rdtsc instructions are GetSystemTimeAsFileTime calls to mark times
that way, the Sleep api is used to consume time, not measure it
here is a simplified version of the code at the heart of the measurement routine
just prior to this code, a single core is selected using SetProcessAffinityMask
after the measurement is complete, the function is used again to restore affinity
notice that the measurement Sleep interval is a variable
the program alternates between long and short intervals and calculates frequency using the deltas
that method minimizes errors due to overhead
the suplimentary amount of time is also consumed with another Sleep call so the total measurement period is always the same
also, there is a dead period between measurements
my current settings are:
total cycle time: 500 ms
short period: 20 ms
long period: 130 ms
;RDTSC core found and selected
;save the initial priority class
FMeas6: INVOKE GetPriorityClass,
CpuFrequencyData.hProc
or eax,eax
jnz FMeas7
mov eax,NORMAL_PRIORITY_CLASS
FMeas7: mov CpuFrequencyData.PrioCls,eax
;elevate priority class
INVOKE SetPriorityClass,
CpuFrequencyData.hProc,
REALTIME_PRIORITY_CLASS
;elevate thread priority
INVOKE SetThreadPriority,
CpuFrequencyData.hThrd,
THREAD_PRIORITY_TIME_CRITICAL
;start with a fresh time-slice
INVOKE Sleep,
0
;get the initial system time
push edx
push eax
INVOKE GetSystemTimeAsFileTime,
esp
mov ebx,[esp]
;wait for it to change
FMeas8: INVOKE GetSystemTimeAsFileTime,
esp
cmp ebx,[esp]
jz FMeas8
;get the TSC start count
xor eax,eax
cpuid
rdtsc
push edx
push eax
;wait for the specified interval
INVOKE Sleep,
CpuFrequencyData.StrtInt
;get the terminal system time
push edx
push eax
INVOKE GetSystemTimeAsFileTime,
esp
mov ebx,[esp]
;wait for it to change
FMeas9: INVOKE GetSystemTimeAsFileTime,
esp
cmp ebx,[esp]
jz FMeas9
;get the TSC stop count
xor eax,eax
cpuid
rdtsc
push edx
push eax
;restore thread priority
INVOKE SetThreadPriority,
CpuFrequencyData.hThrd,
THREAD_PRIORITY_NORMAL
;restore priority class
INVOKE SetPriorityClass,
CpuFrequencyData.hProc,
CpuFrequencyData.PrioCls
can;t u just get the cpu speed from the registry or wmi? that would resolve the problem of smarter cpus slowin down at idle times. None the less thanks for the code, is quite useful.
of course, we can get "a" value from a number of places
but, to know the actual current value, it needs to be measured
i have never tried overclocking my cpu (it's a prescott - not a good cpu for that)
but, that might be one example where measurement is nice
another example is, as with Hutch's new machine, it throttles the clock according to core tempurature
the values stored in the registry or other places are not going to reflect that
if you just want a rough idea of maximum operating frequency, QueryPerformanceFrequency seems like a good source
that value seems to be calculated or estimated at boot-time, and remains constant until the next boot
at any rate (pun), i wanted to see if it could be accurately measured without ring 0 access
EDIT
this is all part of my "learn win-32" process - lol
i wanted to become as comfortable with 32-bit console mode apps as i am with 16-bit dos apps
i have learned the "new" x86 pentium instructions and changes in the fpu (compared with 8087 - lol)
i have also learned a bit about the pe format, obj's, res's, etc
next step is to learn my way around mmx and sse instructions
then, i will be ready to attack gui programming, starting with simple "look and feel" type stuff
after that, i will go whatever direction the apps take me - graphics, ntfs, ring 0, other hardware, etc
Quoteif you just want a rough idea of maximum operating frequency, QueryPerformanceFrequency seems like a good source
Per the PSDK:
Quote
If a high-resolution performance counter exists on the system, you can use the QueryPerformanceFrequency function to express the frequency, in counts per second. The value of the count is processor dependent. On some processors, for example, the count might be the cycle rate of the processor clock.
I can't recall ever testing a system that did not support a high-resolution performance counter, or one where the frequency was not very close to 1193182 (Windows 9x) or 3579546 (Windows 2000/XP).
mine returns 3,000,002,000 - very close to 3 GHz
well, it did the other day, when i was playing with it - lol
QPF() has multiple potential timing sources. You cannot rely on it *ever* being the CPU frequency on arbitrary systems.
On multicore AMD's running XP SP1, the QPF() source was indeed the cpu cycle count. But somewhere along the way between then and XP SP3 and AMD's "dual core optimizer" (which is actualy a windows patch) the source of QPF() changed, configured with the 'USEPMTIMER' switch in boot.ini or whatever.
The problem with the CPU tick count (RDTSC) being used is that if your process migrates cpu's (or even cores in the case of AMD's), the tick count can appear to move backwards since the cpu's tick counters are not in synch. This had caused endless problems for users of older games on multicore systems, because programmers normally assume that time cannot go backwards.. that the calculation (now - then) is always a positive number.
See http://www.google.com/search?hl=en&q=%2Fusepmtimer&btnG=Search&aq=0&oq=&aqi=g10 for a little bit about the USEPMTIMER switch.