您的位置:首页 > 运维架构 > Linux

Linux性能优化从入门到实战:03 CPU篇:CPU上下文切换

2020-02-04 17:58 260 查看

  linux操作系统是将CPU轮流分配给任务,分时执行的。而每次执行任务时,CPU需要知道CPU寄存器(CPU内置的内存)和程序计数器PC(CPU正在执行指令和下一条指令的位置)值,这些值是CPU执行任务所依赖的环境,也就是CPU上下文
  CPU上下文切换,就是把前一个任务的CPU上下文(CPU寄存器和程序计数器)保存起来,然后加载入新任务的上下文到CPU寄存器和程序计数器中,最后跳转到程序计数器所指的位置,运行新任务。
  保存下来的上下文会在系统内核中,并在任务重新调度执行时再次加载进来,让任务看起来是连续执行的。
  根据任务的不同,CPU上下文切换分为进程上下文切换、线程上下文切换、中断上下文切换。
  
  进程上下文切换
  Linux把进程的运行空间分为内核空间和用户空间,并对进程按照特权等级划分,从内核空间Ring 0至用户空间Ring 3:Ring 0具有最高权限,可以直接访问所有资源;Ring 3只能访问受限资源,不能直接访问内存等硬件设备,需要通过系统调用陷入到内核中,才能访问这些特权资源。
  
  进程运行在用户空间为进程的用户态,陷入内核空间为进程的内核态。从用户态到内核态的转变,需要通过系统调用来完成,期间涉及CPU上下文的切换:先保存原来用户态指令位置,然后更新内核态指令新位置,最后执行内核态代码;系统调用结束后,恢复用户态数据,继续执行进程。一次系统调用发生二次CPU上下文切换
  进程上下文切换 VS 系统调用:(1)进程上下文切换是一个进程切换到另一个进程;系统调用是同一个进程。(2)都需要进行上下文切换。(3)进程是由内核管理和调度的,切换只发生在内核态,所以进程上下文切换包括虚拟内存、栈、全局变量等用户资源,还包括内核堆栈、寄存器等内核资源;而系统调用只包括内核堆栈、寄存器等内核资源。
  
  每次上下文切换需要几十纳秒到数微妙的CPU时间。切换次数较多,容易导致平均负载升高。
  Linux通过TLB(Translation Lookaside Buffer)来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB 也需要刷新,内存的访问也会随之变慢。特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。
  Linux为每个CPU都维护一个就绪队列,将活跃进程(正在运行和正在等待)按照优先级和等待CPU时间进行排序,优先级最高和等待时间最长的进程优先运行。所以触发进程调度的情况
    (1)按照时间片轮转执行
    (2)进程执行的资源不足时,该进程被挂起,系统调用其他进程
    (3)进程通过睡眠函数sleep将自己挂起
    (4)挂起当前进程,由优先级更高的进程运行
    (5)硬件中断时,挂起CPU上的进程,转而执行内核中断服务程序。
  
  线程上下文切换
  线程是调度的基本单位,而进程是资源拥有的基本单位。(1)当进程只有一个线程时,进程等于线程(2)进程拥有多个线程时,线程共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时不需要修改(3)线程也有私有的数据(栈和寄存器),上下文切换时需要保存。
  不同进程中的两个线程切换,与进程的上下文切换是一样的。同一进程中两个线程,共享资源不动,切换线程中私有数据。所以同进程中线程切换,比多进程切换消耗更少资源,多线程替代多进程更有优势。
  
  中断上下文切换
  中断事件会打断进程的正常调度和执行,转而调用中断处理程序,打断期间,保存当前进程状态,中断结束后,恢复原来的状态执行。
  中断上下文,其实只包括内核态中断服务程序执行所必需的状态(CPU寄存器、内核堆栈、硬件中断参数等),不需要保存和恢复被打断进程的虚拟内存、全局变量等用户态资源。
  中断处理比进程拥有更高的优先级,所以中断上下文切换与进程上下文切换不会同时发生。
  中断次数过多,也会消耗大量CPU,降低系统整体性能。
  
  
  例程
  vmstat用于分析系统的内存使用情况、CPU上下文切换和中断次数。

$ vmstat
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 285444 290716 2682728    0    0     2   146   77   80  1  0 99  1  0

// cs (context switch) 每秒上下文切换次数
// in (interrupt) 每秒中断次数
// r (Running or Runable) 正在运行和等待CPU的进程数
// b (Blocked) 处于不可中断睡眠状态的进程数

  pidstat查看每个进程的详细情况,-w选项,查看每个进程上下文切换情况,-wt选项,查看每个线程的上下文切换情况。

$ pidstat -w
21时57分43秒   UID       PID   cswch/s nvcswch/s  Command
21时57分43秒     0         1      0.05      0.15  systemd
21时57分43秒     0         2      0.00      0.00  kthreadd
...

// cswch 每秒自愿上下文切换的次数(voluntary context switches):进程无法获取所需资源(I/O、内存不足等),导致上下文切换
// nvcswch 每秒非自愿上下文切换的次数 (non voluntary context switches):时间片已到等原因,系统强制调度,导致上下文切换,如大量进程争抢CPU

  通过sysbench模拟系统多线程调度

$ sudo apt install sysbench sysstat
$ sysbench --num-threads=10 --max-time=300 --test=threads run  // first terminal
$ vmstat 1  // second terminal
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      0 278256 291152 2688492    0    0     0     0 1080 2375  1  1 98  0  0
0  0      0 278256 291152 2688492    0    0     0    12  506 2520  3  2 95  0  0
9  0      0 277736 291152 2688492    0    0     0    20  319 9189  1  1 98  0  0
8  0      0 277612 291152 2688492    0    0     0     0 53149 2069616  8 92  1  0  0
8  0      0 277636 291152 2688492    0    0     0     0 53289 2129835  9 92  0  0  0
8  0      0 277612 291156 2688488    0    0     0    12 51352 2134779 10 90  0  0  0
9  0      0 277604 291156 2688492    0    0     0     0 53214 2079199 10 89  1  0  0
9  0      0 277604 291156 2688492    0    0     0     0 51975 2106476  7 93  0  0  0
0  0      0 278348 291156 2688492    0    0     0     0 3978 221384  3 12 86  0  0
0  0      0 278348 291156 2688492    0    0     0     0  433 1017  1  1 99  0  0
0  0      0 278348 291156 2688492    0    0     0     0  249  789  2  0 98  0  0

// r 列就绪队列长度远远大于CPU数量
// in cs 两列陡然上升
// us sy 两列升高,sy列高表示CPU被内核占用的多

$ pidstat -w -u 1  // -w 显示进程切换指标, -u 显示CPU使用指标
22时36分03秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
22时36分04秒     0       921    0.00    2.00    0.00    2.00     1  Xorg
22时36分04秒  1000      8703    1.00    1.00    0.00    2.00     1  pidstat
22时36分04秒  1000      8704   18.00  174.00    0.00  192.00     0  sysbench

22时36分03秒   UID       PID   cswch/s nvcswch/s  Command
22时36分04秒     0       921    250.00      2.00  Xorg
22时36分04秒  1000      1459     84.00      0.00  compiz
22时36分04秒  1000      8703      1.00    314.00  pidstat
22时36分04秒  1000     15616    360.00      4.00  gnome-terminal-
22时36分04秒     0     27490    315.00      0.00  kworker/u4:0

// CPU使用率 是sysbench进程拉高
// 上下文切换 由pidstat、kworker等共同拉高,并不到vmstat中上万的次数,因为更多的是sysbench线程的上下文切换

$ pidstat -wt 1  // -wt 显示线程切换指标
22时44分18秒  1000      8751         -      4.00      0.00  sysbench
22时44分18秒  1000         -      8751      4.00      0.00  |__sysbench
22时44分19秒  1000         -      8761  14719.00 173756.00  |__sysbench
22时44分20秒  1000         -      8752  15012.00 142064.00  |__sysbench

$ watch -d cat /proc/interrupts  // 中断次数过高,查看该文件分析具体的中断类型
CPU0       CPU1
RES:    2418433    2089523   Rescheduling interrupts

// RES 重调度中断,唤醒空闲状态的CPU来调度新任务运行。中断值过高,说明过多任务的调度问题。

  
  最合适的上下文切换次数:每秒上下文切换次数取决于系统本身的CPU性能,通过数百到一万以内是正常;超过一万或次数出现数量级增长,则有性能问题。
  vmstat 、 pidstat 、 /proc/interrupts
  
  
  
  
  

转载于:https://www.cnblogs.com/qccz123456/p/11385718.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
站内首发文章 ak18888 发布了0 篇原创文章 · 获赞 0 · 访问量 611 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: