重要的上下文切换概念
自愿上下文切换
是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换
非自愿上下文切换
非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换
工具
vmstat
- 上下文相关输出解析:
cs(context switch)是每秒上下文切换的次数。
in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数。
pidstat
- 选项
-w 显示每个进程的上下文切换情况
-t 输出线程的指标
# 每隔5秒输出1组数据
$ pidstat -w 5
Linux 4.15.0 (ubuntu) 09/23/18 _x86_64_ (2 CPU)
08:18:26 UID PID cswch/s nvcswch/s Command
08:18:31 0 1 0.20 0.00 systemd
08:18:31 0 8 5.40 0.00 rcu_sched
...
- 相关输出解析:
- cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数
- nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数。
sysbench
- 模拟系统多线程调度
#以10个线程运行5分钟的基准测试,模拟多线程切换的问题
$ sysbench --threads=10 --max-time=300 threads run
/proc/interrupts
/proc 实际上是 Linux 的一个虚拟文件系统,用于内核空间与用户空间之间的通信。/proc/interrupts 就是这种通信机制的一部分,提供了一个只读的中断使用情况。/proc/interrupts是只读文件
- 使用watch -d 监控/proc/interrupts文件
# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts
CPU0 CPU1
...
RES: 2450431 5279697 Rescheduling interrupts
...
重调度中断(RES)个中断类型表示,唤醒空闲状态的 CPU 来调度新的任务运行,通常也被称为处理器间中断(Inter-Processor Interrupts,IPI)
案例
多线程调度
- 模拟多线程
# 以10个线程运行5分钟的基准测试,模拟多线程切换的问题
$ sysbench --threads=10 --max-time=300 threads run
- 查看上下文切换变化
#每隔1秒输出1组数据(需要Ctrl+C才结束)
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
0 0 930152 65228 756172 0 0 4 0 125 226 0 1 99 0 0
0 0 0 930168 65232 756232 0 0 48 0 80 151 0 0 100 0 0
0 0 0 930168 65236 756216 0 0 8 0 109 210 0 0 100 0 0
0 0 0 929988 65240 756220 0 0 4 0 113 216 0 0 100 0 0
0 0 0 930028 65248 756224 0 0 12 0 111 205 1 1 97 1 0
0 0 0 930044 65260 756228 0 0 12 12 130 240 0 0 100 0 0
8 0 0 925256 65264 759696 0 0 3452 0 201 26820 4 3 85 8 0
9 0 0 924388 65268 759680 0 0 4 272 1119 1579178 6 94 0 0 0
9 0 0 924248 65272 759708 0 0 32 0 1091 1581345 7 93 0 0 0
从一开始的100-250上下文切换数,到模拟后的百万级.切换数极数上升
- 追踪具体进程
# 每隔1秒输出一组数据(需要 Ctrl+C 才结束)
# -wt 参数表示输出线程的上下文切换指标
$ pidstat -wt 1
08:14:05 UID TGID TID cswch/s nvcswch/s Command
...
08:14:05 0 10551 - 6.00 0.00 sysbench
08:14:05 0 - 10551 6.00 0.00 |__sysbench
08:14:05 0 - 10552 18911.00 103740.00 |__sysbench
08:14:05 0 - 10553 18915.00 100955.00 |__sysbench
08:14:05 0 - 10554 18827.00 103954.00 |__sysbench
...
- 判断终端类型
# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts
CPU0 CPU1
...
RES: 2450431 5279697 Rescheduling interrupts
...
总结
- 根据不同的上下文切换,可以得到如下结论:
- 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
- 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈;
- 中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件来分析具体的中断类型。
tips
- stress和sysbench两个工具在压测过程中的对比发现:
- stress基于多进程的,会fork多个进程,导致进程上下文切换,导致us开销很高;
sysbench基于多线程的,会创建多个线程,单一进程基于内核线程切换,导致sy的内核开销很高;