73

I was wondering how to calculate the total CPU usage of a process.

If I do cat /proc/pid/stat, I think the relevant fields are (taken from lindevdoc.org):

  1. CPU time spent in user code, measured in jiffies
  2. CPU time spent in kernel code, measured in jiffies
  3. CPU time spent in user code, including time from children
  4. CPU time spent in kernel code, including time from children

So is the total time spend the sum of fields 14 to 17?

alexwlchan
  • 5,699
  • 7
  • 38
  • 49

6 Answers6

178

Preparation

To calculate CPU usage for a specific process you'll need the following:

  1. /proc/uptime
    • #1 uptime of the system (seconds)
  2. /proc/[PID]/stat
    • #14 utime - CPU time spent in user code, measured in clock ticks
    • #15 stime - CPU time spent in kernel code, measured in clock ticks
    • #16 cutime - Waited-for children's CPU time spent in user code (in clock ticks)
    • #17 cstime - Waited-for children's CPU time spent in kernel code (in clock ticks)
    • #22 starttime - Time when the process started, measured in clock ticks
  3. Hertz (number of clock ticks per second) of your system.

Calculation

First we determine the total time spent for the process:

total_time = utime + stime

We also have to decide whether we want to include the time from children processes. If we do, then we add those values to total_time:

total_time = total_time + cutime + cstime

Next we get the total elapsed time in seconds since the process started:

seconds = uptime - (starttime / Hertz)

Finally we calculate the CPU usage percentage:

cpu_usage = 100 * ((total_time / Hertz) / seconds)

See also

Top and ps not showing the same cpu result

How to get total cpu usage in Linux (c++)

Calculating CPU usage of a process in Linux

Community
  • 1
  • 1
Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114
  • 10
    Hi, this would give the avg cpu usage since the application start. If a process has in last 5 secs consumed most of cpu while it was idle for 1hr, this code would still give the avg value since its uptime.. Right –  Jun 12 '13 at 11:29
  • Yes, this is average cpu usage since the process started (`starttime`). So the hour the process spent idle is also factored into the calculation (`uptime - starttime`). – Vilhelm Gray Jun 12 '13 at 12:36
  • How to get this value in android? I believe CLK_TCK is not giving HZ? –  Jun 30 '13 at 10:48
  • @Manish You may have to [derive the HZ value](http://stackoverflow.com/a/17371631/1806289) if you're using the ADB shell. – Vilhelm Gray Jul 01 '13 at 13:21
  • 1
    I got it from the same link Thanks :). I have posted an answer to my question please check it –  Jul 01 '13 at 13:31
  • @Manish I'm sorry, I just realized the link I gave you derives the kernel `HZ` value, but you actually need the `USER_HZ` value in this particular case. – Vilhelm Gray Jul 01 '13 at 18:47
  • How can I get utime from /proc/[PID]/stat ? I'm using bash, not c++. I do smth like: cat /proc/self/stat | awk '{print $14;}')" but it returns me 0. How to know whoch parameter pass to awk ? – Volodymyr Dec 31 '13 at 16:35
  • @Volodymyr Your awk command is correct: the **utime** parameter for `/proc/self/stat` is `0` in this case. I suspect your confusion is from the behavior of `/proc/self/stat`, which is a link to the currently running process -- i.e. the execution of `cat /proc/self/stat` -- which hasn't existed long enough for **utime** to be greater than `0`. – Vilhelm Gray Dec 31 '13 at 20:26
  • @VilhelmGray, so I can be sure that $14 always points to utime? Thanks. – Volodymyr Jan 09 '14 at 20:41
  • @Volodymyr Yes, unless that section of the kernel is changed in the future, `$14` will always return **utime**. – Vilhelm Gray Jan 10 '14 at 13:33
  • Do you mean by uptime the first parameter of the /proc/uptime file? or the difference between the 1st and the 2nd parameters of the file? – T-D Jul 04 '15 at 16:43
  • 1
    @T-D The `uptime` I use in the equation is the first parameter of `/proc/uptime`. I mentioned the second parameter of `/proc/uptime` to indicate how to calculate the total CPU usage of the system as a whole rather than a single process; since we are only concerned with the CPU usage of a single process, the second parameter is unused in the equations. – Vilhelm Gray Jul 06 '15 at 13:10
  • @VilhelmGray Okay i understand. Thank you. Could you please take a look at this post – T-D Jul 06 '15 at 16:02
  • @Vilhelm Gray I have tried to follow the steps you have mentionned to calculate the cpu utilization of the process but the problem is that both stime and utime as returned from the `/proc/[pid]/stat` are equal to 0, and even if I add a `sleep(20)` before reading those values they still equal to 0. Does somebody know the reason behind that? – Bionix1441 Sep 20 '17 at 14:05
  • @Kiwy; As the first two steps of the above method performs the same calculation as time, I would be interested in learning more about the method you used to compare the two. – anthropic android Aug 15 '18 at 22:51
  • @anthropicandroid my comment was wrong it is accurate average value, but it will be precise only when children process ends, because the tic count for children is only updated once the process ends. – Kiwy Aug 16 '18 at 08:52
  • @VilhelmGray I see the CPU values going down for Android and some libraries like below started ignoring it. I am trying to understand why would it go down? It is the time spent on kernel and userspace and should be always increasing? https://github.com/facebookincubator/Battery-Metrics/commit/956801de76ed9dfd25613eaca68c53c403707665 – Vishal Nagpure Jul 13 '20 at 13:06
  • @VishalNagpure Off the top of my head, I'm not sure why your time values would decrease. That would be a good question to have answered; I recommend you open a new StackOverflow question and link it to this page. – Vilhelm Gray Jul 14 '20 at 15:19
  • It's been a very long time since PC CPUs have has consistent clock rates. They clock up/down as demand requires, so you can't just convert between clocks and ticks so simplistically. – Alexander Jul 19 '20 at 15:57
6

Yes, you can say so. You can convert those values into seconds using formula:

      sec = jiffies / HZ ; here - HZ = number of ticks per second

HZ value is configurable - done at kernel configuration time.

rakib_
  • 136,911
  • 4
  • 20
  • 26
6

Here is my simple solution written in BASH. It is a linux/unix system monitor and process manager through procfs, like "top" or "ps". There is two versions simple monochrome(fast) and colored version(little bit slow, but useful especially for monitoring the statе of processes). I made sorting by CPU usage.

https://github.com/AraKhachatryan/top

  • utime, stime, cutime, cstime, starttime used for getting cpu usage and obtained from /proc/[pid]/stat file.

  • state, ppid, priority, nice, num_threads parameters obtained also from /proc/[pid]/stat file.

  • resident and data_and_stack parameters used for getting memory usage and obtained from /proc/[pid]/statm file.


    function my_ps
    {
        pid_array=`ls /proc | grep -E '^[0-9]+$'`
        clock_ticks=$(getconf CLK_TCK)
        total_memory=$( grep -Po '(?<=MemTotal:\s{8})(\d+)' /proc/meminfo )

        cat /dev/null > .data.ps

        for pid in $pid_array
        do
            if [ -r /proc/$pid/stat ]
            then
                stat_array=( `sed -E 's/(\([^\s)]+)\s([^)]+\))/\1_\2/g' /proc/$pid/stat` )
                uptime_array=( `cat /proc/uptime` )
                statm_array=( `cat /proc/$pid/statm` )
                comm=( `grep -Po '^[^\s\/]+' /proc/$pid/comm` )
                user_id=$( grep -Po '(?<=Uid:\s)(\d+)' /proc/$pid/status )

                user=$( id -nu $user_id )
                uptime=${uptime_array[0]}

                state=${stat_array[2]}
                ppid=${stat_array[3]}
                priority=${stat_array[17]}
                nice=${stat_array[18]}

                utime=${stat_array[13]}
                stime=${stat_array[14]}
                cutime=${stat_array[15]}
                cstime=${stat_array[16]}
                num_threads=${stat_array[19]}
                starttime=${stat_array[21]}

                total_time=$(( $utime + $stime ))
                #add $cstime - CPU time spent in user and kernel code ( can olso add $cutime - CPU time spent in user code )
                total_time=$(( $total_time + $cstime ))
                seconds=$( awk 'BEGIN {print ( '$uptime' - ('$starttime' / '$clock_ticks') )}' )
                cpu_usage=$( awk 'BEGIN {print ( 100 * (('$total_time' / '$clock_ticks') / '$seconds') )}' )

                resident=${statm_array[1]}
                data_and_stack=${statm_array[5]}
                memory_usage=$( awk 'BEGIN {print( (('$resident' + '$data_and_stack' ) * 100) / '$total_memory'  )}' )

                printf "%-6d %-6d %-10s %-4d %-5d %-4s %-4u %-7.2f %-7.2f %-18s\n" $pid $ppid $user $priority $nice $state $num_threads $memory_usage $cpu_usage $comm >> .data.ps

            fi
        done

        clear
        printf "\e[30;107m%-6s %-6s %-10s %-4s %-3s %-6s %-4s %-7s %-7s %-18s\e[0m\n" "PID" "PPID" "USER" "PR" "NI" "STATE" "THR" "%MEM" "%CPU" "COMMAND"
        sort -nr -k9 .data.ps | head -$1
        read_options
    }

screenshot of working script

Ara
  • 71
  • 1
  • 3
2

If need to calculate how much cpu% used by a process in last 10 secs

  1. get total_time (13+14) in jiffies => t1 starttime(22) in jiffies => s1

--delay of 10 secs

total_time (13+14) in jiffies => t2 starttime(22) in jiffies => s2

t2-t1 *100 / s2 - s1 wouldnt give the % ??

  • To get the CPU usage over an elapsed period of time (e.g. 10 seconds), you [divide the elapsed process time by the total elapsed time](http://stackoverflow.com/a/1424556/1806289). – Vilhelm Gray Jul 01 '13 at 14:24
  • s2-s1 wont be equal to 10 secs ? –  Jul 02 '13 at 00:02
  • @VilhelmGray what do u think? –  Jul 02 '13 at 10:26
  • I may be misinterpreting your equation, but if you're using `starttime(22)` then both s2 and s1 will be the same. `starttime` is the moment in time when the process was started, so the value stays the same throughout the life of your process. – Vilhelm Gray Jul 02 '13 at 12:39
  • oh oops. My mixup, i was assuming it to be time since it was started. –  Jul 02 '13 at 13:56
  • so now the question remains how to get user HZ –  Jul 02 '13 at 13:57
2

Here is another way that I got my App's CPU usage. I did this in Android, and it makes a kernel top call and gets the CPU usage for your apps PID using what top returns.

public void myWonderfulApp()
{
   // Some wonderfully written code here
   Integer lMyProcessID = android.os.Process.myPid();
   int lMyCPUUsage = getAppCPUUsage( lMyProcessID );
   // More magic
}


// Alternate way that I switched to.  I found the first version was slower
// this version only returns a single line for the app, so far less parsing
// and processing.
public static float getTotalCPUUsage2()
{
    try
    {
        // read global stats file for total CPU
        BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"));
        String[] sa = reader.readLine().split("[ ]+", 9);
        long work = Long.parseLong(sa[1]) + Long.parseLong(sa[2]) + Long.parseLong(sa[3]);
        long total = work + Long.parseLong(sa[4]) + Long.parseLong(sa[5]) + Long.parseLong(sa[6]) + Long.parseLong(sa[7]);
        reader.close();

        // calculate and convert to percentage
        return restrictPercentage(work * 100 / (float) total);
    }
    catch (Exception ex)
    {
        Logger.e(Constants.TAG, "Unable to get Total CPU usage");
    }

    // if there was an issue, just return 0
    return 0;
}

// This is an alternate way, but it takes the entire output of 
// top, so there is a fair bit of parsing.
public static int getAppCPUUsage( Integer aAppPID)
{
    int lReturn = 0;
    // make sure a valid pid was passed
    if ( null == aAppPID && aAppPID > 0)
    {
        return lReturn;
    }

    try
    {
        // Make a call to top so we have all the processes CPU
        Process lTopProcess = Runtime.getRuntime().exec("top");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(lTopProcess.getInputStream()));

        String lLine;

        // While we have stuff to read and we have not found our PID, process the lines
        while ( (lLine = bufferedReader.readLine()) != null )
        {
            // Split on 4, the CPU % is the 3rd field .
            // NOTE: We trim because sometimes we had the first field in the split be a "".
            String[] lSplit = lLine.trim().split("[ ]+", 4);

            // Don't even bother if we don't have at least the 4
            if ( lSplit.length > 3 )
            {
                // Make sure we can handle if we can't parse the int
                try
                {
                    // On the line that is our process, field 0 is a PID
                    Integer lCurrentPID = Integer.parseInt(lSplit[0]);

                    // Did we find our process?
                    if (aAppPID.equals(lCurrentPID))
                    {
                        // This is us, strip off the % and return it
                        String lCPU = lSplit[2].replace("%", "");

                        lReturn = Integer.parseInt(lCPU);
                        break;
                    }
                }
                catch( NumberFormatException e )
                {
                    // No op.  We expect this when it's not a PID line
                }
            }
        }

        bufferedReader.close();
        lTopProcess.destroy();      // Cleanup the process, otherwise you make a nice hand warmer out of your device

    }
    catch( IOException ex )
    {
        // Log bad stuff happened
    }
    catch (Exception ex)
    {
        // Log bad stuff happened
    }

    // if there was an issue, just return 0
    return lReturn;
}
Brian S
  • 3,096
  • 37
  • 55
  • I'd like to add that this has shown at times to not be a fast operation. I have seen this take 3+ seconds. I recently switched to the other answer I provided. Not blazing fast, but processes less lines. You only get back a single line for the PID you requested.. – Brian S Jun 30 '16 at 00:52
  • 1
    "I have seen this take 3+ seconds" => This is perfectly expected, the default top delay is 3s exactly, you can use `-d 0` to avoid it and get an immediate result. – Kikiwa Sep 28 '16 at 16:04
  • getTotalCPUUsage2 gets average cpu usage since bootup since /proc/stat returns values aggregated since the device booted – William Reed Aug 10 '18 at 14:15
  • To calculate instantaneous, perform the operation twice and calculate the delta of /proc/stat values and calculate cpu usage from that delta. – William Reed Aug 10 '18 at 14:24
-4

Here's what you're looking for:

//USER_HZ detection, from openssl code
#ifndef HZ
# if defined(_SC_CLK_TCK) \
     && (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000)
#  define HZ ((double)sysconf(_SC_CLK_TCK))
# else
#  ifndef CLK_TCK
#   ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
#    define HZ  100.0
#   else /* _BSD_CLK_TCK_ */
#    define HZ ((double)_BSD_CLK_TCK_)
#   endif
#  else /* CLK_TCK */
#   define HZ ((double)CLK_TCK)
#  endif
# endif
#endif

This code is actually from cpulimit, but uses openssl snippets.