1.2 CPU
CPU Load
$ cat /proc/loadavg
7.06 7.73 8.26 7/3569 3560
- 1 分钟的平均负载
- 5 分钟的平均负载
- 15 分钟的平均负载
- 正在运行的进程数/活跃的总进程数
- 最近的进程 id
CPU 负载是指正在使用和等待使用 CPU 的进程数。
对于单核处理器,如果 CPU 负载小于 1,意味着每个进程都能被及时处理,如果大于 1,意味着 CPU 满负荷,且有部分进程正处于等待状态,不能被及时处理。
对于多核处理器,比如 n 核,每个 CPU 满负荷处理时系统负载为 n,系统负载超过 n,意味着有进程不能被及时处理。
CPU Usage
CPU 使用率是指单位时间内 CPU 工作时间的占比。
查看 CPU 信息
$ cat /proc/cpuinfo
uptime 输出解释
$ uptime
16:58:33 up 2:07, 1 user, load average: 2.76, 1.78, 1.46
表示系统在 1, 5, 15 分钟内的平均工作负载分别为 2.76, 1.78, 1.46。
vmstat 使用
使用:
vmstat [<interval> [<count>]]
比如每隔 1 秒展示一次统计数据,总共展示 2 次:
$ vmstat 1 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
6 0 0 4081200 46644 980480 0 0 9 20 559 431 15 8 77 0 0
8 0 0 4082736 46644 980480 0 0 0 0 65887 21435 17 11 72 0 0
输出上一秒内的 CPU 使用率
echo "CPU Usage: "$[100-$(vmstat 1 2|tail -1|awk '{print $15}')]"%"
注意:vmstat 从 /proc/stat 获取信息,计算得到展示结果,/proc/stat 提供的是累计值,展示的数据需要计算时间间隔前后的变化,所以 vmstat 首次运行时显示自系统启动开始的各项统计信息,之后运行 vmstat 将显示自上次运行该命令以后的统计信息
top 输出解释
load average: 7.59, 6.63, 4.27
表示系统在 1, 5, 15 分钟内的平均工作负载分别为 7.59, 6.63, 4.27。
%Cpu(s): 15.9 us, 13.7 sy, 0.0 ni, 63.3 id, 0.3 wa, 0.0 hi, 6.8 si, 0.0 st
- us, user: 花在 userland 的 cpu 时间百分比
- sy, system: 花在 kernel 的 cpu 时间百分比
- ni, nice: 改变过优先级的进程占用 cpu 时间百分比
- id, idle: cpu 空闲状态的时间百分比
- wa, iowait: cpu 空闲并且同时有未完成的 io 请求,占用 cpu 时间的百分比
- cpu 空闲不一定是因为进程都在等待 io,进程休眠还可能是因为等待定时器、等待键盘输入等等原因,但有未完成的 io 请求意味着确实有进程在等待 io
- 因为「有未完成的 io 请求」和 「cpu 空闲」不是明确的因果关系,所以出现 iowait 升高时,不一定是出现 io 瓶颈,还需要根据 io 相关的监控一起判断
- 但是如果机器上的进程很少,只有一个消耗 cpu 和 io 负载的进程,那么出现 iowait 升高,很可能是该进程出现 io 瓶颈
- hi
- si
- st, stolen: time is stolen from a virtual machine
进程列表每项含义:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- PID
- USER
- PR
- NI
VIRT
:virtual memory usage 虚拟内存,单位 kb- 进程 需要的 虚拟内存大小,包括进程使用的库、代码、数据等
- 假如进程申请 100m 的内存,但实际只使用了 10m,那么它会增长 100m,而不是实际的使用量
RES
:resident memory usage 常驻内存- 进程当前使用的内存大小,但不包括 swap out
- 包含其他进程的共享
- 如果申请 100m 的内存,实际使用 10m,它只增长 10m,与
VIRT
相反 - 关于库占用内存的情况,它只统计加载的库文件所占内存大小
SHR
:shared memory 共享内存- 除了自身进程的共享内存,也包括其他进程的共享内存
- 虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小
- 计算某个进程所占的物理内存大小公式:RES – SHR
- swap out 后,它将会降下来
- S
- %CPU: cup 使用率,按
P
根据此列排序 - %MEM: 内存使用率,按
M
根据此列排序 - TIME+
- COMMAND
top 操作
- 筛选用户:按下
u
会出现输入提示Which user (blank for all)
,这时可以输入用户名筛选该用户下的进程。想要重置筛选条件可以重新按下u
之后不输入内容直接按enter
键。 - 按列筛选:按下
o
会出现输入提示add filter #1 (ignoring case) as: [!]FLD?VAL
,这时可以输入filed=value
,例如输入COMMAND=java
筛选COMMAND
列为 java 的进程,之后可以按o
增加筛选条件。想要重置筛选条件可以直接按=
清除筛选条件。 - 排序:
- 按下
M
按内存使用排序 - 按下
P
按 CPU 使用率排序 - 按下
T
按 CPU 使用时间排序 - 按下
N
按 PID 排序 - 按下
R
反向排序
- 按下
/proc/stat
$ cat /proc/stat
cpu 1556845 9332 426834 71797181 20571 0 77501 0 0 0
cpu0 797997 18 205486 35880989 15411 0 37980 0 0 0
cpu1 758848 9314 221348 35916191 5159 0 39520 0 0 0
intr 381840449 56 10 0 0 632 0 0 0 0 0 0 0 15 0 0 0 0 0 0 22 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 32627201 1141 29904569 1652 0 555151 0 3 0 0 0 258369 0 181135 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 694123415
btime 1655693978
processes 766648
procs_running 2
procs_blocked 0
softirq 379953149 6 87302416 1 208869762 993234 0 92 46347545 0 36440093
监控程序一般从 /proc/stat
中采集 CPU 监控数据,/proc/stat
中所有数字都是自系统开机后的累计值。
cpu
以 cpu
开头的一行数据汇总了机器所有 cpu 核的数据,之后的 cpu0
, cpu1
表示不同 cpu 核分开的数据(这里是 2 核 cpu),每一行都有 10 列数字,按顺序分别表示:
- user – time spent in user mode
- nice – time spent processing nice processes in user mode
- system – time spent executing kernel code
- idle – time spent idle
- iowait – time spent waiting for I/O to completed. This is considered idle time too. since Linux 2.5.41
- irq – Time spent serving hardware interrupts. See the description of the intr line for more details. since Linux 2.6.0
- softirq – time spent servicing software interrupts. since Linux 2.6.0
- steal – Time stolen by other operating systems running in a virtual environment. since Linux 2.6.11
- guest – Time spent for running a virtual CPU or guest OS under the control of the kernel. since Linux 2.6.24
- guest_nice – time spent running a virtual CPU for a “niced” guest operating system. since Linux 2.6.33
这里的 CPU 时间以 USER_HZ
(也被称为 Jiffies
) 为单位,通常为 1/100
秒。USER_HZ
为编译时常量,可以通过以下方式查询:
$ getconf CLK_TCK
100
import os
ticks = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
const double ticks = (double)sysconf( _SC_CLK_TCK );
SC_CLK_TCK
为 100,表示每秒有 100 个 CPU 时钟(clock ticks),即每个 CPU 时间为 1/100
秒。
计算 CPU 使用率
根据 /proc/stat
中 CPU 时间数据,可以计算 CPU 使用率。
CPU 使用率是指单位时间内 CPU 工作时间的占比,可以表示为:
CPU Usage (%) = 100 - idle / (user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice) * 100
用以下命令可以计算自系统开机后,CPU 的平均使用率:
cat /proc/stat | grep cpu | tail -1 | awk '{print $5/($2+$3+$4+$5+$6+$7+$8+$9+$10)*100}' | awk '{print "CPU Usage: " 100-$1}'
因为 /proc/stat
中的数据是累计,如果要计算实时的 CPU 使用率,需要以固定时间间隔读取 /proc/stat
,计算此时间内 CPU 使用时间占比。下面的脚本可以每隔 1 秒输出这 1 秒内的 CPU 使用率。
#!/bin/bash
while :; do
# Get the first line with aggregate of all CPUs
cpu_now=($(head -n1 /proc/stat))
# Get all columns but skip the first (which is the "cpu" string)
cpu_sum="${cpu_now[@]:1}"
# Replace the column seperator (space) with +
cpu_sum=$((${cpu_sum// /+}))
# Get the delta between two reads
cpu_delta=$((cpu_sum - cpu_last_sum))
# Get the idle time Delta
cpu_idle=$((cpu_now[4]- cpu_last[4]))
# Calc time spent working
cpu_used=$((cpu_delta - cpu_idle))
# Calc percentage
cpu_usage=$((100 * cpu_used / cpu_delta))
# Keep this as last for our next read
cpu_last=("${cpu_now[@]}")
cpu_last_sum=$cpu_sum
echo "CPU usage at $cpu_usage%"
# Wait a second before the next read
sleep 1
done
其他行含义
intr
: 以intr
开头的一行数据表示自系统开机后发生的所有中断(interrupt),查看/proc/interrupts
可以看到更多详细信息。ctxt
: 表示所有 CPU 上下文切换的次数btime
: 表示自系统开机时的 unix 时间(单位秒)processes
: 表示已创建的进程与线程的数量procs_running
: 表示正在占用 CPU 运行的进程数量procs_blocked
: 表示阻塞状态的进程数量
参考
- 理解 IOWAIT: http://linuxperf.com/?p=33
- https://www.idnt.net/en-US/kb/941772
- https://www.baeldung.com/linux/get-cpu-usage
- https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk65143
- https://klab.tw/2023/01/linux-top-commnad/