How to get the CPU usage of a process

In this short article I will describe how to obtain the CPU usage of a single process (like the “CPU” column in Task Manager). I have also created a small unit that implements this functionality – uCpuUsage (7 Kb, RAR archive).

One way, that works only in NT-based operation systems (NT/2000/XP and so on) is to use the GetProcessTimes() API function (Windows unit).

function GetProcessTimes(
    // process handle
    hProcess:cardinal;
    // when the process was created
     var lpCreationTime:_FILETIME;
    // when the process exited var
     lpExitTime:_FILETIME;
    // time the process has spent in kernel mode
     var lpKernelTime:_FILETIME;
    // time the process has spent in user mode
     var lpUserTime :_FILETIME
):LongBool;

As you can see, this function returns the total amount of time the process has been using the CPU (lpKernelTime+lpUserTime) (we can ignore lpCreationTime and lpExitTime). This amount is expressed in units of 100 nanoseconds (divide by 10000 to get miliseconds). The _FILETIME structure is essentially a 64-bit integer and can be converted to Delphi version of Int64 quite easily :

TotalTime:Int64;
{…..}
TotalTime:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32));

To get the CPU usage we must get the process times twice (say, TotalTime1 and TotalTime2), and calculate the CPU usage as ((TotalTime2-TotalTime1) / DeltaTime), where DeltaTime is time elapsed between the two calls of GetProcessTimes (TotalTime’s and DeltaTime must be expressed in the same units, see the example below).

Method 1
A simple (though not very flexible) way of getting the CPU usage is then such :

(Add Windows to your Uses clause)

{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;
begin
     {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;
    CloseHandle(h);
end;

Method 2
The previous method has some obvious shortcomings – it pauses the program for the specified time every time it is run and is a bit inefficient when used repeatedly (e.g. to create a CPU usage graph for a process). That’s why I wrote a simple unit that is more flexible and still easy to use. You can download it or copy & paste the code below.

Using the unit

When starting to monitor a process, call cnt:=wsCreateUsageCounter(Process_id) to initialize a usage counter. When you need to get the current CPU usage of that process, use usage:=wsGetCpuUsage(cnt). When you have finished monitoring the process, call wsDestroyUsageCounter(cnt) to free memory used by usage counter and close open handles.

The uCpuUsage unit

unit uCpuUsage;

interface
const
    wsMinMeasurementInterval=250; {minimum amount of time that must have elapsed to calculate CPU usage, miliseconds. If time elapsed is less than this, previous result is returned, or zero, if there is no previous result.}
type
    TCPUUsageData=record
        PID,Handle:cardinal;
        oldUser,oldKernel:Int64;
        LastUpdateTime:cardinal;
        LastUsage:single;
        //Last result of wsGetCpuUsage is saved here
        Tag:cardinal;
        //Use it for anythin you like, not modified by this unit
    end;
    PCPUUsageData=^TCPUUsageData;

function
wsCreateUsageCounter(PID:cardinal):PCPUUsageData;
function wsGetCpuUsage(aCounter:PCPUUsageData):single;
procedure wsDestroyUsageCounter(aCounter:PCPUUsageData);

implementation

uses
Windows;

function wsCreateUsageCounter(PID:cardinal):PCPUUsageData;
var
    p:PCPUUsageData;
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
    h:cardinal;
begin
    result:=nil;
    //We need a handle with PROCESS_QUERY_INFORMATION privileges
    h:=OpenProcess(PROCESS_QUERY_INFORMATION,false,PID);
    if h=0 then exit;
    new(p);
    p.PID:=PID;
    p.Handle:=h;
    p.LastUpdateTime:=GetTickCount;
    p.LastUsage:=0;
    if GetProcessTimes(p.Handle, mCreationTime, mExitTime, mKernelTime, mUserTime) then begin
        //convert _FILETIME to Int64
        p.oldKernel:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32));
        p.oldUser:=int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));
        Result:=p;
    end else begin
        dispose(p);
    end;
end;

procedure wsDestroyUsageCounter(aCounter:PCPUUsageData);
begin
    CloseHandle(aCounter.Handle);
    dispose(aCounter);
end;

function wsGetCpuUsage(aCounter:PCPUUsageData):single;
var
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
    DeltaMs,ThisTime:cardinal;
    mKernel,mUser,mDelta:int64;
begin
    result:=aCounter.LastUsage;
    ThisTime:=GetTickCount; //Get the time elapsed since last query

    DeltaMs:=ThisTime-aCounter.LastUpdateTime;
    if DeltaMs < wsMinMeasurementInterval then exit;
aCounter.LastUpdateTime:=ThisTime;

    GetProcessTimes(aCounter.Handle,mCreationTime, mExitTime, mKernelTime, mUserTime);
    //convert _FILETIME to Int64.
    mKernel:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32));
    mUser:=int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));
    //get the delta
    mDelta:=mUser+mKernel-aCounter.oldUser-aCounter.oldKernel;

    aCounter.oldUser:=mUser;
    aCounter.oldKernel:=mKernel;

    Result:=(mDelta/DeltaMs)/100;
    //mDelta is in units of 100 nanoseconds, so…

    aCounter.LastUsage:=Result;
    //just in case you want to use it later, too
end;

end.

Related posts :

30 Responses to “How to get the CPU usage of a process”

  1. Musa says:

    Thanks For This Source

    But Ic Want To get Process Id FRom Process Name

    Do You help Me?

    Thank You

  2. White Shadow says:

    To get a process ID from process name you’ll need to enumerate all processes and find one that has the name you want.

    I don’t know if there is an universal solution, but you can download http://w-shadow.com/files/wsHideDLL.zip and in procs.pas there is a function FindProcess() that will find a process id for a given name.

    You could use it like pid:=FindProcess(‘explorer.exe’)

    Thanks for reading 🙂

  3. Zcoder says:

    WOW!! BIG THX FOR THIS CODE!

  4. GerardAtJob says:

    It’s working for ONE process… but if you extend your code a little
    and want to have a Overall CPU Usage you’ll find yourself listening
    only YOUR USERS PROCESS… (in Vista)… which I find innacurate…

    All the process of other users won’t be listed using your code…

    I’m searching a way to get all the process… even thoses of other
    users to get an accurate CPU usage…

    If someone find any (without using SE_DEBUG_PRIVILEGE…)
    please let me know! 😀

    Ps : Good Work! 😀

  5. GerardAtJob says:

    Forgot to say this too …. you must divide your result by the number of CPUs…

    else you’ll get 200% usage 😉

  6. Mcone says:

    Very nice! I was searching only for how to determine the total CPU usage. Your routine exceeds that goal by giving individual process usages – plus the code for a list box all in one! The individual values can just be added together to get the total . Thanks for posting this code.

  7. Vinaya says:

    Can you provide me the above code(i.e code to get the cpu usage of each process in C#.NET

  8. White Shadow says:

    Personally I haven’t used .NET that much, but this link should help you – Getting CPU usage of processes and threads, .NET style

  9. rap dinle says:

    That’s good plungin! I’ll use it for my wordpress and control my works. Thank you!…

  10. mohammad says:

    Thanks alot. Works fine. But seems the result of your code should be divide to number of CPU cores on system. I have Quad core cpu and your results are 4th time more than taskmanager.

  11. White Shadow says:

    That’s true. Multicore CPU’s weren’t nearly this popular when I wrote this post 3 years ago. Here’s info about how to get the number of cores.

  12. Was truly a very nice thank you, I’m following your site for information is constantly available, good work.

  13. müzik dinle says:

    WOW!! BIG THX FOR THIS CODE!

  14. ArabeskRap says:

    Thank’s Very GooD!!

  15. Davis says:

    Hi for all,

    The demo works fine for me but in my bellow code don’t works. Where is my error ?
    The result for S var is 0.

    procedure TForm1.Update
    var
    p:PCPUUsageData;
    s:single;
    Pid:cardinal;

    begin
    s := 0;
    pid := 984; //pid of a process with more than 0 percent of usage

    p:=wsCreateUsageCounter(pid);
    s:=wsGetCpuUsage(P);

    Memo1.Lines.Add(floattostr(s));

    wsDestroyUsageCounter(P);

    end;

    Thanks.

  16. White Shadow says:

    Due to the way the functions work, you need to wait at least a few milliseconds between wsCreateUsageCounter() and the first call to wsGetCpuUsage(). Put a Sleep(100); call in there.

  17. Davis says:

    Now it’s ok!
    Thanks.

  18. Alexander says:

    Thangks Very Much!

  19. muzik dinle says:

    thanks so much. its ok now. greetings

  20. big Thx fot this kode..!

Leave a Reply