News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

clock speed

Started by allynm, August 04, 2009, 01:58:04 AM

Previous topic - Next topic

allynm

Hi everyone-

I have been looking at the CPUID instruction to see how to extract the clock speed.  I did this because I was very interested in MichaelW's timer programs (which work nicely on my old crummy machine).  I can't figure out from the documentation which registers contain the information after the CPUID call or (not surprisingly!) how to interpret them. 

Thanks,
Mark Allyn

GregL

Here is some good up-to-date documentation.  See chapter 9.

Intel Processor Identification and
the CPUID Instruction



allynm

Greg -

Thanks for alerting me to this document.  I looked thru Chapte 9 as you suggested.  There is reference therein to IA32_MPERF instruction.  Not sure how to determine if this instruction is available to me on my crummy ancient old HP box that crashes for reasons I have never understood.

Thanks,
Mak

dedndave

the CPUID outputs can be somewhat confusing if you try to get the same piece of information from different processors
to get the actual operating frequency, i think you need ring 0 access, though

MichaelW

#4
This is quick and dirty, and since the maximum frequency feature started with the Pentium 4, I have no good, simple way to test it. Also, this is based on an Intel instruction set reference from 2005, so Intel could have changed directions several times by now.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
    .686
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data

        name$       db 64 dup(0)
        multiplier$ db 8  dup(0)
        maxfreq$    db 8  dup(0)
        maxfreq     REAL8 ?

    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    mov eax, 80000000h
    cpuid
    .IF eax & 80000000h

        .IF eax >= 80000004h

            print "Processor Brand String Supported",13,10

            mov eax, 80000002h
            cpuid
            mov DWORD PTR name$,    eax
            mov DWORD PTR name$+4,  ebx
            mov DWORD PTR name$+8,  ecx
            mov DWORD PTR name$+12, edx
            mov eax, 80000003h
            cpuid
            mov DWORD PTR name$+16, eax
            mov DWORD PTR name$+20, ebx
            mov DWORD PTR name$+24, ecx
            mov DWORD PTR name$+28, edx
            mov eax, 80000004h
            cpuid
            mov DWORD PTR name$+32, eax
            mov DWORD PTR name$+36, ebx
            mov DWORD PTR name$+40, ecx
            mov DWORD PTR name$+44, edx

            mov DWORD PTR maxfreq$, ecx
            mov DWORD PTR multiplier$, edx

            print ADDR name$,13,10,13,10

            invoke crt_atol, ADDR maxfreq$
            push eax
            fild DWORD PTR [esp]
            mov DWORD PTR [esp], 1000
            fild DWORD PTR [esp]
            pop eax
            fdiv
            fstp maxfreq

            invoke crt_printf,cfm$("maxfreq = %1.3f %s\n\n"),
                              maxfreq, ADDR multiplier$
        .ENDIF

    .ELSE

        print "Processor Brand String Not Supported",13,10

    .ENDIF

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


All I can find in the new document is a mention of this, not the details that are in the older document, but just the mention probably indicates that the feature is still supported.

Edit:

Corrected some errors in the code. The full brand string is not needed here, but I included it as a test.
eschew obfuscation

dedndave

Hiya Michael
the first time i ran it, i got this....

Processor Brand String Not Supported

i have a prescott, so i know it does
i commented out the outer if/then/endif, because i do not know what the "&" operator does and i am too lazy too look it up - lol
obviously, this is not right...

    .IF eax & 80000000h

then i ran it again and got...

Processor Brand String Supported
              Intel(R) Penti

maxfreq = 0.000

i think you can get the maximum frequency fairly easily
but getting the actual operating frequency with CPUID requires ring 0, as i understand it
it might be easier to use the system clock and calculate it
to do that, i think you may have to use SetProcessAffinityMask and restrict execution to core 0

dedndave

this code should display the brand string

        mov     eax,80000000h
        cpuid
        cmp     eax,80000004h
        jae     BrStr0

        print   'Brand String Not Supported',13,10
        jmp     exit00

BrStr0: xor     eax,eax
        push    eax
        mov     eax,80000004h
        cpuid
        push    edx
        push    ecx
        push    ebx
        push    eax
        mov     eax,80000003h
        cpuid
        push    edx
        push    ecx
        push    ebx
        push    eax
        mov     eax,80000002h
        cpuid
        push    edx
        push    ecx
        push    ebx
        push    eax
        mov     eax,esp
        push    edi
        xchg    eax,edi
        mov     al,20h
        mov     ecx,48
        repz    scasb
        mov     edx,edi
        pop     edi
        dec     edx
        print   edx,13,10
        add     esp,52

exit00:

MichaelW

Your statement about ring 0 seems vaguely familiar, but in the time I spent on it I did not find any related statement in the documents. The document I was using has several obvious errors, so there are a number of details that I'm not sure about. I now think the BSWAPs are not necessary.
eschew obfuscation

jj2007

Quote from: dedndave on August 04, 2009, 04:40:16 AM
i commented out the outer if/then/endif, because i do not know what the "&" operator does and i am too lazy too look it up - lol


    .IF eax & 80000000h


Lazybones!! It is bitwise and. In this case,

     .if sdword ptr eax<0

would also do the job. :wink

sinsi

Quote from: MichaelW on August 04, 2009, 05:13:13 AM
Your statement about ring 0 seems vaguely familiar
Maybe here?
Quote from: Intel CPUID pdf Chapter 9With the introduction of the Time-Stamp Counter, it is possible for software operating in real mode or protected mode with ring 0 privilege to calculate the actual operating frequency of the processor.
I have some real-mode code somewhere that calculates the MHz of a processor if you want (even works in XP's DOS).

.IF eax & 80000000h
Isn't that true if bit 31 is set? my code
mov eax,80000000h
cpuid
returns eax=80000008h
QuoteOn current and future IA-32 processors, bit 31 in the EAX register will be clear when CPUID is executed with an input parameter greater than the highest value for either set of functions, and when the extended functions are not supported.
Light travels faster than sound, that's why some people seem bright until you hear them.

MichaelW

I posted a console app here:

http://www.masm32.com/board/index.php?topic=3970.0

The ability to get the maximum rated frequency without removing the HSF could be useful.
eschew obfuscation

dedndave

Quote
    .IF eax & 80000000h
Lazybones!! It is bitwise and.
ya know, i kind of guessed that it would be bitwise AND but it isn't the right logic for the test
so, i thought maybe there was yet another thing i do not know - lol

on the bright side, i had enough gumption to look up BSWAP
so, that was my new insturction for the day - lol

btw:
time required to comment it out and reassemble - 1 minute
time required to look up and read bswap - 3 minutes
i was conserving my strength

if it makes you feel any better, Jochen, i do see a need to learn the if/then/else/endif and even to write macros - lol
that makes a longer list of stuff i need to learn
i hafta push some stuff out of my brain to make room

allynm

Hi all,

More on this clock stuff, if you haven't lost patience with me.  I looked at Michael's program, but I don't understand how cycles are computed.  It seems to me you need two things:  time elapsed, and the number of clock ticks that occur (not the number of times around the loop).  RDTSC gives you elapsed time.  But where are the ticks? 

I started the thread because I didn't see where the ticks were getting counted.  I went to the Intel CPUID doc and read the same thing SINSI quotes--about Ring 0.  If you go to the end of the document--last 5,6 pages- Intel gives sample code for obtaining the frequency....but doesn't explain whether/how Ring 0 is needed to execute their sample code. 

I apologize for my sluggish comprehension cycles....

Regards,
Mark Allyn

BogdanOntanu

RDTSC gives you the CPU cycles. You need another independent time source in order to calculate the CPU frequency. Usuually the OS offers such an source for "wall time" or an independent timmer driven from an XTAL clock.

By CPU design the RDTSC instruction can require Ring-0 access in order to be executed. But this is optional and in Windows the use of RDTSC instruction is allowed for Ring-3 code.

Apparently Michael does NOT calculate the run time frequency. Instead he reads the maximum frequency reported by the CPU from the CPUID instruction.

The frequency calculated at runtime might be inaccurate for a couple of reasons such as:
- multitasking
- speed throttle of the CPU in order to save power or reduce heat generation
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

donkey

As Bogdan says there needs to be 2 clocks in order to accurately measure one. Using rdtsc and the high resolution performance counter you can fairly accurately calculate the runtime frequency of your CPU. Setting thread priority can help reduce inaccuracies due to task switching. The following code is written in GoAsm and translated to MASM (translation was not tested but I will not post GoAsm code in this forum) it will calculate the CPU frequency and return the number of clocks per second in EDX:EAX

CPUSpeed PROC uses ebx edi esi
LOCAL hProcess :DWORD
LOCAL hThread :DWORD
LOCAL PriorityClass :DWORD
LOCAL Priority :DWORD
LOCAL timer :QWORD
LOCAL PerformanceCount :QWORD
LOCAL Frequency :QWORD

; Returns the number of clocks per second in EDX:EAX

invoke GetCurrentProcess
mov [hProcess],eax
invoke GetCurrentThread
mov [hThread],eax
invoke GetPriorityClass,[hProcess]
mov [PriorityClass],eax
invoke GetThreadPriority,[hThread]
mov [Priority],eax

invoke QueryPerformanceFrequency,addr Frequency
or eax,eax
jnz @F
invoke SetLastError,21
xor edx,edx
xor eax,eax
ret
@@:

mov esi,DWORD PTR [Frequency]
mov edi,DWORD PTR [Frequency+4]

invoke SetPriorityClass,[hProcess], REALTIME_PRIORITY_CLASS
invoke SetThreadPriority,[hThread], THREAD_PRIORITY_TIME_CRITICAL
invoke Sleep,0

invoke QueryPerformanceCounter,addr PerformanceCount
mov ebx,DWORD PTR [PerformanceCount]

@@:
invoke QueryPerformanceCounter,addr PerformanceCount
mov eax,DWORD PTR [PerformanceCount]
cmp ebx,eax
je @B
add esi,eax
adc edi,DWORD PTR [PerformanceCount+4]

ALIGN 4
rdtsc
mov DWORD PTR [timer],eax
mov DWORD PTR [timer+4],edx

@@:
invoke QueryPerformanceCounter,addr PerformanceCount
cmp edi,DWORD PTR [PerformanceCount+4]
ja @B
cmp esi,DWORD PTR [PerformanceCount]
ja @B

rdtsc
sub eax,DWORD PTR [timer]
sbb edx,DWORD PTR [timer+4]
push eax
push edx
invoke SetThreadPriority, [hThread], [Priority]
invoke SetPriorityClass, [hProcess], [PriorityClass]
invoke SetLastError,0

pop edx
pop eax

or eax,eax
RET
CPUSpeed ENDP
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable