linux-optimize002

cpu 上下文切换

设置好 cpu寄存器和程序计数器

依赖环境 因此叫做上下文

进程上下文切换 线程上下文切换 中断上下文切换

进程上下文切换

linux 按照特权等级 将进程的运行空间分为内核空间和用户空间

  • 内核空间ring 0 具有最高权限 可以直接访问所有资源
  • 用户空间 ring 3 只能访问受限资源 不能直接访问内存等硬件设备 必须通过系统调用陷入到内核中 才能访问这些特权资源

进程既可以在用户空间运行 也可以在内核空间中运行

  • 用户态
  • 内核态

从用户态到内核态的转变 需要通过系统调用来完成。

比如查看文件内容的时候,需要多次系统调用来完成,首先open()打开文件 然后read 读取文件内容 write 将内容写到标准输出 最后再close关闭文件

系统调用的过程中 有cpu上下文的切换

cpu寄存器里原来用户态的指令位置 需要先保存起来 接着为了执行内核态代码 cpu寄存器需要更新为内核态的新位置 最后才是跳到内核态运行内核任务

系统调用恢复之后cpu寄存器需要恢复 需要再切换一次

一次系统调用 发生了两次上下文切换

系统调用 被称为特权模式切换 而不是上下文切换

进程的切换只能发生在内核态 因此进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态

进程的上下文切换 比系统调用多了一步

在保存当前进程的内核状态和cpu寄存器之前 需要先把该进程的虚拟内存、栈等保存起来 而加载下一进程的内核态之后 还需要刷新进程的虚拟内存和用户栈

进程一和进程二之间 包含进程1上下文保存和加载进程2上下文

每次上下文的切换 都需要几十纳秒到数微秒的cpu时间 这个时间还是相当可观的

线程和进程的最大区别在于 线程是调度的基本单位 而进程则是资源拥有的基本单位

进程只是給线程提供了虚拟内存、全局变量等资源

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

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

线程也有自己的私有数据 比如栈和寄存器

线程的切换

  • 不属于同一进程的时候 因为资源不共享 所以切换和进程时一样的
  • 属于同一进程 因为虚拟内存是共享的 只需要切换线程的私有数据结构 栈 寄存器这些不共享的数据

同进程内的线程切换 要比对进程之间的切换消耗更少的资源 这也是多线程代替多进程的一个优势

中断上下文切换

为了快速响应硬件的事件 中断处理会打断进程的正常调度和执行 转而调用中断处理程序 响应设备事件

中断上下文切换不涉及到进程的用户态

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

cpu上下文切换 是保证linux系统正常工作的核心功能之一
过多的上下文切换 会把cpu时间消耗在寄存器 内核栈 虚拟内存等数据结构的保存和恢复上

1
vmstat 5
  • context switch
  • interrupt
  • r(running or runnable)
  • b blocked 则是处于不可中断睡眠状态的进程数
1
pidstat -w 5
1
apt install sysbench
1
sysbench --threads=10 --max-time=300 threads run
  • 自愿上下文切换变多 说明进程都在等待资源 有可能发生了io等其他问题
  • 非自愿上下文切换变多 说明进程都在被强制调度 都在争取cpu
  • 中断次数变多说明cpu被中断处理程序占用 还需要通过查看 /proc/interrupts 具体问题具体分析