如何查看系统的上下文切换情况

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

# 每隔 5 秒输出 1 组数据
vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b 交换 空闲 缓冲 缓存 si so bi bo in cs us sy id wa st
0 0 0 8090200 959848 5225828 0 0 15 14 150 126 6 1 93 0 0
0 0 0 8114904 959872 5201488 0 0 0 270 2056 7736 4 2 94 0 0

重点关注:

cs(context switch):每秒上下文切换的次数

in(interrupt):每秒中断的次数

r(running or runnable):就绪队列长度,即正在运行和等待CPU的进程数

b(blocked):处于不可中断睡眠状态的进程数

vmstat只给出系统总体的上下文切换情况,可以用pidstat -w查看每个进程上下文切换的情况。

重点关注:

cswch:每秒自愿上下文切换的次数,指的是进程无法获取所需资源导致的上下文切换,如I/O、内存等系统资源 不足

ncswch:每秒非自愿上下文切换的次数,指的是时间片耗尽等其他原因,被系统强制调度发生的上下文切换,如大量进程抢夺CPU。

# 每隔5秒输出1组数据
dyy@dyy-Lenovo-ThinkBook-14-IIL:~$ pidstat -w 5
Linux 5.4.0-74-generic (dyy-Lenovo-ThinkBook-14-IIL) 2021年09月11日 _x86_64_(8 CPU)
19时36分03秒 UID PID cswch/s nvcswch/s Command
19时36分08秒 0 1 259.28 0.20 systemd
19时36分08秒 0 22496 3.79 0.00 kworker/6:0-events
19时36分08秒 0 22508 2.20 0.00 kworker/4:3-events
19时36分08秒 1000 22606 0.20 0.00 pidstat

模拟压测

# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题
$ sysbench --threads=10 --max-time=300 threads run

运行之后,在另外一个终端上可以看出:
cs突然增加了许多:

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b 交换 空闲 缓冲 缓存 si so bi bo in cs us sy id wa st
0 0 0 6177232 992200 6797896 0 0 0 0 2376 7604 6 2 92 0 0
0 0 0 6191628 992208 6783560 0 0 0 52 2136 6504 4 2 94 0 0
9 0 0 6206244 992208 6767868 0 0 0 0 2176 204091 6 9 84 0 0
8 0 0 6205984 992208 6767608 0 0 0 0 3140 1344343 18 53 28 0 0
7 0 0 6195676 992208 6778792 0 0 0 0 4403 1283034 19 54 27 0 0
7 0 0 6194896 992208 6779332 0 0 0 0 4521 1370898 18 50 32 0 0
3 0 0 6201196 992208 6773336 0 0 0 4 4633 1309928 19 50 31 0 0

r 列:就绪队列的长度变长所以肯定会有大量的 CPU 竞争。
us(user)和 sy(system)列:这两列的 CPU 使用率加起来上升到了 100%,其中系统 CPU 使用率,也就是 sy 列高达 84%,说明 CPU 主要是被内核占用了。
in 列:中断次数也上升到了 4000左右,说明中断处理也是个潜在的问题。

使用命令:

# 每隔 1 秒输出一组数据(需要 Ctrl+C 才结束)
# -wt 参数表示输出线程的上下文切换指标
$ pidstat -wt 1

sysbench 进程(也就是主线程)的上下文切换次数看起来并不
多,但它的子线程的上下文切换次数却有很多。

平均时间:   UID      TGID       TID   cswch/s nvcswch/s  Command
平均时间: 0 - 28411 48857.14 10855.95 |__sysbench
平均时间: 0 - 28412 49817.26 13526.39 |__sysbench
平均时间: 0 - 28413 48023.41 13608.33 |__sysbench
平均时间: 0 - 28414 48886.31 12581.94 |__sysbench
平均时间: 0 - 28415 48584.13 12016.27 |__sysbench
平均时间: 0 - 28416 47521.83 13308.93 |__sysbench
平均时间: 0 - 28417 48813.89 12481.55 |__sysbench
平均时间: 0 - 28418 49105.16 14612.70 |__sysbench
平均时间: 0 - 28419 50239.29 13927.38 |__sysbench
平均时间: 0 - 28420 47539.09 13134.33 |__sysbench

当然也可以通过下面命令查看高亮地区,即切换频繁的地区:

# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts

vmstat、sysbench、/proc/interrupts,性能压测_缓存
你可以发现,变化速度最快的是重调度中断(RES),这个中断类型表示,唤醒空闲状态的 CPU 来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同 CPU 的机制,通常也被称为处理器间中断(Inter-Processor Interrupts,IPI)。
所以,这里的中断升高还是因为过多任务的调度问题。

总结

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