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.
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]
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 (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/ntquerysysteminformation.asp)
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.
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.
Hutch,
I think I have a simple example at home. Ill send it through when im there.
Rgs, striker.
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...
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]
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
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]
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.
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.
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]
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.
anyway to find out a paticular processes cpu usage? would be nice to be able to auto kill 100%'rs :bg
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)
Thanks a lot tedd :D only other solution I found was via WMI, this solution is easier+smaller so definitely appreciated.