前言

最近准备再做压测,对于压测,需要有指标去寻找瓶颈,CPU正是其中关键一环。本文聚焦于CPU角度,理清CPU的指标有哪些,总结CPU性能指标概念。

CPU性能指标有哪些

通过常用的top命令,可以看出CPU的大部分指标:

  1. top - 12:17:02 up 11 days, 21:04, 0 users, load average: 1.85, 1.67, 1.75
  2. Tasks: 23 total, 1 running, 22 sleeping, 0 stopped, 0 zombie
  3. %Cpu(s): 2.7 us, 2.1 sy, 0.0 ni, 95.1 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st

其中CPU性能指标相关的包括:

  • load average:平均负载
  • us: user 用户空间占用CPU的百分比
  • sy: system 系统空间占用CPU的百分比
  • ni: nice 跟进程优先级相关,指的是改变过优先级的进程占用CPU的百分比
  • id: idle 空闲CPU百分比
  • wa: iowait IO等待占用CPU的百分比
  • hi: 硬中断(Hardware Interrupts)占用CPU的百分比
  • si: 软中断(Software Interrupts)占用CPU的百分比
  • st: steal,下文会讲

上面是top命令能看到的东西。而总的来说,CPU的性能指标主要包括

  • 平均负载
  • CPU使用率
  • 上下文切换
  • CPU缓存命中率

下面分别介绍这些性能指标。

平均负载

简单来说,平均负载代表系统繁忙程度。平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。

  • 所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。
  • 不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。所以,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

平均负载有三个值,如load average: 1.85, 1.67, 1.75,分别是1分钟、5分钟、15分钟内系统的平均负荷。
那怎么看这些值有没有问题呢?
判断平均负载的值有没有问题,是跟总逻辑CPU数相关。假设总逻辑CPU数是1:

  • 当系统负荷持续大于0.7,你必须开始调查了,问题出在哪里,防止情况恶化。
  • 当系统负荷持续大于1.0,你必须动手寻找解决办法,把这个值降下来。
  • 当系统负荷达到5.0,就表明你的系统有很严重的问题,长时间没有响应,或者接近死机了。你不应该让系统达到这个值。

这里总逻辑CPU数 = 物理CPU个数 X 每个物理CPU的核数 X 超线程数(一般为2)
如果总逻辑CPU数是1 4 2 = 8,那么可接受的系统负载就是8,当超过8时,意味着有进程在等待CPU处理。

CPU使用率

CPU使用率包括:

  • 用户CPU使用率
  • 系统CPU使用率
  • 等待I/O的CPU使用率
  • 中断的CPU使用率
  • 窃取CPU使用率(steal)和客户CPU使用率(guest)

用户CPU使用率

表示CPU在用户态运行的时间百分比,包括

  • 用户态CPU使用率(%user),不包含nice进程
  • nice进程(改变过优先级的进程)的用户态CPU使用率(%nice)

nice进程会有一个nice值,范围从-20到+19,正值表示低优先级,负值表示高优先级,值为零则表示没有调整该进程的优先级。nice值最低优先级越高,所以值-20使得一项任务变得非常重要。与之相反,如果任务的nice为+19,则表示它是一个高尚的、无私的任务,允许所有其他任务比自己享有宝贵的CPU时间的更大使用份额,这也就是nice的名称的来意。

用户CPU使用率高,通常说明有应用程序比较繁忙。

系统CPU使用率

表示CPU在内核态运行的时间百分比(%system),不包含中断
内核态执行的任务如系统调用、调度任务等。系统CPU使用率高,说明内核比较繁忙

等待I/O的CPU使用率

表示等待I/O完成的时间百分比,也用iowait(%wa)表示
iowait高,通常说明系统与硬件设备的I/O交互时间比较长。

中断的CPU使用率

包括软中断(%si)和硬中断(%hi),分别表示内核调用软中断处理程序、硬中断处理程序的时间百分比。
以网卡接收数据包为例子,网卡接收到数据包后,会通过硬件中断的方式,通知内核有新的数据到了,这时内核就调用中断处理程序来响应它,这个程序包含上下半部:

  • 上半部是快速处理,把网卡的数据读到内存中,然后更新硬件寄存器的状态(表示数据已经读好了),最后再发送一个软中断信息,通知下半部做进一步的处理。上半部直接处理硬件请求,就是我们说的硬中断,特点是快速执行
  • 下半部被软中断信号唤醒后,从内存中找到网络数据,再按照网络协议栈,对数据进行解析和处理,直到把它送给应用程序。下半部是由内核处理,也就是我们说的软中断,特点是延迟执行。

那为什么要分软中断和硬中断呢?
我们知道,由于需要快速响应硬件的任务,对于中断处理来说会打断CPU正在执行的任务(在进程上下文切换一节也会说到)去响应中断,这时还会临时关闭响应中断,也就是不会再去响应新的中断。为了减少对正常进程运行调度,以及尽量避免中断丢失,就将中断处理拆成上下半部,由硬中断快速响应,响应之后先返回,再由软中断以内核线程的方式执行下半部的任务。

软中断和硬中断的使用率高,通常说明系统发生了大量的中断,如有大量的网卡接收数据包的事件。

窃取CPU使用率和客户CPU使用率

窃取CPU使用率(%steal)指的是被其它虚拟机占用的CPU时间百分比
客户CPU使用率(%guest)指运行客户虚拟机的CPU时间百分比

上下文切换

我们知道,Linux是多任务操作系统,他支持多个任务“同时运行”,当前这些任务不是真的在同时运行,只是将CPU的执行划分时间片,轮流分配给这些任务,这些时间片很短,看起来像是任务同时在运行。
每个任务在运行前,CPU需要知道这些任务的运行上下文(CPU上下文),如知道从哪里开始运行等数据,这些数据存放在通过CPU寄存器(CPU内置的容量小但运行速度极快的内存)和程序计数器(存储CPU正在执行的指令位置和下一条指令位置)。任务不断执行,就伴随着CPU上下文的切换。

CPU的上下文切换是Linux正常工作的核心功能之一,一般情况下不需要我们关注。但过多的上下文切换,会把CPU时间消耗在CPU上下文的保存和恢复上,从而缩短进程真正的运行时间,导致系统的整体性能大幅下降。

CPU上下文切换出现的场景包括:

  • 进程上下文切换
  • 线程上下文切换
  • 中断上下文切换

进程上下文切换

进程上下文切换出现的场景包括:

  • 为了公平调度各个进程,CPU时间以时间片的形式切换,时间片耗尽了就会进行进程切换
  • 进程在系统资源不足(如内存不足)时,要等到资源满足后才能继续运行,这个时候进程也会挂起,进行进程切换
  • 进程通过sleep挂起,会进行进程切换
  • 有更高优先级进程运行,为了保证更高优先级进程的运行,会挂起当前进程,进行进程切换
  • 发生硬件中断,CPU上的进程会被中断挂起,转而执行内核中的中断服务程序

线程上下文切换

我们知道,线程是调度的基本单位,而进程是资源拥有的基本单位。内核中的任务调度,实际上是针对线程,而进程给线程提供了虚拟内存、全局变量等资源。
这样,由于线程上下文切换发生在同一个进程中,对于虚拟内存等资源来说是不需要动的,只需要切换线程的私有数据,如寄存器等线程私有的数据,因此线程上下文切换相比进程上下文切换消耗更少的资源

中断上下文切换

为了快速响应硬件的事件,中断处理器会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍可以从原来的状态恢复运行。
对于检查中断的时机可以简单了解下,如图,在指令周期中,会有环节去检查中断。
image.png
中断上下文切换,只涉及内核态中断服务程序执行所必需的状态,包括CPU寄存器、硬件中断参数等,不涉及进程的用户态。
对同一个CPU来说,中断处理比进程拥有更高的优先级。另外跟进程上下文切换一样,中断上下文切换次数过多也会消耗大量的CPU时间。当发现中断次数过多时,需要注意排查是否会有性能问题。

CPU缓存命中率

由于CPU的发展速度远快于内存的发展,CPU的处理速度就比内存的访问速度快得多。为了提升CPU处理性能,CPU多级缓存就出现了,缓存了内存的热点数据。根据优先级不同,分为L1、L2、L3等三级缓存。
因此,CPU缓存的命中率就跟性能相关,命中率越高,性能越好。

总结

本文主要讲了CPU性能指标,通过如下的脑图可以有个整体视角 理解Linux CPU性能指标 - 图2这里强调一点是,这些指标不是相互孤立的,彼此之间可能存在关系。比如中断、上下文切换由内核调度,中断、上下文切换一多,系统CPU使用率也会跟着上升。把他们拆分出来,可以更好地定位是哪里可能有问题,而不是只能看着系统CPU比较大的指标:)

参考链接