参考:搞懂上下文切换
是什么
上下文切换是操作系统在多任务环境下进行任务切换时的一种重要机制。
上下文切换是指操作系统从一个正在运行的进程或线程切换到另一个进程或线程的过程。它涉及保存当前执行进程的上下文(如寄存器状态、程序计数器和进程控制块等)并加载新进程的上下文。
进程上下文可能涉及的内容:
CPU寄存器
:在上下文切换期间,CPU寄存器中的值需要保存和恢复。这包括程序计数器(PC)和其他寄存器,用于保存当前执行的指令和进程的状态。
内核数据结构
:Linux内核维护了各种数据结构来管理进程和线程。在上下文切换期间,内核需要保存和恢复与进程相关的数据结构,例如进程控制块(Process Control Block,PCB)和调度信息。
内核堆栈
:每个进程都有一个内核堆栈,用于保存函数调用和局部变量。在上下文切换期间,内核需要切换堆栈以保存和恢复进程的执行状态。
内存管理单元(MMU)
:上下文切换还涉及到虚拟内存管理。当进程从用户态切换到内核态或从内核态切换回用户态时,MMU需要更新虚拟内存映射以确保正确的内存访问权限和地址转换。
原因
上下文切换可以由多种原因引起,包括但不限于以下几点:
时间片轮转:在多任务处理中,操作系统会为每个进程或线程分配一定的时间片,当时间片用完时,操作系统会进行上下文切换,将CPU资源分配给下一个进程或线程。
阻塞和唤醒:当一个进程或线程发出阻塞请求(例如等待I/O完成)或被其他事件唤醒(例如信号),操作系统需要进行上下文切换,以便处理阻塞的进程或线程或执行唤醒后的进程或线程。
中断处理:当系统收到硬件中断(例如定时器中断、硬件错误等)时,当前正在执行的进程或线程可能需要被中断,并切换到中断处理程序的上下文。
影响
上下文切换是一项开销较大的操作,它涉及到保存和恢复大量的上下文信息,包括寄存器和内存等。因此,过多的上下文切换可能会导致系统性能下降。
上下文切换的频率取决于多任务处理的策略和系统负载情况。对于需要频繁进行I/O操作的任务,上下文切换可能会更加频繁,因为这些任务经常需要等待I/O完成。针对上下文切换的优化是操作系统设计中的一个重要方面,以提高系统的整体性能。
类型
进程切换
(Process Switching):从一个正在运行的进程切换到另一个进程。
线程切换
(Thread Switching):从一个正在运行的线程切换到另一个线程。
中断切换
(Interrupt Switching):当系统接收到硬件中断时,将当前正在执行的进程或线程切换到中断处理程序。
用户态和内核态切换
(User Mode and Kernel Mode Switching):当进程从用户态切换到内核态(例如发起系统调用)或从内核态切换回用户态时,会进行上下文切换。
命令
-
vmstat
% vmstat 1 3 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b 交换 空闲 缓冲 缓存 si so bi bo in cs us sy id wa st 6 0 1648500 793760 610352 6389900 0 1 11 17 9 9 3 1 95 0 0 0 0 1648500 779844 610352 6402460 0 0 0 12 5672 8318 4 2 93 0 0 0 0 1648500 779424 610352 6402460 0 0 0 0 3573 7730 2 1 97 0 0
-
pidstat -w
% pidstat -w | head Linux 5.15.0-71-generic (Work) 2023年08月11日 _x86_64_ (12 CPU) 17时58分35秒 UID PID cswch/s nvcswch/s Command 17时58分35秒 0 1 1.61 0.00 systemd 17时58分35秒 0 2 0.04 0.00 kthreadd 17时58分35秒 0 3 0.00 0.00 rcu_gp 17时58分35秒 0 4 0.00 0.00 rcu_par_gp 17时58分35秒 0 5 0.00 0.00 slub_flushwq 17时58分35秒 0 6 0.00 0.00 netns 17时58分35秒 0 8 0.00 0.00 kworker/0:0H-events_highpri # 统计所有进程的上下文切换(单位 秒) % pidstat -w | awk '{sum += $4} END {print sum}' 3513.22
-
查看上下文切换的耗时
sudo perf record -e context-switches -a -g -- sleep 1 # 这个命令将收集1秒钟内的上下文切换信息,并将其保存到perf.data文件中。 sudo perf report # 这个命令将打开一个交互式的报告,显示上下文切换的相关信息,包括调用堆栈、上下文切换的次数和耗时等。