点击上方【蓝字】关注博主
“ 在计算机系统中,CPU上下文切换是实现多任务处理的核心机制之一,但其频繁发生可能导致显著的性能损失。本文将深入探讨上下文切换的定义、类型及其对系统性能的影响。我们将讨论造成上下文切换频繁的各种因素,并介绍有效的监控和优化策略。通过这些措施,系统管理员可以提升CPU利用率,从而优化整体系统性能与用户体验。”
什么是CPU上下文切换?
CPU上下文切换是操作系统中一种重要的机制,它指的是在多个进程或线程之间切换CPU控制的过程。这个过程涉及保存当前正在执行的进程或线程的状态(称为“上下文”),并加载另一个进程或线程的状态。这种切换使得操作系统能够在多个任务间高效地分配CPU资源。
所谓的上下文切换,就是把上一个任务的寄存器和计数器保存起来,然后加载新任务的寄存器和计数器,最后跳转到新任务的位置开始执行新任务。
根据任务的不同,CPU 的上下文切换就可以分为几个不同的场景,也就是进程上下文切换、线程上下文切换以及中断上下文切换。
具体步骤包括:
保存当前上下文:将当前进程或线程的寄存器值、程序计数器、堆栈指针等信息保存到进程控制块(PCB)或线程控制块(TCB)中。
选择下一个要运行的任务:操作系统根据调度算法选择下一个运行的进程或线程。
加载新上下文:从选定的进程或线程的PCB/TCB中恢复其状态信息,如寄存器值和程序计数器等。
切换到新任务:CPU开始执行新选择的进程或线程。
哪些因素会导致频繁的上下文切换?
过多的进程或线程:系统中同时存在过多的进程或线程,会导致操作系统频繁地切换任务,以满足每个任务的执行需求。
低优先级进程的竞争:如果多个低优先级进程在争用CPU资源,操作系统为平衡负载而频繁切换也可能导致频繁的上下文切换。
短时任务:频繁出现在短时间内的快速任务,例如信号处理程序或小型计算任务,会导致上下文切换次数显著增加。
I/O操作:在需要等待I/O操作(例如磁盘读写或网络请求)时,进程会被挂起,操作系统会切换到其他进程,这种情形下,如果I/O操作非常频繁,将会导致上下文切换频繁发生。
进程优先级变化:动态调整进程优先级(比如实时系统中的高优先级任务抢占低优先级任务),可能导致频繁的上下文切换。
高频率的定时器中断:操作系统用定时器中断来实现时间片轮转调度,如果中断频率过高,会增加上下文切换的频率。
资源锁竞争:多线程环境中,如果多个线程在争抢共享资源,可能导致线程不断被挂起和恢复,增加上下文切换。
上下文切换是实现多任务处理的关键,但频繁的上下文切换可能导致性能下降,因为它涉及一定的开销,包括保存和加载状态信息的时间。因此,操作系统通常会优化调度策略,以减少不必要的上下文切换。
有哪些上下文切换?
2.1、系统调用上下文切换
Linux 进程既可以在用户空间运行,又可以在内核空间中运行。
当它在用户空间运行时,被称为进程的用户态;当它进入进入内核空间的时候,被称为进程的内核态
从用户态到内核态的转变过程,需要通过系统调用来完成
CPU 寄存器里原来的指令位置是在用户态。但是为了执行内核态代码,需要先把用户态的位置保存起来,然后寄存器更新为内核态指令的新位置。最后跳转到内核态运行内核任务。
当系统调用结束后,CPU 寄存器需要恢复原来保存的用户态位置,然后再切换到用户空间,继续运行进程。一次系统调用发生了两次 CPU 上下文切换!
系统调用过程中对用户态的资源没有任何影响,也不会切换进程,所以也称为特权模式切换。
2.2、进程上下文切换
为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行。(被动切换)
进程在系统资源不足,这个时候进程也会被挂起,并由系统调度其他进程运行。(主动切换)
当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度。
当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行。
发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序。
2.3、线程上下文切换
线程与进程的区别在于:线程是调度的基本单位,而进程是资源分配基本单位。内核中的任务调度,实际调度的是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。
当进程只有一个线程时,可以认为进程就等于线程。
当进程拥有多个线程时,共享虚拟内存和全局变量等资源。这些资源在上下文切换时不需要修改。
线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时需要保存。
线程的上下文切换分为两种:
前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。
前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据
2.4、中断上下文切换
为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。
跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。中断上下文只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等。
怎么查看上下文切换?
过多的上下文切换,会把 CPU 时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成了系统性能大幅下降的一个元凶。
常用的CPU性能监控工具有:perf, iostat, top, vmstat 等。
perf 是Linux内核自带的性能分析工具,能够对CPU的性能进行采样,分析应用的性能瓶颈。特点:
支持多种事件的监控,包括 CPU 周期、缓存命中率、分支预测等。
可生成详细的性能报告,帮助开发者找到瓶颈。
提供命令如
perf stat
,perf record
,perf report
等用于收集和分析数据。
iostat 用于监控系统输入/输出设备的统计信息。特点:
提供 CPU 使用情况和各个设备的输入/输出统计。
有助于识别I/O瓶颈,优化存储设备的性能。
使用简单,常用于系统性能监视。
top 是一个实时系统监控工具,显示 CPU、内存和进程的使用情况。特点:
显示活动进程的实时列表,包括 CPU 使用率、内存使用率等。
可以按 CPU、内存等指标进行排序,方便用户监控系统负载。
提供交互式界面,可以杀死进程或改变其优先级。
vmstat 提供关于虚拟内存、进程、CPU活动的统计信息。特点:
报告系统的虚拟内存信息、进程、CPU活动等,帮助评估系统的性能。
提供内存、交换、I/O、系统和CPU等多维度的信息。
适合长时间监控和诊断。
htop 是 top 的增强版,提供更友好的用户界面。
mpstat 提供CPU的各个核心的使用情况统计。特点:
可以监控各个CPU核心的使用情况,适合多核CPU的性能监控。
提供详细的用户、系统、空闲等CPU活动信息。
适合分析多核处理器的性能瓶颈。
sar 提供系统活动报告,用于收集和报告各类系统性能数据。特点:
可以定期收集CPU、内存、网络、I/O等各方面的性能数据。
能够生成历史数据,适合长期监控和分析。
一般配合
sysstat
包使用,支持多种统计项。
dstat 是一个多功能的系统监控工具,整合了多种监控工具的功能。特点:
同时显示 CPU、I/O、网络、内存等统计信息,提供全面的视图。
提供实时数据,易于观察系统的当前状态。
可以输出成CSV格式,方便做后续分析。
vmstat [选项] [间隔] [次数]
选项 | 说明 |
---|---|
-a | 显示活动的内存信息。 |
-m | 显示内存页信息。 |
-s | 显示内存的系统统计信息。 |
-d | 显示块设备的统计信息。 |
-p | 显示每个分区的统计信息。 |
-t | 显示时间戳。 |
# 每隔5秒输出1组数据
ubuntu:~$ 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
17 0 12 1179508 469892 3315788 0 0 6 20 49 74 0 0 99 0 0
16 0 12 1179376 469892 3315788 0 0 0 0 1048 678 100 0 0 0 0
16 0 12 1179376 469892 3315788 0 0 0 0 1045 675 100 0 0 0 0
16 0 12 1179376 469892 3315788 0 0 0 0 1047 685 100 0 0 0 0
类别 | 字段 | 描述 |
---|---|---|
procs | r | 就绪队列的长度,正在运行和等待CPU的进程数 (Runnable processes) |
b | 等待I/O的进程数 (Blocked processes),处于不可中断睡眠状态的进程数 | |
memory | swpd | 使用的交换空间大小 (Swap space used) |
free | 空闲物理内存 (Free memory) | |
buff | 使用的缓冲区内存 (Buffered memory) ,是I/O系统存储的磁盘块文件的元数据的统计信息。 | |
cache | 使用的缓存内存 (Cached memory),是操作系统用来缓存磁盘数据的缓冲区,操作系统会自动一调节这个参数,在内存紧张时操作系统会减少cache的占用空间来保证其他进程可用。 | |
swap | si | 从交换空间交换到物理内存 (Swap in) 。值较大时,说明系统频繁使用交换区,应该查看操作系统的内存是否够用。 |
so | 从物理内存交换到交换空间 (Swap out),值较大时,说明系统频繁使用交换区,应该查看操作系统的内存是否够用。 | |
io | bi | 每秒钟从块设备读取的字节数 (Blocks in),代表I/O活动,根据其大小可以知道磁盘I/O的负载情况。 |
bo | 每秒钟写入块设备的字节数 (Blocks out),代表I/O活动,根据其大小可以知道磁盘I/O的负载情况。 | |
system | in | 每秒钟中断的次数 (Interrupts),是每秒中断的次数。 |
cs | 每秒钟上下文切换的次数 (Context switches) ,参数表示线程环境的切换次数,此数据太大时表明线程的同步机制有问题。 | |
cpu | us | 用户空间使用CPU的时间比率 (User time) |
sy | 内核空间使用CPU的时间比率 (System time) | |
id | CPU空闲时间比率 (Idle time) | |
wa | 等待I/O的时间比率 (I/O wait time) | |
st | 从虚拟机偷取的CPU时间 (Steal time) |
案例分析
测试工具sysbench的安装:
apt install sysbench
使用vmstat查看空闲系统的上下文切换次数:
# 间隔1秒后输出1组数据
root@ubuntu:/home/fly# vmstat 1 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 12 1173896 470200 3318136 0 0 6 20 49 74 0 0 99 0 0在另一个终端开始压测:
# 以10个线程运行5分钟的基准测试,模拟多线程切换的问题
sysbench --num-threads=10 --max-time=300 --max-requests=10000000 --test=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
9 0 0 206356 67344 548616 0 0 0 14 1666 1596479 7 93 0 0 0
7 0 0 206356 67344 548612 0 0 0 0 1680 1542861 10 90 0 0 0
7 0 0 206356 67344 548612 0 0 0 0 1700 1550600 11 90 0 0 0
7 0 0 206356 67344 548612 0 0 0 0 1704 1586618 9 91 0 0 0
8 0 0 206356 67348 548612 0 0 0 8 1700 1493243 8 93 0 0 0
cs 列:的上下文切换次数从之前的 35 骤然上升到了 139 万。
r
列:就绪队列的长度已经到了 8,远远超过了系统 CPU 的个数 2,所以肯定会有大量的 CPU 竞争。us
(user)和sy
(system)列:这两列的 CPU 使用率加起来上升到了 100%,其中系统 CPU 使用率,也就是 sy 列高达 84%,说明 CPU 主要是被内核占用了。in
列:中断次数也上升到了 1 万左右,说明中断处理也是个潜在的问题。综合这几个指标,我们可以知道,系统的就绪队列过长,也就是正在运行和等待 CPU 的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统 CPU 的占用率升高。
使用pidstat查看。什么进程导致了这些问题呢?在第三个终端再用 pidstat 来看一下, CPU 和进程上下文切换的情况:
# 每隔1秒输出1组数据(需要 Ctrl+C 才结束)
# -w参数表示输出进程切换指标,而-u参数则表示输出CPU使用指标
$ pidstat -w -u 1
# 每隔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
这时,你还需要根据上下文切换的类型,再做具体分析。比方说:
自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈;
中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件来分析具体的中断类型。
遇到CPU利用率高该如何排查?
%iowait
高,这时要重点关注磁盘IO的相关操作,是否存在不合理的写日志操作,数据库操作等;%soft
或%cs
高,观察CPU负载是否较高、网卡流量是否较大,可不可以精简数据、代码在是否在多线程操作上存在不合适的中断操作等;%steal
高,这种情况一般发生在虚拟机上,这时要查看宿主机是否资源超限;
如果是用户态较高,且没有达到预期的性能,说明应用程序需要优化。
根据指标查找工具:
性能指标 | 工具 | 说明 |
---|---|---|
平均负载 | uptime, top | uptime最简单;top提供了更全的指标 |
系统整体CPU使用率 | vmstat, mpstat, top, sar, /proc/stat | top、vmstat、mpstat 只可以动态查看,而sar 还可以记录历史数据 |
进程CPU使用率 | top, pidstat, ps, htop, atop | top和ps可以按CPU使用率给进程排序,而pidstat只是显示当前CPU的进程 |
系统上下文切换 | vmstat | 除了上下文切换次数,还提供运行状态和可阻塞状态进程的数量 |
进程上下文切换 | pidstat | 注意加上 -w 选项 |
软件中断 | top, /proc/softirqs, mpstat | top提供软件中断CPU使用率,/proc/softirqs和mpstat提供了各种中断在每个CPU上的运行次数 |
硬件中断 | vmstat, /proc/interrupts | vmstat提供总的中断次数,/proc/interrupts提供各个中断在每个CPU上运行的累积次数 |
网络 | dstat, sar, tcpdump | dstat和sar提供网络接收和发送情况,而tcpdump则是实时抓取正在进行的网络通信 |
I/O | dstat, sar | dstat和sar都提供了I/O的整体情况 |
CPU 个数 | /proc/cpuinfo , lscpu | lscpu更简单 |
事件分析 | perf, execsnoop | perf可以用来分析CPU的缓慢及内部状态,execsnoop需注意控制选项 |
根据工具查指标:
性能工具 | CPU性能指标 |
---|---|
uptime | 平均负载 |
top | 平均负载、运行队列、整体的CPU使用率以及每个进程的状态和CPU使用率 |
htop | top 增强版,以不同颜色区分不同类型的进程,更新频率 |
atop | CPU、内存、磁盘和网络等各种资源的全面监控 |
vmstat | 系统整体的CPU使用率,上下文切换次数、中断次数,还包括正在运行和可中断状态的进程数 |
mpstat | 每个CPU的使用率和软中断次数 |
pidstat | 进程和线程的CPU使用率,中断上下文切换次数 |
/proc/softirqs | 软件中断类型在每个CPU上的累积中断次数 |
/proc/interrups | 硬件中断类型在每个CPU上的累积中断次数 |
ps | 每个进程的状态和CPU使用率 |
pstree | 进程的父子关系树 |
dstat | 系统整体的CPU使用率 |
sar | 系统整体的CPU使用率,包括可配置的历史数据 |
strace | 进程级系统调用使用 |
perf | CPU性能事件采样,如调谐性能分析、CPU缓冲等 |
execsnoop | 监控跟踪进程 |
总结
在现代计算系统中,CPU上下文切换的理解与管理至关重要。上下文切换是操作系统在多个进程或线程之间转换执行状态的过程,虽然这种机制使得多任务处理成为可能,但频繁的上下文切换会导致显著的性能损失。
通过监控上下文切换的频率和模式,可以识别出性能瓶颈,并采取合适的优化措施。优化的方法可能包括调整进程优先级、减小进程数量或合理配置系统资源等。这不仅能够提高CPU利用率,还能减少由于上下文切换带来的额外开销,从而显著增强系统的整体性能和响应速度。
公众号: Lion 莱恩呀
微信号: 关注获取
扫码关注 了解更多内容
点个 在看 你最好看