怎么查看系统的上下文切换情况?
通过前面的学习我们知道,过多的上下文切换,会把CPU时间消耗在寄存器、内存栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成了系统性能大幅下降的一个元凶。
既然上下文切换对系统性能影响那么大,到底要怎么查看上下文切换呢?我们可以通过vmstat来查询系统的上下文切换情况。
vmstat是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析CPU上下文切换和中断的次数。
比如:
# 每隔5秒输出1组数据
#vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 14240388 162080 1381008 0 0 0 2 25 33 0 0 100 0 0
每一列含义可参考:https://blog.csdn.net/wgq2020/article/details/134094555。我这里重点强调下以下四列内容:
in(interrupt):每秒的中断次数。
cs(context switch):每秒的上下文切换次数。
r(Running or Runnable):是就绪队列的长度,也就是正在运行和等待CPU的进程数。
b(Blocked):则是处于不可中断睡眠状态的进程数。
可以看到,这个例子中上下文切换次数cs是33次,而系统中断次数in是25次,而就绪队列长度r和不可中断状态进程数b都是0。
vmstat只给出了系统总体的上下文切换情况,想要查看每个进程的详细情况,就需要使用我们前面提到过的pidstat了。给它加上-w选项,你就可以查看每个进程上下文切换情况了
#每隔5秒输出1组数据
#pidstat -w 5
Linux 3.10.0-1160.92.1.el7.x86_64 (ensp-nginx) 04/10/2024 _x86_64_ (8 CPU)
03:53:09 PM UID PID cswch/s nvcswch/s Command
03:53:14 PM 0 9 9.60 0.00 rcu_sched
03:53:14 PM 0 11 0.20 0.00 watchdog/0
03:53:14 PM 0 12 0.20 0.00 watchdog/1
...
cswch表示每秒自愿上下文切换(voluntary context switches)的次数
nvcswch表示每秒非自愿上下文切换(non voluntary context switches)的次数
这两个概念一定要记住,因为他们意味着不同的性能问题:
1.所谓自愿上下文切换,是指进程无法获取 所需资源,导致的上下文切换。
比如,I/O、内存等系统资源不足时,就会发生自愿上下文切换。
2.而非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。
比如说,大量进程都在争抢CPU时,就容易发生非自愿上下文切换。
案例分析
一、环境与测试工具准备
1、操作系统
[root@ensp-nginx ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
2、测试工具
yum install sysbench sysstat -y
3、机器配置
#grep 'model name' /proc/cpuinfo |wc -l #cpu
8
# grep 'MemTotal' /proc/meminfo
MemTotal: 16264988 kB #内存
二、操作和分析
首先,在第一个终端运行sysbench,模拟系统多线程调度瓶颈:
#以10个线程运行5分钟的基准测试,模拟多线程切换的问题
# sysbench --threads=10 --max-time=300 threads run
第二个终端运行vmstat,观察上下文切换情况
# 每隔1秒输出1组数据,需要ctrl+c才结束
#vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
11 0 0 14226056 162236 1388140 0 0 0 0 170307 818244 16 84 37 0 0
9 0 0 14226056 162236 1388140 0 0 0 0 167015 815787 16 84 37 0 0
你应该可以发现,cs列的上下文切换次数骤然上升到了81万。同时注意观察其他几个指标:
r列:就绪队列的长度已经到了11,所以肯定会有CPU竞争。
us(user)和sy(system)列:这2列的CPU使用率加起来上升到了100%,其中系统CPU使用率,也就是sy列高达84%,说明CPU主要时被内核占用了。
in列:中断次数也上升到17万,说明中断处理也是问题。
# 每隔1秒输出一组数据 -w参数表示输出进程切换指标 -u表示输出CPU使用指标
#pidstat -w -u 1
Linux 3.10.0-1160.92.1.el7.x86_64 (ensp-nginx) 04/11/2024 _x86_64_ (8 CPU)
...
10:45:17 AM UID TGID TID %usr %system %guest %CPU CPU Command
10:45:18 AM 0 21746 - 116.00 491.00 0.00 607.00 2 sysbench
10:45:18 AM 0 - 21747 8.00 24.00 0.00 32.00 1 |__sysbench
10:45:18 AM 0 - 21748 5.00 23.00 0.00 28.00 7 |__sysbench
10:45:18 AM 0 - 21749 5.00 25.00 0.00 30.00 1 |__sysbench
10:45:18 AM 0 - 21750 4.00 24.00 0.00 28.00 5 |__sysbench
...
从pidstat的输出可以发现,CPU使用率升高果然时sysbench导致的,它的CPU使用率高达600%。
#-wt参数表示输出线程的上下文切换指标
#pidstat -wt 1
10:34:44 AM UID TGID TID cswch/s nvcswch/s Command
...
10:34:45 AM 0 21747 - 3.96 0.00 sysbench
10:45:18 AM 0 - 21747 21724.00 7354.00 |__sysbench
10:45:18 AM 0 - 21748 22547.00 6817.00 |__sysbench
10:45:18 AM 0 - 21749 22197.00 6954.00 |__sysbench
10:45:18 AM 0 - 21750 22635.00 6891.00 |__sysbench
10:45:18 AM 0 - 21751 21860.00 7123.00 |__sysbench
...
你应该能看到,虽然sysbench进程(也就是主线程)的上下文切换次数并不多,但它的子线程的上下文切换次数却很多。看来上下文切换罪魁祸首,还是过多的sysbench线程。
那是不是到这里就可以结束了呢?
当然不是。前面观察系统指标时,除了上下文切换频率升高,中断次数也上升到了17万,但是到底什么导致的中断次数上升,我们还不清楚。
既然是中断,我们都知道,它只发生在内核态,而pidstat只是一个进程的性能分析工具,并不提供任何关于中断的信息,怎么才能知道中断发生的类型呢?
从/proc/interrupts这个只读文件中读取。/proc实际上时Linux的一个虚拟文件系统,用于内核空间与用户空间之间的通信。/proc/interrupts就是这种通信机制的一部分,提供了一个只读的中断使用情况。
第三个终端里,运行如下:
# -d 参数表示高亮显示变化的区域
# watch -d cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
...
RES: 73755215 55944503 68991624 55527260 71992122 55675436 71387076 55803899 Rescheduling interrupts
...
观察一段时间,你可以发现,变化速度最快的是重调度中断(RES),这个中断类型表示,唤醒空闲状态的CPU来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同CPU的机制,通常也被称为处理器间中断(Inter-Processor Interrupts,IPI).
所以,这里的中断升高还是因为过多的任务的调度问题,跟前面上下文切换次数的分析结果是一致的。
通过这个案例,你应该也发现了多工具、多方面指标对比观测的好处。如果最开始,我们只用了pidstat观测,这些很严重的上下文切换线程,压根就发现不了。
现在再回到最初的问题,每秒上下文切换多少次才算正常呢?
这个数值其实取决于系统本身的CPU性能。在我看来,如果系统的上下文切换次数比较稳定,那么从数百到一万内,都应该算正常。但当上下文切换次数超过一万次,或者切换次数出现数量级的增长时,就很可能出现了性能问题。
这时,你还需要根据上下文切换的类型,再分析:
1. 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了I/O等其他问题
2. 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢CPU,说明CPU的确成了瓶颈。
3. 中断次数多了,说明CPU被中断处理程序占用,还需要通过查看/proc/interrupts文件来分析具体的中断类型。
小结
通过sysbench案例,学习了上下文切换问题的分析思路。碰到上下文切换次数过多的问题时,我们可以借助vmstat、pidstat和/proc/interrupts等工具,来辅助排除性能问题的根源