News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

GetCpuFrequency Tests

Started by dedndave, October 13, 2015, 08:34:58 PM

Previous topic - Next topic

Grincheux


QueryPerformanceFrequency: 00000000_00DA7A64h
            EFlags Toggle: 00240000h
                CPUID TSC: Supported
               RDTSC Test: Pass
          GetCpuidSupport: 00341B05h
             dwPerfPeriod: 55930
             dwMultiplier: 256
                 Measured: 13391013, 13392498, 13392825, 13392039, 13392771
                   Sorted: 13391013, 13392039, 13392498, 13392771, 13392825


          GetCpuFrequency: 3428515 KHz


Press any key to continue ...

Kenavo (Bye)
----------------------
Help me if you can, I'm feeling down...

dedndave


guga

#62
Excellent work, dave.

Was it suppose to show only the CPU frequency without other infos ? On your GetCpuFreqStatus3 i have different results then the last one you update. Here are some results on my I7

On the updated app it shows only this:

2933435 KHz

Press any key to continue ...



And on version 3 it shows a more complete  info. :
QueryPerformanceFrequency: 00000000_AED78580h
            EFlags Toggle: 00240000h
                CPUID TSC: Supported
               RDTSC Test: Pass
          GetCpuidSupport: 0034080Bh
             dwPerfPeriod: 11458438
             dwMultiplier: 256
                 Measured: 11458353, 11458341, 11458092, 11458612, 11458678
                   Sorted: 11458092, 11458341, 11458353, 11458612, 11458678

          GetCpuFrequency: 2933337 KHz

Press any key to continue ...



Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

i was having trouble getting it to work correctly on some machines
so, i had it display additional information   :biggrin:

Grincheux

No only 3.0 Ghz
http://www.phrio.biz/download/MyPc.jpg
Kenavo (Bye)
----------------------
Help me if you can, I'm feeling down...

guga

Hi Dave

Can you give me a hand, pls ;)

I´m testing a app i´m using to analyse the different algorithms for timming. In order to the app work, it grabs the Frequency of the CPU. I was using QueryperformanceFrequency to find the proper value, but, in some machines (Intel I5 420 U) the frequency found by your function is different.

For example, using CPUID alone, it displays 1,70 GHZ, but, after computing with GetCpuFrequency the frequency shows 2,39 ?!

That´s from a thread i´m talking here:
http://masm32.com/board/index.php?topic=4925.15

Which values are the correct ones ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

it may be overclocked - i don't know

here is my final version
there are 2 PROC's: GetCpuFrequency, which requires GetCpuidSupport

        .XCREF
        .NoList
        INCLUDE    \Masm32\Include\Masm32rt.inc
        .686p
        .List

;###############################################################################################

        .DATA

szKernel32  db 'Kernel32.dll',0
szAffinMask db 'SetProcessAffinityMask',0

;###############################################################################################

        .CODE

;***********************************************************************************************

main    PROC

    call    GetCpuFrequency
    print   ustr$(eax),' KHz',13,10,13,10
    inkey
    exit

main    ENDP

;***********************************************************************************************

GetCpuFrequency PROC

;David R. Sheldon (C)opyright 2015
;version 3.01

;EAX = Returns the CPU clock frequency in KHz
;      Returns 0 if any required function is not supported on the current system
;ECX = 1000
;EDX = 0 (ECX and EDX are prepared for DIV ECX, if frequency in MHz is desired)

;---------------------------------

_dwQPFreqHi                 TEXTEQU <Dword Ptr [EBP+20]>
_dwQPFreqLo                 TEXTEQU <Dword Ptr [EBP+16]>
;saved EBX contents                            [EBP+12]
;saved ESI contents                            [EBP+8]
;saved EDI contents                            [EBP+4]
;saved EBP contents                            [EBP]
_hProcess                   TEXTEQU <Dword Ptr [EBP-4]>
_dwPrcsClass                TEXTEQU <Dword Ptr [EBP-8]>
_hThread                    TEXTEQU <Dword Ptr [EBP-12]>
_dwThrdLevel                TEXTEQU <Dword Ptr [EBP-16]>
_dwSystemAffinityMask       TEXTEQU <Dword Ptr [EBP-20]>
_dwProcessAffinityMask      TEXTEQU <Dword Ptr [EBP-24]>
_lpfnSetProcessAffinityMask TEXTEQU <Dword Ptr [EBP-28]>
_dwPerfPeriod               TEXTEQU <Dword Ptr [EBP-32]>
_dwQPCountHi                TEXTEQU <Dword Ptr [EBP-36]>
_dwQPCountLo                TEXTEQU <Dword Ptr [EBP-40]>

;---------------------------------

    push    eax                                         ;[EBP+20] = _dwQPFreqHi
    push    eax                                         ;[EBP+16] = _dwQPFreqLo
    INVOKE  QueryPerformanceFrequency,esp
    .if eax
        push    ebx
        push    esi
        push    edi
        push    ebp
        mov     ebp,esp
        INVOKE  GetCurrentProcess
        push    eax                                     ;[EBP-4]  = _hProcess
        INVOKE  GetPriorityClass,eax
        push    eax                                     ;[EBP-8]  = _dwPrcsClass
        INVOKE  GetCurrentThread
        push    eax                                     ;[EBP-12] = _hThread
        INVOKE  GetThreadPriority,eax
        push    eax                                     ;[EBP-16] = _dwThrdLevel
        INVOKE  GetModuleHandleA,offset szKernel32
        mov     esi,offset szAffinMask
        xchg    eax,ebx                                 ;EBX = hmoduleKernel32
        INVOKE  GetProcAddress,ebx,esi
        mov byte ptr [esi],'G'
        xchg    eax,edi                                 ;EDI = lpfnSetProcessAffinityMask
        INVOKE  GetProcAddress,ebx,esi
        mov byte ptr [esi],'S'
        xor     ecx,ecx
        push    ecx                                     ;[EBP-20] = _dwSystemAffinityMask placeholder
        mov     edx,esp
        push    ecx                                     ;[EBP-24] = _dwProcessAffinityMask placeholder
        .if (eax) && (edi)
            mov     ebx,esp
            push    edi                                 ;[EBP-28] = _lpfnSetProcessAffinityMask
            push    edx                                 ;GetProcessAffinityMask:lpSystemAffinityMask
            push    ebx                                 ;GetProcessAffinityMask:lpProcessAffinityMask
            push    _hProcess                           ;GetProcessAffinityMask:hProcess
            call    eax                                 ;GetProcessAffinityMask
            xor     eax,eax
            mov     edx,_dwProcessAffinityMask
            stc
            .repeat
                rcl     eax,1
                .break .if CARRY?
                test    eax,edx                         ;first available core
            .until !ZERO?
            .if !CARRY?
                push    eax                             ;SetProcessAffinityMask:lpProcessAffinityMask
                push    _hProcess                       ;SetProcessAffinityMask:hProcess
                call    edi                             ;SetProcessAffinityMask
                INVOKE  Sleep,1
            .endif
        .else
            push    ecx                                 ;[EBP-28] = _lpfnSetProcessAffinityMask = NULL
        .endif
        call    GetCpuidSupport
        .if eax&100000h

;calculate performance counter period

            mov     ecx,_dwQPFreqLo
            mov     edx,_dwQPFreqHi
            .if (edx) || (ecx>255)
                shrd    ecx,edx,8
                adc     ecx,0
            .endif
            push    ecx                                 ;[EBP-32] = _dwPerfPeriod

;make 5 measurement passes

            push    eax                                 ;[EBP-36] = _dwQPCountHi placeholder
            push    eax                                 ;[EBP-40] = _dwQPCountLo placeholder
            mov     ebx,5
            mov     edi,esp                             ;EDI = lpqwQPCount
            .repeat
                INVOKE  SetPriorityClass,_hProcess,REALTIME_PRIORITY_CLASS
                INVOKE  Sleep,1
                INVOKE  SetThreadPriority,_hThread,THREAD_PRIORITY_TIME_CRITICAL
                INVOKE  Sleep,1
                INVOKE  QueryPerformanceCounter,edi
                mov     esi,[edi]
                .repeat
                    INVOKE  QueryPerformanceCounter,edi
                .until esi!=[edi]
                rdtsc
                mov     esi,[edi]
                push    eax
                .repeat
                    INVOKE  QueryPerformanceCounter,edi
                    mov     eax,[edi]
                    sub     eax,esi
                .until eax>=_dwPerfPeriod
                pop     ecx
                rdtsc
                sub     eax,ecx
                push    eax                             ;store measurement on stack
                INVOKE  SetPriorityClass,_hProcess,_dwPrcsClass
                INVOKE  Sleep,1
                INVOKE  SetThreadPriority,_hThread,_dwThrdLevel
                INVOKE  Sleep,1
                dec     ebx
            .until ZERO?

;recall the 5 measurements from the stack and in-register sort

            pop     esi
            pop     edx
            pop     eax
            pop     ecx
            pop     ebx
            .if ebx>ecx
                xchg    ebx,ecx
            .endif
            .if ecx>eax
                xchg    eax,ecx
            .endif
            .if eax>edx
                xchg    eax,edx
            .endif
            .if edx>esi
                xchg    edx,esi
            .endif
            .if edx<eax
                xchg    eax,edx
            .endif
            .if eax<ecx
                xchg    eax,ecx
            .endif
            .if ecx<ebx
                xchg    ebx,ecx
            .endif
            .if ecx>eax
                xchg    eax,ecx
            .endif
            .if eax>edx
                xchg    eax,edx
            .endif
            .if eax<ecx
                xchg    eax,ecx
            .endif

;ESI = A(4) highest
;EDX = A(3)
;EAX = A(2)
;ECX = A(1)
;EBX = A(0) lowest

;throw away the lowest and highest, A(0) and A(4)
;find the closest pair of A(1),A(2) or A(2),A(3)
;  if A(3)-A(2) > A(2)-A(1), use (A(2)+A(1))/2 as the result
;  if A(3)-A(2) < A(2)-A(1), use (A(3)+A(2))/2 as the result
;  if A(3)-A(2) = A(2)-A(1), use A(2) as the result

            mov     esi,edx                             ;ESI = A(3)
            mov     ebx,eax                             ;EBX = A(2)
            sub     esi,eax                             ;ESI = A(3)-A(2)
            sub     ebx,ecx                             ;EBX = A(2)-A(1)
            cmp     ebx,esi
            .if CARRY?
                add     eax,ecx
            .elseif !ZERO?
                add     eax,edx
            .else
                shl     eax,1
            .endif
            shr     eax,1
            adc     eax,0

;scale the result, Freq(KHz) = Measurement*qwQPCount/1000*dwPerfPeriod

            mov     esi,eax
            xor     edi,edi
            mul     _dwQPFreqLo
            xchg    eax,esi
            xchg    edx,edi
            mul     _dwQPFreqHi
            mov     ecx,_dwPerfPeriod
            add     eax,edi                             ;product in EAX:ESI
            div     ecx
            xchg    eax,esi
            div     ecx                                 ;quotient in ESI:EAX, modulo in EDX
            mov     edx,esi
            mov     ecx,1000
            div     ecx
            shr     ecx,1
            cmp     edx,ecx
            sbb     eax,-1
        .else
            xor     eax,eax
        .endif

;restore affinity and exit

        mov     ecx,_lpfnSetProcessAffinityMask
        .if ecx
            push    eax
            push    _dwProcessAffinityMask              ;SetProcessAffinityMask:dwProcessAffinityMask
            push    _hProcess                           ;SetProcessAffinityMask:hProcess
            call    ecx                                 ;SetProcessAffinityMask
            INVOKE  Sleep,0
            pop     eax
        .endif
        mov     ecx,1000
        xor     edx,edx
        leave
        pop     edi
        pop     esi
        pop     ebx
    .endif
    add     esp,8
    ret

GetCpuFrequency ENDP

;***********************************************************************************************

GetCpuidSupport PROC

;David R. Sheldon (C)opyright 2015
;version 3.01

;Returns a value in EAX with the following flag bits:
;
; Bit            Description
;
;0-7             Highest CPUID standard leaf supported
;8-15            Highest CPUID extended leaf supported
; 18             Processor is 80486 or later
; 20             Processor has TimeStampCounter (RDTSC supported)
; 21             Processor supports CPUID instruction
;
;All other bits are reserved.
;It is possible, however unlikely, that different values may be returned from individual cores.
;It is advisable to select a single specific core prior to calling this routine.

;---------------------------------

    push    ebx
    pushfd
    mov     ecx,240000h                                 ;bit 21 = CPUID, bit 18 = 486+
    pop     ebx
    mov     edx,ebx                                     ;EDX = original EFlags
    xor     ebx,ecx                                     ;EBX = toggled EFlags
    push    ebx
    popfd                                               ;EFlags = toggled flags
    pushfd
    pop     ebx                                         ;EBX = test flags
    push    edx                                         ;original EFlags on stack
    xor     ebx,edx                                     ;EBX = toggle result
    and     ebx,ecx
    mov     ecx,200000h                                 ;ECX = bit 21 only
    xor     eax,eax                                     ;EAX = CPUID leaf 0
    test    ebx,ecx
    .if !ZERO?
        or      edx,ecx
        push    ebx
        push    edx
        popfd
        cpuid
        pop     ebx
        .if ah==5
            or     ebx,100000h                          ;TSC supported for pre-b0 stepping
        .elseif eax
            .if eax>0FFh
                mov     bl,0FFh
            .else
                mov     bl,al
            .endif
            mov     eax,1
            push    ebx
            cpuid
            pop     ebx
            and     edx,10h                             ;TSC support flag
            shl     edx,16
            or      ebx,edx
            mov     eax,80000000h
            push    ebx
            cpuid
            pop     ebx
            .if eax>800000FFh
                mov     bh,0FFh
            .else
                mov     bh,al
            .endif
        .endif
        .if ebx&100000h
            rdtsc
            push    eax
            INVOKE  Sleep,1
            rdtsc
            pop     edx
            .if eax==edx
                and     ebx,0FFEFFFFFh                  ;TSC not running
            .endif
        .endif
    .endif
    xchg    eax,ebx
    popfd                                               ;EFlags = original
    pop     ebx
    ret

GetCpuidSupport ENDP

;###############################################################################################

        END     main

dedndave

2.39 GHz ~ 2.4 GHz, which is a common clock freq

dedndave

http://www.notebookcheck.net/Intel-Core-i5-4210U-Notebook-Processor.115081.0.html

QuoteEach core offers a base speed of 1.7 GHz, but can dynamically increase clock rates
with Turbo Boost up to 2.7 GHz for 1 active core or 2.4 GHz for 2 active cores.

mabdelouahab

http://masm32.com/board/index.php?topic=4925.msg53020#msg53020

guga

Thanks Dave. A LOT ! Your function is amazing. I´m using it on the app i was talking about   I hope that once i succeed to finish the fine tunnings, i can make a dll so you guys can use it on your apps too. Biased on the results the guys are reporting, the values seems accurated :)

I found 2 problems only. The huge variance found in mabdelouahab (which maybe explained by the increasing of speed as you told) and the problems when analyzing short codes (as "xor eax eax" alone) . On both, although the values of the mean are acceptable, the variance is too high to be correct, meaning that something has passed through a function i built to block such rare situations.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

Hi Dave,

does your function works inside a dll? I mean, since it is using SetProcessAffinityMask Api, can the function be used inside a dll (As an export function or not) ?

https://msdn.microsoft.com/pt-br/library/windows/desktop/ms686223%28v=vs.85%29.aspx
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

what they mean is....
don't use it in a DLL that may be used by more than one process at a time

dedndave

...my intention is to use it in a static library (LIB)
the code is then imported to the EXE when you build it

guga

Phew !

I thought for a moment i´ll have to rewrite the Benchmark app to it allow the dll form :greensml:

I was confused by the msdn doc.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com