Authors Top

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Overview

In this tutorial, we’ll learn how to calculate the total CPU usage of a process. We’ll do this by writing a Bash script to perform arithmetic operations using the values from /proc/<pid>/stat and /proc/uptime.

First, we’ll see the content of the special file /proc/<pid>/stat and the meaning of its columns. Then, we’ll see how to calculate the CPU usage using the values from the /proc/<pid>/stat and /proc/uptime files.

Finally, we’ll write a Bash script to calculate the total CPU usage of a process.

2. Understanding the Values in /proc/<pid>/stat

There is a special filesystem called proc in Linux systems that we usually mount on the /proc directory. This directory contains files with information about the system.

2.1. The /proc/<pid>/stat File

Inside the /proc directory, each process has its own /proc/<pid> folder, identified by the process’s PID. Then, each process has the special file /proc/<pid>/stat that contains the process’s status.

The /proc/<pid>/stat file contains the information to calculate the total CPU usage. It’s a plain text file holding several values separated by whitespaces.

Let’s use cat to see the status of the current shell. We can use the $$ special variable that is replaced with the current shell PID:

$ cat /proc/$$/stat
6608 (bash) S 2782 6608 6608 34818 25989 4194304 6423 130989 0 428 3 1 903 124 20 0 1 0 84265 9269248 1452 18446744073709551615 4345856 5123037 140728509762160 0 0 0 65536 3686404 1266761467 0 0 0 17 6 0 0 0 0 0 5362544 5410152 9601024 140728509767363 140728509767374 140728509767374 140728509771758 0

We can see several values separated by whitespace, and each value has its meaning.

For instance, the first value is the process ID, the second is the process’s name, and the third is the process’s state. We can see the full list of values and their meanings by running the man 5 proc command.

2.2. The CPU Usage

Inside the /proc/<pid>/stat special file, there are two values with the CPU usage of the process. One value is called utime and the other is called stime, which are the 14th and 15th values, respectively. The utime value is the time the process has been running in user mode. The stime value is the amount of time the process has been running in kernel mode.

Usually, we represent the CPU usage as a percentage of the elapsed time since the process started. So, the total CPU usage of an application is the sum of utime and stime, divided by the elapsed time.

To get the elapsed time since the process started, we can use the process’s start time. This value is the 22nd column from the /proc/<pid>/stat file and is called starttime. The process’s starttime is measured since the system booted. So, we can calculate the elapsed time by subtracting the process’s starttime from the system’s uptime.

We can get the system’s uptime by reading the /proc/uptime file. The first value is the system’s uptime in seconds. Let’s see the content of /proc/uptime:

$ cat /proc/uptime 
28057.65 218517.53

Now, we know how to calculate the total CPU usage. However, the process’s utime, stime, and starttime are not in seconds. Instead, they are in units called clock ticks. As the system’s uptime is in seconds, we have to convert the clock ticks to seconds to calculate the process’s CPU usage.

2.3. Converting From Clock Ticks to Seconds

We can get the number of clock ticks in a second by reading the system’s configuration. To do this, we can use the getconf command with the CLK_TCK parameter. Let’s get the CLK_TCK value:

$ getconf CLK_TCK
100

We can see that on our system, there are 100 clock ticks in a second. This value can be different, depending on the system configuration.

So, for instance, if the sum of a process’s utime and stime is 6000, and the CLK_TCK value is 100, then the process has used 60 seconds of CPU. Also, if the process’s starttime is 360000 clock ticks, then the process has started 3600 seconds (one hour) after the system booted.

3. Calculating the CPU Usage of a Process

Now that we’ve learned where we can find the values needed to calculate the CPU usage of a process, we can write a Bash script to calculate it.

3.1. Writing a Bash Script

We can split the CPU usage calculation into three steps. First, we get the process’s utime, stime, and starttime, and the system’s uptime. Then, we convert the process’s values from clock ticks to seconds. Finally, we calculate the elapsed time since the process started and divide the sum of utime and stime by the elapsed time. This way, we can easily calculate the total CPU usage of a process.

Let’s write a Bash script called total_cpu_usage.sh to perform the calculation:

#!/bin/bash
PID=$1
if [ -z "$PID" ]; then
    echo Usage: $0 PID
    exit 1
fi

PROCESS_STAT=($(sed -E 's/\([^)]+\)/X/' "/proc/$PID/stat"))
PROCESS_UTIME=${PROCESS_STAT[13]}
PROCESS_STIME=${PROCESS_STAT[14]}
PROCESS_STARTTIME=${PROCESS_STAT[21]}
SYSTEM_UPTIME_SEC=$(tr . ' ' </proc/uptime | awk '{print $1}')

CLK_TCK=$(getconf CLK_TCK)

let PROCESS_UTIME_SEC="$PROCESS_UTIME / $CLK_TCK"
let PROCESS_STIME_SEC="$PROCESS_STIME / $CLK_TCK"
let PROCESS_STARTTIME_SEC="$PROCESS_STARTTIME / $CLK_TCK"

let PROCESS_ELAPSED_SEC="$SYSTEM_UPTIME_SEC - $PROCESS_STARTTIME_SEC"
let PROCESS_USAGE_SEC="$PROCESS_UTIME_SEC + $PROCESS_STIME_SEC"
let PROCESS_USAGE="$PROCESS_USAGE_SEC * 100 / $PROCESS_ELAPSED_SEC"

echo The PID $PID has spent ${PROCESS_UTIME_SEC}s in user mode, ${PROCESS_STIME_SEC}s in kernel mode. Total CPU usage is ${PROCESS_USAGE_SEC}s
echo The process has been running for ${PROCESS_ELAPSED_SEC}s. So, the process has used ${PROCESS_USAGE}% of CPU

Now, we can test the script. Let’s find a process’s ID and execute the script by running ./total_cpu_usage.sh <pid>:

$ ./total_cpu_usage.sh 4396
The PID 4396 has spent 416s in user mode, 126s in kernel mode. Total CPU usage is 542s
The process has been running for 8893s. So, the process has used 6% of CPU

As we can see, the script displayed all the information for the process ID 4396.

First, the script prints how much CPU time in seconds the process has used. And then, the script prints the CPU usage as a percentage of the elapsed time since the process started.

3.2. Understanding the Bash Script

Now, let’s review some parts of the previous Bash script.

First of all, we check if the script receives the process’s ID as a parameter. Then, we read the process’s status from the /proc/$PID/stat file and store it into an array.

We use the sed command to substitute anything in between parenthesis with an X character. We do this because the process’s name is placed inside parentheses and it can have whitespaces. If the process’s name has whitespaces and we don’t account for that situation, it would change the meaning of each column in the /proc/$PID/stat file.

After that, we get the process’s utime, stime, and starttime from the PROCESS_STAT array and store them into individual variables. We can notice we use the index 13, 14, and 21 instead of 14, 15, and 22. This is because Bash has zero-based arrays. So, the 14th column in the /proc/$PID/stat file becomes the 13th index in the array.

We also get the system’s uptime using the awk command after substituting the dot with a white space using the tr command. We do this because Bash’s arithmetic only works with integers.

Finally, we’ll also notice that we used let to perform the arithmetic operations.

4. Conclusion

In this article, we saw how to calculate the total CPU usage of an application.

First, we learned about /proc/<pid>/stat and the meaning of its values. Then, we saw what arithmetic operations we need to perform to calculate the CPU usage.

Finally, we wrote a script to calculate the total CPU usage of a process.

Authors Bottom

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are closed on this article!