CPU 上下文
当多个进程竞争同一个 CPU 的时候,会导致大量的上下文切换,从而使得系统负载升高。
常见的系统都是多任务操作系统,进程数量远大于 CPU 数量,系统会在很短的时间内将 CPU 资源轮流分给不同的进程使用,从而营造多任务的错觉。
CPU 知道其实并不用关心任务从从哪里开始,它只需要把 PC(程序计数器)中的指令取出来执行即可。
即将执行的下一条指令位置,寄存器等等这些速度极快的在 CPU 中的小内存被叫做 CPU 上下文 。
CPU 上下文切换
就是把前一个任务的的上下文保存起来,然后使用新的上下文覆盖当前上下文,等执行完当前任务或者时间片到了再切换回原来的上下文。
根据任务不同,分成不同的上下文切换:进程上下文切换,线程上下文切换以及中断上下文切换
进程上下文切换
正常执行的进程处于 Ring3 (用户空间),而内核空间是 Ring0,当进程尝试读写文件的时候,会先使用系统调用打开文件描述符,open() -> write() -> close()
等一系列操作,系统调用也是会是的 CPU 进行上下文切换的,通常涉及上下文切换的在以下场景:
- 时间片耗尽
- 进程系统资源不足
- 进程通过sleep函数休眠
- 高优先级进程运行
进程是由内核来管理调度的,进程的切换只能发生在内核态,所以进程的上下文切换不仅包括了虚拟内存、栈、全局变量等,还包括了内核堆栈,寄存器的让那个内核空间的状态。
线程上下文切换
线程和进程的区别?
- 当进程只包含一个线程时,可以认为进程等于线程
- 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局全局变量。
- 线程有私有数据,栈,寄存器等。
其实没有进程上下文切换,只有线程上下文……
因为线程是调度的单位,然而调度的过程中会发现两种不同的情况:
第一种,前后两个线程不属于同一个进程。此时,因为资源不共享,所以切换过程和进程一样。 第二种,前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不同,只需要切换线程的私有数据,寄存器等不共享的数据。
线程共享相同的虚拟内幕和全局变量等资源,这些资源在上下文切换时不需要修改。
中断上下文切换
对于同一个 CPU 来说,中断处理比进程拥有更高的优先级。
如何查看系统中断
vmstat 1 1
每隔1秒输出1次,总计输出1秒
|
|
- r:是就绪队列,超过cpu核心数就会产生竞争
- us和sy: user 和 system 列:表示 CPU 分别被 user 和 system 占用多少?
- in:指标是975,说明每秒中断975次
- cs:上下文切换 7756次
使用 pidstat
能看到进程详细信息
|
|
- cswch 自愿上下文切换:进程无法获得需要资源而产生上下文切换。
- nvcswch 非自愿上下文切换:进程时间片到了,被系统强制调度,而发生的上下文切换
更深层次查看进程运行情况
某个进程运行消耗大量资源,却不知道它在干什么,因此,希望使用 perf 工具来查看。
|
|
编译运行,CPU单线程占用100%,使用top获取到它的 pid 后,可以使用 perf 查看具体情况。
执行命令
sudo perf top -g -p 5444
可以从执行关系里看到 add 这个函数占用了 60% 的资源