Linux性能优化-上下文切换

目录

CPU上下文

进程上下文切换

线程上下文切换

中断上下文切换

上下文切换的两个指标

简单案例


CPU上下文

CPU的平均负载升高,上下文切换是罪归祸首
Linux支持远大于CPU数量的任务同时运行,通过将时间分片造成同时运行的错觉

每个任务运行前,需要设置好CPU寄存器和程序计数器Program Counter PC
CPU寄存器,是CPU内置的cache,存储数据和指令
程序计数器,用来存储CPU正在执行的指令位置,或者即将执行的下一条指令位置,他们都是CPU在运行任何任务
前,必须依赖的环境,因此被叫做 CPU上下文

扫描二维码关注公众号,回复: 4529590 查看本文章


CPU上下文切换,先把前一个任务的CPU上下文(寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器中,最后再跳转到程序计数器所指的新位置,运行新任务
保存的这些上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来,这样就能保证任务原来的状态不受影响,让任务看起来是连续的
根据任务的不同,CPU的上下文切换可以分为几个不同的场景
1.进程上下文切换
2.线程上下文切换
3.中断上下文切换

进程上下文切换

Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,对应下图
内核空间Ring 0 有最高权限,可以直接访问所有资源
用户空间Ring 3 只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核
  中,才能访问这些特权资源

进程既可以在用户空间运行,又可以在内核空间中运行,进程在用户空间运行时,称为进程的用户态
而陷入内核空间时,被成为进程的内核态
从用户态到 内核态,需要通过系统调用来完成,比如调用open,read,write等

系统调用需要保存CPU寄存器相关信息,再更新为内核态指令的新位置,接着跳转到内核态运行内核任务,等系统调用结束后
CPU寄存器再恢复到用户态,切换到用户空间
一次系统调用过程,发生了 两次 CPU上下文切换
系统调用过程,不会涉及到虚拟内存等进程用户态的资源,也不会切换进程
1.进程上下文切换,是指从一个进程切换到另一个进程运行
2.系统调用过程一直是在同一个进程中运行
所以系统调用也被称为 特权模式切换,而不是上下文切换,但调用过程中CPU的上下文切换无法避免

进程的上下文切换比系统调用多了一步,需要保存该进程的虚拟内存,栈等信息,加载了下一进程的内核态之后,还需要刷新进程的虚拟内存和用户栈

进程上下文切换,需要内核在CPU上运行才能完成


Linux通过TLB Translation Lookaside Buffer,来管理虚拟内存到物理内存的映射管理,当虚拟内存更新后,TLB也要刷新,内存的访问也会变慢,如果是在多处理器上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程

系统为每个CPU都维护了一个就绪队列,将活跃进程(正在运行和正在等待CPU的进程)按照优先级和等待CPU的时间排序,然后选择最需要CPU的进程,也就是优先级最高和等待CPU时间最长的进程来运行
触发进程切换的场景
1.CPU时间片到了就会切换
2.系统在资源不足(如内存不足)时,等到资源满足后才可以允许,这个时候进程也会被挂起,系统会
  调度其他进程
3.当进程通过sleep函数将自己挂起,系统也会重新调度
4.有更高优先级的进程运行时,当前进程会被挂起
5.当硬件发生中断时,CPU上的进程会被中断挂起

线程上下文切换

线程是调度的基本单位,而进程是资源拥有的基本单位
内核中任务调度,实际上调度的对象是线程
进程只是给线程提供了虚拟内存,全局变量等资源
1.当进程只有一个线程时,可以认为进程就等于线程
2.当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源,在上下文切换时不需要修改
3.线程私有数据,比如栈和寄存器等,这些在上下文切换的时候需要保存

线程的上下文切换分为两种情况
1.前后两个线程属于不同进程,此时资源不共享,切换过程中就跟进程上下文切换是一样的
2.前后两个线程属于同一个进程,此时虚拟内存是共享的,在切换时,虚拟内存这些资源就保持不动,只要切换
  线程私有数据,寄存器等不共享的数据

中断上下文切换

中断会打断进程的政策调度和执行,转而调用中断处理程序,响应设备事件,而在打断其他进程时,就需要将进程当前的状态保存下来,这样再中断结束后,进程仍然可以从原来的状态恢复运行
中断上下文切换并不涉及到进程的用户态,即便中断过程打断了一个正在处理用户态的进程,也不需要保存和恢复这个进程的虚拟内存,全局变量等用户态资源,中断上下文,其实只包括内核态中断服务程序执行锁必须的状态,包括CPU寄存器,内核堆栈,硬件中断参数等

对同一个CPU来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生,同样由于中断会打断正常进程的调度和执行,所以大部分中断程序都短小精悍,以便快速执行结束
中断上下文切换也会消耗CPU,切换次数过多会耗费大量CPU,降低系统整体性能

上下文切换的两个指标

pidstat -w 输出之后有两个指标
一个是 cswch 表示每秒自愿上下文切换(voluntary context switches)的次数,另一个是nvcswch 表示每秒非自愿上下文切换(non voluntary context switches)的次数
这种模式会导致不同的性能问题
1.自愿上下文切换,是指进程无法获得所需自愿,导致上下文切换,比如I/O,内存等系统资源不足时,就会
  发生自愿上下文切换
2.非自愿上下文切换,是指进程由于时间片已经到等原因,被系统强制调度,进而发生的上下文切换,比如
  大量进程都在争抢CPU时,就容易发生非自愿上下文切换

//目前的场景是线上服务器有大量的网络I/O,查看bond0 这个进程的结果
//机器是万M网卡,通过dstat -n 的结果为
-net/total-
 recv  send
   0     0 
 292M  176M
 291M  179M
 285M  175M
 291M  176M
 308M  191M
 284M  180M
 309M  191M

//bound0 这个进程的 上下文切换情况
pidstat -p 3246 -w  1
12:35:35 PM       PID   cswch/s nvcswch/s  Command
12:35:36 PM      3246     10.00      0.00  bond0
12:35:37 PM      3246     10.00      0.00  bond0
12:35:38 PM      3246     10.00      0.00  bond0
12:35:39 PM      3246     10.00      0.00  bond0
12:35:40 PM      3246     10.00      0.00  bond0
12:35:41 PM      3246     10.00      0.00  bond0
12:35:42 PM      3246     10.00      0.00  bond0

简单案例

用压测工具模拟上下文切换场景,安装 sysbench 压测工具

//压测
sysbench --threads=10 --max-time=300 threads run

//通过 vmstat,或者 dstat,可以发现 中断和上下文切换瞬间变高了

//每两秒显示一次,-u表示cpu使用率
pidstat -w -u -2

//找到CPU使用率高的进程,然后 -w 看上下文切换情况,-u 看使用率, -t 看线程指标
pidstat -p 29938 -w -u -t 2 

01:04:32 PM   UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
01:04:34 PM     0     29938         -   19.50   80.00    0.00   99.50     0  sysbench
01:04:34 PM     0         -     29938    0.00    0.00    0.00    0.00     0  |__sysbench
01:04:34 PM     0         -     29939    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29940    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29941    2.00    8.50    0.00   10.50     0  |__sysbench
01:04:34 PM     0         -     29942    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29943    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29944    2.50    8.00    0.00   10.50     0  |__sysbench
01:04:34 PM     0         -     29945    1.50    8.00    0.00    9.50     0  |__sysbench
01:04:34 PM     0         -     29946    1.50    8.00    0.00    9.50     0  |__sysbench
01:04:34 PM     0         -     29947    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29948    2.50    7.50    0.00   10.00     0  |__sysbench

01:04:32 PM   UID      TGID       TID   cswch/s nvcswch/s  Command
01:04:34 PM     0     29938         -      0.00      0.00  sysbench
01:04:34 PM     0         -     29938      0.00      0.00  |__sysbench
01:04:34 PM     0         -     29939  14419.00 108190.50  |__sysbench
01:04:34 PM     0         -     29940  14475.00 110001.00  |__sysbench
01:04:34 PM     0         -     29941  14524.50 110557.00  |__sysbench
01:04:34 PM     0         -     29942  13536.50 107055.50  |__sysbench
01:04:34 PM     0         -     29943  12553.50 111592.00  |__sysbench
01:04:34 PM     0         -     29944  10616.50 112754.00  |__sysbench
01:04:34 PM     0         -     29945  19468.00  97932.50  |__sysbench
01:04:34 PM     0         -     29946  13479.50 110462.00  |__sysbench
01:04:34 PM     0         -     29947  16443.00 100000.00  |__sysbench
01:04:34 PM     0         -     29948  19969.50  97967.50  |__sysbench

找到了sysbench这个进程是上下文切换的元凶
除了大量的上下文切换,还有很多中断
通过 /proc/interrupts 这个只读文件分析
/proc是 linux的一个虚拟文件系统,用于内核空间与用户空间之间的通讯,/proc/interrupts 就是这种通讯机制的一部分,提供了一个只读的中断使用情况
通过 watch -d cat /proc/interrupts  查看

watch -d cat interrupts  
.....
NMI:          0   Non-maskable interrupts
LOC:   95780367   Local timer interrupts
SPU:          0   Spurious interrupts
PMI:          0   Performance monitoring interrupts
IWI:    1503219   IRQ work interrupts
RTR:          0   APIC ICR read retries
RES:          0   Rescheduling interrupts
CAL:          0   Function call interrupts
TLB:          0   TLB shootdowns
TRM:          0   Thermal event interrupts
THR:          0   Threshold APIC interrupts
DFR:          0   Deferred Error APIC interrupts
MCE:          0   Machine check exceptions
MCP:       2019   Machine check polls
ERR:          0
MIS:          0
PIN:          0   Posted-interrupt notification event
PIW:          0   Posted-interrupt wakeup event


我的是单CPU机器,变化最大的是
LOC:   95780367   Local timer interrupts   这一段

对于多CPU机器,可能变化最大的是RES 重调度中断,这个中断类型表示,唤醒空闲状态的CPU来调度新的任务运行,这是多处理器系统SMP中,调度器用来分散任务到不同CPU的机制,也被称为 处理器间中断 Inter-Processor Interrupts IP
所以,这里的中断升高还是因为过多任务的调度问题,跟前面上下文切换次数分析的结果是一致的


上下文切换数量没有一个具体的值,取决于系统本身的CPU性能,如果系统的上下文切换次数比较稳定,那么数量从数百 -- 一万以内都是正常的, 但超过一万,或者切换次数出现数量级的增长,就很可能出现性能问题了


 

猜你喜欢

转载自blog.csdn.net/hixiaoxiaoniao/article/details/84977592
今日推荐