什么是CPU上下文切换

CPU寄存器,程序计数器,这些CPU在运行任何任务前,都必须的依赖环境被叫做CPU上下文。根据任务的不同,CPU的上下文切换,可以分为不同的场景,也就是进程上下文切换,线程上下文切换,中断上下文切换。

当切换任务的时候,需要记录任务当前的状态和获取下一任务的信息和地址(指针),这就是上下文的内容。因此,上下文是指某一时间点CPU寄存器(CPU register)和程序计数器(PC)的内容, 广义上还包括内存中进程的虚拟地址映射信息.

上下文切换的过程

(1)记录当前任务的上下文(即寄存器和计算器等所有的状态);
(2)找到新任务的上下文并加载;
(3)切换到新任务的程序计算器位置,恢复其任务。

根据不同任务区分三种上下文切换

根据任务的执行形式,相应的下上文切换,有进程上下文切换、线程上下文切换、以及中断上下文切换三类。
进程和线程的区别:
进程是资源分配和执行的基本单位;线程是任务调度和运行的基本单位。线程没有资源,进程给指针提供虚拟内存、栈、变量等共享资源,而线程可以共享进程的资源。

进程上下文切换:是指从一个进程切换到另一个进程。

  1. 进程运行态为内核运行态和进程运行态。内核空间态资源包括内核的堆栈、寄存器等;用户空间态资源包括虚拟内存、栈、变量、正文、数据等
  2. 系统调用(软中断)在内核态完成的,需要进行2次CPU上下文切换(用户空间–>内核空间–>用户空间),不涉及用户态资源,也不会切换进程。
  3. 进程是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文不仅包括了用户空间的资源,也包括内核空间资源。
  4. 进程的上下文切换过程:
    • 接收到切换信号,挂起进程,记录当前进程的虚拟内存、栈等资源存储;
    • 将这个进程在 CPU 中的上下文状态存储于起来;
    • 然后在内存中检索下一个进程的上下文;
    • 并将其加载到 CPU的寄存器中恢复;
    • 还需要刷新进程的虚拟内存和用户栈;
    • 最后跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行),以恢复该进程。
  5. 下列将会触发进程上下文切换的场景:
  • 根据调度策略,将CPU时间划片为对应的时间片,当时间片耗尽,当前进程必须挂起。
  • 资源不足的,在获取到足够资源之前进程挂起。
  • 进程sleep挂起进程。
  • 高优先级进程导致当前进度挂起
  • 硬件中断,导致当前进程挂起

线程上下文切换:

  1. 不通进程之间的线程上下文切换,其过程和进程上下文切换大致相同。
  2. 进程内部的线程进上下文切换。不需要切换进程的用户资源,只需要切换线程私有的数据和寄存器等。这会比进程上下文进程切换消耗的资源少,所以多线程相比多进程的优势。

中断上下文切换

快速响应硬件的事件,中断处理会打断进程的正常调度和执行。同一CPU内,硬件中断优先级高于进程。切换过程类似于系统调用的时候,不涉及到用户运行态资源。但大量的中断上下文切换同样可能引发性能问题。

怎么查看系统上下文切换

vmstat 5

每5秒钟输出一组数据

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 724224  88188  16924 319048    1    2    16    18   32    1  1  1 98  0  0
 0  0 724224  88276  16932 319048    1    0     1     6  400  791  1  1 98  0  0
 0  0 724224  87812  16932 319048    1    0     1     0  510  978  2  1 97  0  0
  • cs(context switch)每秒上下文切换的次数
  • in(interrupt)每秒中断的次数
  • r(Running and Runnable)就绪队列的长度,也就是正在运行和等待CPU的进程数
  • b(Blocked)处于不可中断睡眠状态的进程数

pidstat -w 5 每5秒输出一次进程上下文切换的情况

zhk@ubuntu:~$ pidstat -w 5
Linux 4.15.0-29-generic (ubuntu)    12/18/2018  _x86_64_    (2 CPU)

02:57:47 PM   UID       PID   cswch/s nvcswch/s  Command
02:57:52 PM     0         7      0.98      0.00  ksoftirqd/0
02:57:52 PM     0         8     19.02      0.00  rcu_sched
02:57:52 PM     0        11      0.39      0.00  watchdog/0
02:57:52 PM     0        14      0.39      0.00  watchdog/1
02:57:52 PM     0        15      0.20      0.00  migration/1
02:57:52 PM     0        16      0.20      0.00  ksoftirqd/1
02:57:52 PM     0       189      0.39      0.00  kworker/0:1H
02:57:52 PM     0       192      0.20      0.00  kworker/1:1H
02:57:52 PM   103       444     19.22      3.73  dbus-daemon
02:57:52 PM   116       462     17.84      0.20  avahi-daemon
02:57:52 PM     0       471      0.20      0.00  irqbalance
02:57:52 PM     0       490      3.73      0.00  polkitd
02:57:52 PM     0       780      3.92      0.20  prltoolsd
02:57:52 PM     0       789      0.20      0.00  prltimesync
02:57:52 PM   121      1394      1.76      0.00  Xorg
02:57:52 PM     0      1718      0.20      0.00  packagekitd
02:57:52 PM   121      1742      0.98      0.00  gsd-color
02:57:52 PM  1000      2083    112.55      5.69  Xorg
02:57:52 PM  1000      2257     37.65      1.76  gnome-shell
02:57:52 PM  1000      2474      0.98      0.00  gsd-color
02:57:52 PM  1000      2582      0.98      0.00  prlshprof
02:57:52 PM  1000      3548      0.20      0.00  update-notifier
02:57:52 PM     0     11573      5.88      0.00  kworker/u64:0
02:57:52 PM     0     17931      3.33      0.00  kworker/u64:1
02:57:52 PM  1000     19023      8.24      0.20  gnome-terminal-
02:57:52 PM     0     20630      5.69      0.00  cupsd
02:57:52 PM     0     20640      1.76      0.00  cups-browsed
02:57:52 PM  1000     21446      1.76      0.20  watch
02:57:52 PM     0     26102      2.16      0.00  kworker/1:0
02:57:52 PM     0     28012      8.24      0.00  kworker/0:0
02:57:52 PM  1000     29135      0.20      0.00  pidstat
02:57:52 PM     0     29157      0.20      0.00  sh
02:57:52 PM     0     29158      3.33      0.00  lpstat
02:57:52 PM     0     29159      0.20      0.00  sed

cswch,每秒自愿上下文切换次数,进程无法获取所需资源导致的上下文切换,比如IO,内存不足等系统资源不足,会发送资源上下文切换
nvcswch 每秒非自愿上下文切换,指进程由于时间片已经到等原因,被系统强制调度,进而发送的上下文切换。大量进程在争抢CPU时,容易发送非自愿上下文切换。

模拟cpu切换

zhk@ubuntu:~$ sysbench --threads=10 --max-time=300 threads run
WARNING: --max-time is deprecated, use --time instead
sysbench 1.0.11 (using system LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 10
Initializing random number generator from current time


Initializing worker threads...

Threads started!

vmstat 1
-w参数表示输出进程切换指标,-u表示输出cpu使用指标
pidstat -w -u 1
pidstat -wt 1