CPU 使用率是单位时间内 CPU 使用情况的统计,以百分比的方式展示。
CPU 使用率
为了维护 CPU 时间,Linux 通过事先定义的节拍率(内核中表示为 HZ),触发时间中断,并使用全局变量 Jiffies 记录了开机一来的节拍数。每发生一次时间中断,Jiffies 的值就加 1。
Linux 通过 /proc 虚拟文件系统,向用户空间提供了系统内部状态的信息,而 /proc/stat 提供的就是系统的 CPU 和任务统计信息。
第一列是 CPU 编号,其他列则表示不同场景下 CPU 的累加节拍数。
诸如 top、ps 之类的性能工具展示的 %user、%nice、%system、%iowait、%steal 等等,它们都代表什么意思呢?
- user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
- nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
- system(通常缩写为 sy),代表内核态 CPU 时间。
- idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
- iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
- irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
- softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
- steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
- guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
- guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。
而我们通常所说的 CPU 使用率,就是除了空闲时间外的其他时间占总 CPU 时间的百分比,用公式表示就是:
CPU 使用率 = 1 - 空闲时间 / 总 CPU 时间
如果直接用 /proc/stat 的数据计算 CPU 使用率,它记录的是开机以来的节拍数累加值,所以直接算出来的,是开机以来的平均 CPU 使用率,一般参考价值不大。事实上,为了计算 CPU 使用率,性能工具一般都会取间隔一段时间,比如 3 秒,的两次值,作差后,再计算出这段时间内的平均 CPU 使用率。
不同的工具设置的间隔时间可能不同,比如 top 默认使用 3 秒时间间隔,而 ps 使用的是进程的整个生命周期。
怎么查看 CPU 使用率
top 或者 pidstat 这类的工具。pidstat 可以详细查看进程的用户态 CPU 和内核态 CPU。
- %usr:用户态 CPU 使用率
- %system:内核态 CPU 使用率
- %guest:运行虚拟机 CPU 使用率
- %cpu:总的 CPU 使用率
- CPU:CPU 编号
top 第三行 %CPU 就是系统的 CPU 使用率,含义上面说过。top 默认显示的是所有 CPU 的平均值,按下数字 1,就可以切换到每个 CPU 的使用率了。
每个进程的 %CPU 列,表示进程的 CPU 使用率。它是用户态和内核态 CPU 使用率之和,包括进程用户空间使用的 CPU、通过系统调用执行的内核空间 CPU、以及在就绪队列等待运行的 CPU。
CPU 使用率过高怎么办?
通过 top、ps、pidstat 等工具,能够轻松找到 CPU 使用率过高的进程。接下来就要分析 占用 CPU 的到底是代码里的哪个函数呢?找到后才能更高效、更针对性地进行优化。
GDB 并不适合在性能分析的早期应用,GDB 调试程序的过程会中断程序运行,这在线上环境往往是不允许的,所以 GDB 只适合在性能分析的后期,当你找到了出问题的大致函数后,线下再借助它来进一步调试函数内部的问题。
最推荐的工具是 perf。perf 是 Linux 2.6.31 以后内置的性能分析工具,它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题。两种常见用法:
第一种是 perf top,类似 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数,使用界面如下:
第一行包含三个数据,分别是采样数(Samples)、事件类型(event)和事件总数量(Event count)。比如这个例子中,peft 总共采集了 747 个 CPU 时钟事件,而总事件数为 174906250。采样数如果过少,那下面的排序和百分比就没什么实际参考价值了。
- Overhead,是该符号的性能事件在所有采样中的比例,用百分比来表示。
- Shared,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
- Object,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
- Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。
第二种常见用法是,perf record
和 perf report
。perf top
实时展示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后序分析。而 perf record
则提供了保存数据的功能,保存后的数据,需要你用 peft report
解析展示。
对进程进行跟踪分析其调用:
perf top -g -p <pid>
小结
CPU 使用率是最直观和最常用的系统性能指标,更是我们在排查系统性能问题时,通常会关注的第一个指标。所以我们更要熟悉它的含义,尤其要弄清楚用户(%usr)、Nice(%ni)、系统(%sy)、等待I/O(%wa)、中断(hi)以及软中断(si)这几种不同 CPU 的使用率。比如说:
- 用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。
- 系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。
- I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。
- 软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的 CPU,所以应该着重排查内核中的中断服务程序。
碰到 CPU 使用率升高的问题,可以借助 top、pidstat 等工具,确认引发 CPU 性能问题的来源;再使用 perf 等工具,排查出引起性能问题的具体函数。