计算来自/proc/pid/stat的进程的总CPU使用
1. 概述
在本教程中,我们将学习如何计算进程的总 CPU 使用率。为此,我们将编写一个 Bash 脚本,使用/proc/pid/stat 和*/proc/uptime* 中的值执行算术运算。
首先,我们将看到特殊文件*/proc/pid/stat的内容及其列的含义。然后,我们将了解如何使用/proc/pid/stat和/proc/uptime*文件中的值来计算 CPU 使用率。
最后,我们将编写一个 Bash 脚本来计算进程的总 CPU 使用率。
2. 了解*/proc/pid/stat*中的值
Linux系统中有一个特殊的文件系统叫proc ,我们通常挂载在*/proc*目录下。该目录包含有关系统信息的文件。
2.1. /proc/pid/stat文件
在*/proc目录中,每个进程都有自己的/proc/pid文件夹,由进程的PID 标识。然后,每个进程都有包含进程状态的特殊文件/proc/pid/stat* 。
** /proc/pid/stat文件包含计算总 CPU 使用率的信息。*它是一个纯文本文件,包含多个由空格分隔的值。 让我们使用cat 查看当前 shell 的状态。我们可以使用替换为当前 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
我们可以看到由空格分隔的几个值,每个值都有其含义。
例如,第一个值是进程 ID,第二个是进程的名称,第三个是进程的状态。我们可以通过运行man 5 proc命令查看完整的值列表及其含义。
2.2. CPU使用率
在/proc/pid/stat特殊文件中,有两个值表示进程的 CPU 使用率。一个值称为utime,另一个称为stime,它们分别是第 14 个和第 15 个值**。utime值是进程在用户模式下运行的时间。stime值是进程在内核模式下运行的时间量。
通常,我们将 CPU 使用率表示为自进程启动以来经过的时间的百分比。因此,应用程序的总 CPU 使用率是utime和stime的总和除以运行时间。
要获取自进程启动以来经过的时间,我们可以使用进程的启动时间。该值是*/proc/pid/stat文件的第 22 列,称为starttime*。该进程的starttime是从系统启动后开始计算的。因此,我们可以通过从系统的正常运行时间中减去进程的starttime来计算经过的时间。
*我们可以通过读取/proc/uptime文件来获取系统的正常运行时间。第一个值是以秒为单位的系统正常运行时间。*让我们看看/proc/uptime的内容:
$ cat /proc/uptime
28057.65 218517.53
现在,我们知道如何计算总 CPU 使用率。**但是,进程的utime、stime和starttime不是以秒为单位的。相反,它们以称为时钟滴答的单位表示。**由于系统的正常运行时间以秒为单位,我们必须将时钟滴答转换为秒来计算进程的 CPU 使用率。
2.3. 从时钟滴答转换为秒
我们可以通过读取系统的配置来获取一秒内的时钟滴答数。**为此,我们可以使用带有CLK_TCK参数的getconf 命令。**让我们获取CLK_TCK值:
$ getconf CLK_TCK
100
我们可以看到在我们的系统上,每秒有 100 个时钟滴答。该值可能不同,具体取决于系统配置。
因此,例如,如果进程的utime和stime之和为 6000,并且CLK_TCK值为 100,则该进程使用了 60 秒的 CPU。此外,如果进程的开始时间是 360000 个时钟滴答,则进程在系统启动后 3600 秒(一小时)开始。
3. 计算进程的CPU使用率
现在我们已经了解了在哪里可以找到计算进程 CPU 使用率所需的值,我们可以编写 Bash 脚本来计算它。
3.1. 编写 Bash 脚本
我们可以将 CPU 使用率计算分为三个步骤。首先,我们获取进程的utime、stime和starttime,以及系统的正常运行时间。然后,我们将进程的值从时钟滴答转换为秒。最后,我们计算自进程启动以来经过的时间,并将utime和stime的总和除以经过的时间。这样,我们就可以很容易地计算出一个进程的总CPU使用率。
让我们编写一个名为total_cpu_usage.sh的 Bash 脚本来执行计算:
#!/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
现在,我们可以测试脚本了。让我们找到进程的 ID 并通过运行*./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
如我们所见,脚本显示了进程 ID 4396 的所有信息。
首先,该脚本打印进程使用了多少 CPU 时间(以秒为单位)。然后,该脚本将 CPU 使用率打印为自进程启动以来经过的时间的百分比。
3.2. 了解 Bash 脚本
现在,让我们回顾一下前面 Bash 脚本的某些部分。 首先,我们检查脚本是否接收进程 ID 作为参数。然后,我们从/proc/$PID/stat*文件中读取进程的状态并将其存储到一个数组中 。*
我们使用sed 命令用 X 字符替换括号之间的任何内容。我们这样做是因为进程的名称放在括号内并且可以有空格。如果进程的名称有空格并且我们不考虑这种情况,它会改变/proc/$PID/stat*文件中每一列的含义。*
之后,我们从PROCESS_STAT数组中获取进程的 utime、stime和starttime并将它们存储到单独的变量中。我们可以注意到我们使用索引 13、14 和 21 而不是 14、15 和 22。这是因为 Bash 具有从零开始的数组。因此, /proc/$PID/stat文件中的第 14 列成为数组中的第 13 个索引。
在使用tr 命令将点替换为空格后,我们还使用*awk * 命令获取系统的正常运行时间。我们这样做是因为 Bash 的算法只适用于整数。
最后,我们还会注意到我们使用*let *来执行算术运算。