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
    // when the process was created
     var lpCreationTime:_FILETIME;
    // when the process exited var
    // time the process has spent in kernel mode
     var lpKernelTime:_FILETIME;
    // time the process has spent in user mode
     var lpUserTime :_FILETIME

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(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;
    h : Cardinal;
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
     {We need to get a handle of the process with PROCESS_QUERY_INFORMATION privileges.}
    {We can use the GetProcessTimes() function to get the amount of time the process has spent in kernel mode and user mode.}
    TotalTime1:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32)) + int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    {Wait a little}

    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}

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;

    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.}
        //Last result of wsGetCpuUsage is saved here
        //Use it for anythin you like, not modified by this unit

function wsGetCpuUsage(aCounter:PCPUUsageData):single;
procedure wsDestroyUsageCounter(aCounter:PCPUUsageData);



function wsCreateUsageCounter(PID:cardinal):PCPUUsageData;
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
    //We need a handle with PROCESS_QUERY_INFORMATION privileges
    if h=0 then exit;
    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));
    end else begin

procedure wsDestroyUsageCounter(aCounter:PCPUUsageData);

function wsGetCpuUsage(aCounter:PCPUUsageData):single;
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
    ThisTime:=GetTickCount; //Get the time elapsed since last query

    if DeltaMs < wsMinMeasurementInterval then exit;

    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 is in units of 100 nanoseconds, so…

    //just in case you want to use it later, too


Related posts :

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

  1. thank yoou admin really nice kode.
    by turku

  2. Now it’s ok!

  3. quark says:

    In the following code:

    TotalTime:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32));

    ‘shr’ should be ‘shl’ ?

  4. Jānis Elsts says:

    Hmm, it seems you’re right.

  5. Hmm, it seems you’re right.

  6. […] CPU-Auslastung von Threads   Heute, 14:35 Hier ist was Brauchbares:…-of-a-process/ […]

  7. Kevin says:

    To make this work, I had to use UInt64 rather than Int64.

  8. D7.01 says:

    Works nice, thanks.

  9. Nice post. Thanks for sharing.

Leave a Reply