-1

I need to get the cpu usage in % of my own app process at the moment, exactly as the value shown by the column 'CPU' in Windows Task Manager, but using Delphi 11. Is this possible ?

I've found some examples in SO, but all of them gets the global cpu usage, not a specific process.

enter image description here

delphirules
  • 6,443
  • 17
  • 59
  • 108

1 Answers1

1

Here is a function that gets as input the process id (of any process), and gives as output the cpu percentage of this process.

//A function that returns CPU usage (in percent) for a given process id
function GetCpuUsage(PID:cardinal):single;
const
    cWaitTime=750;
var
    h: Cardinal;
    mCreationTime,mExitTime,mKernelTime, mUserTime: _FILETIME;
    TotalTime1,TotalTime2: Int64;
    SysInfo : _SYSTEM_INFO;
    CpuCount: Word;
begin
    //We need to know the number of CPUs and divide the result by that, otherwise we will get wrong percentage on multi-core systems
    GetSystemInfo(SysInfo);
    CpuCount := SysInfo.dwNumberOfProcessors;

    //We need to get a handle of the process with PROCESS_QUERY_INFORMATION privileges.
    h:=OpenProcess(PROCESS_QUERY_INFORMATION,false,PID);
    //We can use the GetProcessTimes() function to get the amount of time the process has spent in kernel mode and user mode.
    GetProcessTimes(h,mCreationTime,mExitTime,mKernelTime,mUserTime);
    TotalTime1:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32)) + int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    //Wait a little
    Sleep(cWaitTime);

    GetProcessTimes(h,mCreationTime,mExitTime,mKernelTime,mUserTime);
    TotalTime2:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32))+
    int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    //This should work out nicely, as there were approx. 250 ms between the calls
    //and the result will be a percentage between 0 and 100
    Result:=((TotalTime2-TotalTime1)/cWaitTime)/100/CpuCount;
    CloseHandle(h);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  pid: Word;
begin
  pid := GetCurrentProcessId;
  Button1.Caption := FormatFloat('0%', GetCpuUsage(pid));
end;

In a comment, op asks if there is a single command line to execute, to get the cpu percentage. Here is a solution for command line:

wmic /namespace:\\root\cimv2 path Win32_PerfFormattedData_PerfProc_Process WHERE "IDProcess = 5332" GET PercentProcessorTime

and

wmic /namespace:\\root\cimv2 path Win32_PerfFormattedData_PerfProc_Process WHERE "IDProcess = 5332" GET PercentUserTime

Where 5332 is the process ID.

But if you are going to use wmic to get the cpu percentage, then it is better to use it using WMI Objects from inside Delphi (using OLE Object).

George Betsis
  • 450
  • 2
  • 4
  • 2
    This function must not be used in the GUI thread due to the very long `Sleep`. – Andreas Rejbrand Sep 14 '22 at 06:45
  • `/ CpuCount` is a wild guess - a process can be assigned/limited to chosen CPU cores (see [`SetProcessAffinityMask()`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setprocessaffinitymask) and [`SetThreadAffinityMask()`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadaffinitymask)) - it may run on just one core and use 100% there already. – AmigoJack Sep 14 '22 at 06:52
  • Is there command on Windows Prompt that would return this percentage ? So i could call it on Delphi and get the cmd prompt – delphirules Sep 14 '22 at 10:52
  • @delphirules How is that question related to this answer? – AmigoJack Sep 14 '22 at 14:18