在本文中,我将进一步讨论如何分析 CPU 上下文切换问题。

检查 CPU 的上下文切换

我们知道,过多的上下文切换会消耗 CPU 的时间来保存和恢复寄存器、程序计数器、内核栈和虚拟内存等数据,从而导致系统性能显着下降。


(资料图片)

既然上下文切换对系统性能的影响如此之大,那么我们如何检查它呢?好了,你可以使用vmstat工具来查询你系统的上下文切换。

vmstat

vmstat是一种常用的系统性能分析工具。主要用于分析内存使用情况,也常用于分析 CPU 上下文切换和中断的次数。

例如vmstat 5(5 秒输出间隔):

让我们看一下输出:

cs(context switch):每秒上下文切换的次数。in(interrupt):每秒的中断数。r(running | runnable):就绪队列的长度,即正在运行和等待 CPU 的进程数。b(blocked):处于不间断睡眠状态的进程数。

在上面的例子中,我们可以看到上下文切换次数为33​次,系统中断次数为25​次,就绪队列长度,不间断状态进程数均为0。

pidstat

vmstat​工具只给出了系统的整体上下文切换的信息。要查看每个进程的详细信息,您需要使用pidstat​。添加-w选项,您可以看到每个进程的上下文切换:

例如:

$ pidstat -w 5Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU)08:18:26      UID       PID   cswch/s nvcswch/s  Command08:18:31        0         1      0.20      0.00  systemd08:18:31        0         8      5.40      0.00  rcu_sched...

结果中有两列需要我们注意:cswch​和nvcswch​。其中,cswch​表示每秒自愿上下文切换的次数,nvcswch表示每秒非自愿上下文切换的次数。

自愿上下文切换:指进程无法获得所需资源而导致的上下文切换。例如,当 I/O 和内存等系统资源不足时,就会发生自愿上下文切换。非自愿上下文切换:指进程因时间片已过期而被系统强制重新调度时发生的上下文切换。例如,当大量进程竞争 CPU 时,很容易发生非自愿的上下文切换。

您必须牢记这两个概念,因为它们意味着不同的性能问题。

案例分析

既然您知道如何查看这些指标,那么就会出现另一个问题,上下文切换频率多久才是正常的呢?让我们看一个示例案例。

我们将使用​​sysbench​​​,一个多线程的基准测试工具通过生成负载来模拟上下文切换过多的问题。假设您已经在 Linux 系统上安装了sysbench​和sysstat。

在我们模拟负载之前,让我们在一个终端中运行一下vmstat:

在这里可以看到当前的上下文切换次数cs​是35​,中断次数in​是19​,r​和b​都是0。由于我目前没有其他任务在运行,因此它们是空闲系统中的上下文切换数量。

现在让我们运行sysbench来模拟多线程调度系统的瓶颈:

$ sysbench --threads=10 --max-time=300 threads run

现在,您应该会看到vmstat输出了与上面不同的结果:

应该可以发现cs​栏的上下文切换次数从之前的35​次突增到139万次。同时,注意观察其他几个指标:

r​:就绪队列的长度已达到8us​和sy:us和sy的 CPU 使用率加起来是100%,系统 CPU 使用率是84%,说明 CPU 主要被内核占用。in​:中断数也上升到了10000,说明中断处理也是一个潜在的问题。

结合这些指标我们可以知道系统的就绪队列太长了,也就是有太多的进程在运行等待 CPU,导致大量的上下文切换,而大量的上下文切换导致了系统 CPU 使用率的增长。

那么是什么过程导致了这些问题呢?

我们继续分析,同时在第三个终端使用pidstat,看看 CPU 和进程上下文切换的情况:

$ pidstat -w -u 108:06:33      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command08:06:34        0     10488   30.00  100.00    0.00    0.00  100.00     0  sysbench08:06:34        0     26326    0.00    1.00    0.00    0.00    1.00     0  kworker/u4:208:06:33      UID       PID   cswch/s nvcswch/s  Command08:06:34        0         8     11.00      0.00  rcu_sched08:06:34        0        16      1.00      0.00  ksoftirqd/108:06:34        0       471      1.00      0.00  hv_balloon08:06:34        0      1230      1.00      0.00  iscsid08:06:34        0      4089      1.00      0.00  kworker/1:508:06:34        0      4333      1.00      0.00  kworker/0:308:06:34        0     10499      1.00    224.00  pidstat08:06:34        0     26326    236.00      0.00  kworker/u4:208:06:34     1000     26784    223.00      0.00  sshd

从pidstat​的输出可以发现,CPU 使用率的增加确实是sysbench​造成的,它的 CPU 使用率已经达到了100%​。但上下文切换来自其他进程,包括非自愿上下文切换频率最高的pidstat​,以及自愿上下文切换频率最高的内核线程kworker​和sshd。

注意:默认情况下pidstat​只显示进程的上下文切换,如果要查看实际线程的上下文切换,请添加-t选项。

中断

要找出中断数量也很高的原因所在,您可以检查/proc/interrupts文件。该文件会提供一个只读的中断使用情况。

$ watch -d cat /proc/interrupts           CPU0       CPU1...RES:    2450431    5279697   Rescheduling interrupts...

观察一段时间后,可以发现变化最快的是重新调度中断(RES, REScheduling interrupt)。这种中断类型表明处于空闲状态的 CPU 被唤醒以调度新的任务运行。所以这里的中断增加是因为太多的任务调度问题,这和前面上下文切换次数的分析结果是一致的

现在回到最初的问题,每秒多少次上下文切换是正常的?

这个值实际上取决于系统本身的 CPU 性能。在我看来,如果系统的上下文切换次数比较稳定的话,几百到一万应该是正常的。但是,当上下文切换次数超过10000,或者切换次数快速增加时,很可能是出现了性能问题。

结论

此时,你应该可以根据上下文切换的类型做一些具体的分析了。

自愿上下文切换较多,说明进程在等待资源,可能会出现 I/O 饱和等其他问题。非自愿上下文切换较多,说明进程正在被强制调度,也就是都在争抢 CPU,说明 CPU 确实产生了瓶颈。中断次数增多,说明 CPU 被中断处理程序占用,需要通过查看​​/proc/interrupts​​文件来分析具体的中断类型。

推荐内容