News:

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

Processor Usage as a function

Started by hutch--, June 14, 2005, 05:06:42 AM

Previous topic - Next topic

hutch--

I wondered if anyone had a known or simple way to extract the processor percentage usage from any of the later versions of Windows ? You can get it from Task Manager or aftermarket tools but I have not seen a method of coding this capacity anywhere.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Phoenix

This is a little control, that is able to show CPU-Load using performance monitoring functions from pdh.dll. It works on single cpu systems and Windows NT 4 or later. Right now, i am trying to add multicpu-support.

Regards, Phoenix

[attachment deleted by admin]

GregL

Hutch,

I have seen examples in PowerBASIC that use NtQuerySystemInformation function in NTDLL.DLL.

  http://www.powerbasic.com/support/forums/Forum7/HTML/002207.html

  http://www.powerbasic.com/support/forums/Forum7/HTML/002459.html
 
  NtQuerySystemInformation - MSDN

I haven't seen an example in MASM, but it wouldn't be too hard to translate. If I get the time I'll do that.

The other way is to use PDH.DLL like Phoenix is doing.

If you can figure out how to call the WMI Performance Counter functions you can do that too. I've only seen it done in VBScript.


hutch--

Thanks Phoenix,

It looks like a lot of work you have done to make the controls but I have only digested a small part of it so far.

Greg,

Thanks for the links, what I had in mind if it could be done was a reasonably simple procedure that could be used for debugging thread related procedures. What I currently do is run task manager or the sysinternals process explorer which has a lot more detail but I thought there may be a more convenient way.

It would be a nice tool to have as a general purpose capacity.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

James Ladd

Hutch,
I think I have a simple example at home. Ill send it through when im there.
Rgs, striker.

Phoenix

It is possible to extract the processor percentage usage using RegQueryValueEx with HKEY_PERFORMANCE_DATA on NT-Systems. Here is a link to code written in C++:

http://spotlight.de/nzforen/acpp/m/acpp-1105521271-30099.html

I am not familiar with C++, so perhaps someone can translate to asm code...

MichaelW

#6
This is a proof of concept app that attempts to measure the time the processor is spending in non-idle threads, directly. It seems to work OK, and it's sensitive enough to respond to movement of the mouse cursor (on my P3-500).

EDIT:

The initial coding had a problem with displaying 0% instead of 100% when the idle time dropped to zero. To correct this I reversed the logic so the idle thread tracked the idle time instead of the non-idle time, and calculated the non-idle time from the idle time. This eliminated the problem with the second sampling period returning an obviously incorrect value, and eliminated the need for the filter. The new version is the code below and the second attachment.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
    .586

    IdleThread  PROTO
    CtrlHandler PROTO :DWORD
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
        startCount  dq 0
        idleCount   dq 0
        totalCount  dq 0
        threadID    dd 0
        hThread     dd 0
        hTimer      dd 0
        exitFlag    dd 0
        temp        dd 0
        exitCode    dd 0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    ;invoke GetCurrentProcess
    ;invoke SetPriorityClass, eax, HIGH_PRIORITY_CLASS

    invoke CreateThread,NULL,0,ADDR IdleThread,
        NULL,CREATE_SUSPENDED,ADDR threadID
    mov   hThread,eax

    invoke SetThreadPriority,hThread,THREAD_PRIORITY_IDLE

    invoke SetConsoleCtrlHandler,ADDR CtrlHandler,TRUE
   
    invoke CreateWaitableTimer,NULL,FALSE,NULL
    mov   hTimer, eax

    ; --------------------------------------------------
    ; ADDR temp used here because 0 will not work, even
    ; though the due time is apparently ignored when a
    ; timer period (here set to 500 ms) is specified.
    ; --------------------------------------------------
    invoke SetWaitableTimer,hTimer,ADDR temp,500,NULL,NULL,0

    rdtsc
    mov   DWORD PTR startCount,     eax
    mov   DWORD PTR startCount[4],  edx

    invoke ResumeThread,hThread

    .WHILE (TRUE)

        invoke WaitForSingleObject,hTimer,1000

        rdtsc
        sub   eax, DWORD PTR startCount
        sbb   edx, DWORD PTR startCount[4]

        mov   DWORD PTR totalCount,    eax
        mov   DWORD PTR totalCount[4], edx

        fild  idleCount
        fild  totalCount
        fdiv                    ; idle cycles / total cycles
        fld8  100.0
        fmul                    ; convert to percent
        fistp temp

        mov   eax, 100          ; calc non-idle percent
        sub   eax, temp

        print ustr$(eax),13,10

        ; -------------------------------------------
        ; Reinitialize for the next sampling period.
        ; -------------------------------------------
        rdtsc
        mov   DWORD PTR startCount,     eax
        mov   DWORD PTR startCount[4],  edx
        mov   DWORD PTR idleCount,      0
        mov   DWORD PTR idleCount[4],   0

    .ENDW

    ;mov   eax, input(13,10,"Press enter to exit...")
    ;exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

CtrlHandler proc ctrlType:DWORD

    .IF (ctrlType == CTRL_CLOSE_EVENT)

        invoke SetThreadPriority,hThread,THREAD_PRIORITY_HIGHEST
        inc   exitFlag

        .WHILE (exitCode == STILL_ACTIVE)
            invoke GetExitCodeThread,hThread,ADDR exitCode
        .ENDW

    .ENDIF

    invoke CloseHandle,hThread

    ; ----------------------------------------------
    ; Exit directly from this procedure to avoid a
    ; "Windows cannot end this program..." warning.
    ; ----------------------------------------------
    exit

CtrlHandler endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

IdleThread proc uses ebx

    ; --------------------------------------------------
    ; If the cycle count for the current loop is below
    ; a threshold value, assume the count represents
    ; the CPU idle time, and add it to the idle count
    ; for the current sampling period.
    ;
    ; Because a task switch could occur at any point in
    ; the loop, each task switch could introduce an
    ; error as large as the cycle count for the loop
    ; instructions, but this should be negligibly small
    ; compared to the cycle count for a time slice.
    ;
    ; The threshold value needs to be somewhat larger
    ; than the worst-case cycle count for the loop
    ; instructions.
    ; --------------------------------------------------

    .WHILE (exitFlag == 0)

        rdtsc
        push  eax
        push  edx
        sub   eax, ebx
        sbb   edx, ecx
        .IF (edx == 0 && eax < 200)
            add   DWORD PTR idleCount,    eax
            adc   DWORD PTR idleCount[4], edx
        .ENDIF
        pop   ecx               ; save for next loop
        pop   ebx

    .ENDW

    ret

IdleThread endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start



[attachment deleted by admin]
eschew obfuscation

zooba

Hmm... interesting

Seems to work alright on my Intel Pentium M 1400 with WinXP Home, 1gb RAM.

Sits at around about 4 or 5 for windows+winrar+IE+MSN running. Moving the mouse around the desktop causes it to rise to about 12,13. But dragging the selection box around on the desktop only takes 6 or 7???

In IE it makes more sense. 18,19 to move the mouse, 30-35 to select.

I hope I'm interpreting these numbers okay  :lol

Phoenix

MichaelW,

great piece of code  :U and works perfect (2nd version)... but however, if i have a look at Windows Task Manager, it shows always 100% cpu-usage when running Test2.exe.

For me, i have played with pdh.dll and attached a working (?) console version of it. I know, this is The Laboratory, but perhaps it is of interest....

Regards, Phoenix

[attachment deleted by admin]

hutch--

Phoenix,

Thanks for the second version that uses PDH functions, this one is producing results very similar to the task manager and the Sysinternals Process Explorer.

I am getting a read out of 6% most of the time but with an occasional 12% spike and I don't know what the spike is for.

I just downloaded Michael's 2nd version and it is producing more even figures in the 10 - 11% range but the task manager shows it running at 100% processor usage. This may not be a problem as I had nothing else running so it just used the lot.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

Phoenix,

Thanks for the code. I concentrated on a simpler method in part because I could not find any suitable examples the used the PDH interface.

It is the local idle thread that is causing Task Manager to show high usage (98-99% on my system). If I start some intensive application that drops the idle time to zero, Task Manager shows that application at ~99%, and test2 at 0% most of the time. This makes it hard to compare the Task Manager results to my results, but I don't see any way around it. After looking at your code I realized that mine could be simplified by replacing the two function calls that set up the timer and the call to WaitForSingleObject with a single call to Sleep.
eschew obfuscation

Phoenix

MichaelW,

QuoteI concentrated on a simpler method

Your method is great and simple in one, and i guess what the Sytem_Idle_Process (PID 0) does must be very similar.

hutch--,

Quoteand I don't know what the spike is for

I got interested to find a way retrieving more detailed information about what the cpu is doing. The attached console app shows information about cpu idle time, kernel time and user time. Unfortunately, it does not explain the peaks, just that they are located in kernel time.. BTW, the code uses two API calls from ntdll.dll, ZwQuerySystemInformation and ZwQuerySystemTime. Both are not documented in MSDN but by a lot of coders who have used them in other context without problems. I have tested the code on W2K SP4 and WinXP x64 beta, works fine on both. And, BTW, is MUCH simpler to use as PDH.dll calls...



[attachment deleted by admin]

hutch--

This looks good, I ran it as was and it was producing a range from 6 to 12 % as before so I changed the sample rate to the same as I run in task manager and Process explorer (1 second) and it started to produce much the same results as both. I don't personally see the use of direct NTDLL.DLL calls in debugging as a problem as its a programmers choice of tools to use and this is shaping up as being a useful technique.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

ecube

anyway to find out a paticular processes cpu usage? would be nice to be able to auto kill 100%'rs  :bg

Tedd

Just came across the GetProcessTimes function, and remembered this thread..

Total processor usage would be: (100% - SystemIdleProcess.time)
Not that I've tested it, but I'd take a first guess at the handle for the idle-process as being zero.


For E^cube: you could use this function, along with a list of currently running processes - then you can kill the greedy ...ones :wink (though I'd lower the threshold to about 96% - as processes rarely get to 100%, other processes are still running; and don't try killing the IdleProcess :lol)
No snowflake in an avalanche feels responsible.