cpu-上下文切换

cpu-上下文切换

前奏

在每个进程任务运行之前,CPU需要知道任务从哪加载,又从哪里开始运行,也就是说,系统要实现帮进程任务设置好CPU寄存器和程序计数器

  • CPU寄存器

    • 容量小,速度极快的内存
  • 程序计数器

    • 存储CPU正在执行指令的位置

所以,CPU寄存器和程序计数器,是CPU在运行任何任务之前必须依赖的环境,因此也被称作CPU上下文

CPU上下文切换也就是把前一个任务的CPU上下文保存起来,然后加载新任务的向下文到这些寄存器和程序计数器

image.png

CPU上下文切换场景分类

根据任务的不同,CPU上下文切换分为如下的几类:

  • 进程上下文切换

  • 线程上下文切换

  • 中断上下文切换

进程上下文切换

Linux按照特权等级,把进程分为内核空间用户空间

内核空间:

- Ring0:具有最高权限,可以直接访问所有资源

用户空间

- Ring3: 只能访问受限的资源,不能直接访问内存等硬件设备,必须用过系统调用陷入内核,才能访问这些特权资源
image.png

用户态到内核态的转变需要系统调用来完成,

系统调用结束后,CPU 寄存器需要恢复原来保存的用户态,然后在切换到用户空间,继续运行进程。一次系统调用的过程其实发生了两次上下文切换。

进程上下文切换和 系统调用的上下文切换

进程上下文切换: 是从一个进程切换到另一个进程运行

系统调用的上下文切换: 一直是同一个进程在运行,系统调用过程通常称为特权模式切换,而不是上下文切换

区别如下:

- 进程由内核来管理和调度的,进程的切换只能发生在内核态

- 进程上下文切换比系统调用多了一个过程

Linux通过TLB来管理虚拟内存到物理内存的映射关系,当虚拟内存更新之后TLB也需要刷新,内存的访问也会随之变慢。

进程切换时才需要上下文切换,Linux为每个CPU都维护了一个就绪队列,将活跃进程按照优先级和等待CPU的时间进行排序,然后选择最需要CPU的进程,也就是最高优先级和等菜CPU时间最长的进程来运行

进程在什么时候会调度到CPU上运行

  • 为了保证所有的进程可以公平调度,CPU时间被划分成一段段的时间片,这些时间片灾备轮流分配给各个进程,这样,当某个进程的时间片被耗尽,就会被系统挂起,切换到其他正在等待CPU的进程运行

  • 进程在系统资源不足时,要等到资源买足后才可以运行,这个时候进程也会被挂起,并有系统调度大其他进程运行

  • 当进程通过睡眠函数sleep这样的方法将自己主动挂起,自然也会重新调度

-当优先级更高的进程运行时,为了保证高优先级的进程运行,当前的进程会被挂起,由高优先级的进程来运行

  • 当发生硬件中断时,CPU上的进程会被中断挂起,转而执行内核中的中断服务程序

线程上下文切换

线程是调度的基本单位,晋城市资源拥有的基本单位。

所谓的内核中的任务调度,实际上调度对象是线程,而进程只是给线程提供了虚拟内存,全局变量等资源。

  • 当进程只有一个线程时,可以认为进程就等于线程

  • 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换的时候是不需要修改的

  • 线程也有自己的私有数据,比如栈和寄存器等,浙西在上下文切换时也是需要保存的

线程上下文切换的情况:

- 前后两个线程属于不同的进程

- 前后两个线程属于同一个进程,切换的数据只有线程的不共享的数据

- 多线程对于多进程会消耗更少的资源,所以多线程是替代多进程的一个优势

中断上下文切换

为了快速响应硬件时间,中断会打断进程的正常调度和执行,转而调度中断程序,响应设备事件,而中断执行过程中会挂起当前正常的进程。

  • 为了快速响应硬件事件,中断会打断进程的正常调度和执行

  • 对于同一个CPU来说,中断处理比进程拥有更高的优先级

小结

  • CPU上下文切换是保证Linux正常工作的核心功能之一,一般不用特别关注

  • 如果上下文切换过多,会将CPU时间消耗在寄存器内核栈以及虚拟内存等数据的保存和恢复上

实战上下文切换

查看整体的CPU上下文切换


[root@www ~]# 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

 3 0 0 80144 140508 1143972 0 0 16 25 1 1 1 0 99 0 0

其中:

  • cs:每秒上下文切换次数

  • in:每秒中断次数

  • r:就绪队列长度

  • b: 不可睡眠状态的进程数

查看每个进程的CPU详细上下文切换


[root@www ~]# pidstat -w 5

Linux 3.10.0-862.el7.x86_64 (www.cropy.cn) 10/16/19 _x86_64_ (1 CPU)

16:11:34 UID PID cswch/s nvcswch/s Command

16:11:39 0 1 0.80 0.00 systemd

16:11:39 0 3 1.40 0.00 ksoftirqd/0

16:11:39 0 9 28.74 0.00 rcu_sched

16:11:39 0 11 0.40 0.00 watchdog/0

16:11:39 0 29 0.20 0.00 khugepaged

需要记住的参数如下:

  • cswch:自愿上下文切换,这个参数是指进程无法获取所需资源导致的上下文切换,比如:IO,内存等资源不足的时候会发生自愿上下文切换

  • nvcswch: 非自愿上下文切换,这个参数表示进程时间片已到等原因被系统强制调度,进而发生上下文切换。比如:大量进程抢占CPU的时候会发生非自愿上下文切换

案例分析

环境需求

  • centos7

  • sysstat: 1.15以上

  • sysbench

  • root权限

实战测试

  • 第一个终端执行如下操作

[root@www ~]# sysbench --threads=10 --max-time=300 threads run      #开启10个进程的五分钟的基准测试,模拟多线程切换

  • 第二个终端执行如下

[root@www ~]# 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

10 0 0 180128 122484 1054324 0 0 12 0 1112 1249403 17 83 0 0 0

 7 0 0 180128 122484 1054336 0 0 4 0 1097 1262657 16 84 0 0 0

 8 0 0 180128 122484 1054340 0 0 0 0 1089 1224114 18 82 0 0 0

 8 0 0 180112 122484 1054340 0 0 0 0 1116 1255382 19 81 0 0 0

 8 0 0 180096 122488 1054340 0 0 36 16 1149 1249025 18 82 0 0 0

发现如下的问题

  • r:就绪队列在长度达到8

  • us和sy:两列加起来到了100,sy在84左右,证明CPU被内核占用了

  • in: 中断也达到了1000以上

综合上面的三个点,可以发现CPU的使用率很高

  • 然后再开一个终端,执行如下命令

[root@www ~]# pidstat -w -u 1
Linux 3.10.0-862.el7.x86_64 (www.cropy.cn) 10/16/19 _x86_64_ (1 CPU)

16:42:08 UID PID %usr %system %guest %wait %CPU CPU Command

16:42:09 0 22937 0.00 1.00 0.00 0.00 1.00 0 barad_agent

16:42:09 0 31092 17.00 83.00 0.00 0.00 100.00 0 sysbench

16:42:08 UID PID cswch/s nvcswch/s Command

16:42:09 0 1 1.00 0.00 systemd

16:42:09 0 3 1.00 0.00 ksoftirqd/0

16:42:09 0 9 32.00 0.00 rcu_sched

16:42:09 0 9921 1.00 0.00 supervisord

16:42:09 0 10617 1.00 0.00 YDLive

16:42:09 0 16286 2.00 0.00 IntelliJIDEALic

16:42:09 1000 17350 2.00 0.00 sshd

16:42:09 0 22936 3.00 0.00 barad_agent

16:42:09 0 28412 1.00 0.00 kworker/0:1

16:42:09 1003 28963 3.00 0.00 tmux

16:42:09 0 30007 11.00 0.00 kworker/0:0

16:42:09 0 30560 1.00 0.00 vmstat

16:42:09 0 31225 6.00 0.00 ntpdate

16:42:09 0 31226 2.00 0.00 grep

16:42:09 0 31241 1.00 0.00 pidstat

可以发现CPU使用过高是sysbench导致的,pidstat -wt 可以分析到线程级别

也可以如下的方式去查看:


**[root@www ~]# watch -d cat /proc/interrupts **

你可能感兴趣的:(cpu-上下文切换)