性能测试必备知识(5)- 深入理解“CPU 上下文切换”
做性能测试的必备知识系列,可以看下面链接的文章哦
https://www.cnblogs.com/poloyy/category/1806772.html
前言
上一篇文章中,举例了大量进程等待 CPU 调度的场景
灵魂拷问
既然进程是在等待,并没有运行,为什么系统的平均负载还是会升高呢
回答
本文的重点:CPU 上下文切换就是罪魁祸首
先来聊聊 Linux
提出疑问
- 之前说最好一个 CPU 运行一个进程,这样 CPU 利用率刚刚好
- 但事实上我们的 Linux 会同时运行很多进程,包括系统态的和自己启动的进程,这不就违背了我们的美好初衷吗?
知识点来回答疑问
- Linux 是一个多任务操作系统
- 它支持远大于 CPU 数量的任务同时运行
- 但多任务其实并不是真的在同时运行
- 而是因为系统在很短时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉
什么是 CPU 上下文
CPU 寄存器和程序计数器(PC)
- 在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行
- 所以需要系统事先帮它设置好 CPU 寄存器和程序计数器
CPU 寄存器
CPU 内置的容量小,但速度极快的内存
程序计数器
用来存储 CPU 正在执行的指令位置,或者即将执行的下一条指令位置
CPU 上下文
CPU 寄存器和程序计数器是 CPU 在运行任何任务前,必须的依赖环境,所以也被叫做 CPU 上下文

CPU 上下文切换
分步骤去理解
- 先把前一个任务的 CPU 上下文(CPU 寄存器和程序计数器)保存起来
- 加载新任务的上下文到这些寄存器和程序计数器
- 最后再跳转到程序计数器所指的新位置,运行新任务
- 保存下来的上下文,会存储到系统内核中,并在任务重新调度执行时再次加载进来,这样能保证任务原来的状态不受影响,让任务看起来还是连续运行
灵魂拷问一
CPU 上下文切换无非就是更新了 CPU 寄存器的值嘛,但这些寄存器,本身就是为了快速运行任务而设计的,为什么会影响系统的 CPU 性能呢?
灵魂拷问二
- 上面老说到的【任务】到底是什么呢?
- 是进程,线程?是的,进程和线程是最常见的任务
- 那除此之外,还有其他的任务吗?
回答
硬件通过触发信号,会导致中断处理程序的调用,也是一种常见的任务
所以,根据任务的不同,CPU 的上下文切换可以分为不同的场景
- 进程上下文切换
- 线程上下文切换
- 中断上下文切换
系统调用
Linux 按照特权等级划分进程的运行空间
分为
- 内核空间(Ring 0):具有最高权限,可以直接访问所有资源
- 用户空间(Ring 3):只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源

也就是说,进程既可以在用户空间运行,称为进程的用户态
又可以在内核空间运行,称为进程的内核态
重点:用户态到内核态的转变需要通过系统调用来完成
系统调用的栗子
比如,当我们查看文件内容时,就需要多次系统调用来完成:
- 首先调用 open() 打开文件
- 然后调用 read() 读取文件内容
- 并调用 write() 将内容输出
- 最后调用 close() 关闭文件
系统调用的过程发生 CPU 上下文的切换
- CPU 寄存器里原来用户态的指令位置,需要先保存起来
- 为了执行内核态代码,CPU 寄存器需要更新为内核态指令的新位置
- 最后才是跳转到内核态运行内核任务
- 系统调用结束后,CPU 寄存器需要恢复原来保存的用户态
- 然后再切换回用户空间,继续运行进程
总结下
- 一次系统调用的过程,其实发生了两次 CPU 上下文切换(用户态切内核态,内核态再切回用户态)
- 系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程
和进程上下文切换的不同
- 进程上下文切换:从一个进程切换到另一个进程运行
- 系统调用:一直是同一个进程在运行
总结
- 系统调用过程通常称为特权模式切换,而不是上下文切换
- 但实际上,系统调用过程中, CPU 上下文切换是无法避免的
进程上下文切换
基础知识点
- 在 Linux 中,进程是由内核来管理和调度
- 进程的切换只能发生在内核态
- 所以,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态
进程的上下文切换就比系统调用时多了一步
- 在保存当前进程的内核状态和 CPU 寄存器之前,需要先把该进程的虚拟内存、栈等保存下来【保存上下文】
- 而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈【加载上下文】

保存上下文和加载上下文的过程需要内核在 CPU 上运行才能完成
进程上下文切换如何影响系统性能?
- 根据 Tsuna的测试报告,每次上下文切换都需要几十纳秒到数微秒的 CPU 时间
- 这个时间还是略大的,特别是在进程上下文切换次数较多的情况下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间
- 这也正是上一篇文章中讲到的,导致平均负载升高的一个重要因素
TLB 也会受影响?
- TLB(Transaction Lookaside Buffer)来管理虚拟内存到物理内存的映射关系
- 当虚拟内存更新后,TLB 也需要刷新,内存的访问也会变慢
- 特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程
什么时候会切换进程上下文
- 顾名思义,只有在进程切换时才需要切换上下文
- 换句话说,只有在进程调度时才需要切换上下文
CPU 如何挑选进程来运行?
- Linux 为每个 CPU 都维护了一个等待队列
- 将活跃进程(正在运行和正在等待 CPU 的进程)按照优先级和等待 CPU 的时间排序
- 然后选择最需要 CPU 的进程,也就是优先级最高和等待 CPU 时间最长的进程来运行
进程什么时候才会被调度到 CPU 上运行?
1 - 主动释放
进程执行完终止了,会释放 CPU,这时候从等待队列中拿一个新的进程来运行
2 - 时间片轮转
为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行
3 - 资源不足
进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候 进程也会被挂起,并由系统调度其他进程运行
4 - sleep 函数
当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度
5 - 优先级高
当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行
6 - 硬中断
发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序
线程上下文切换
先来聊下线程和进程的关系
- 线程和进程的最大区别在于:线程是调度的基本单位,进程是资源分配的基本单位
- 内核中的任务调度,实际上的调度对象是线程
- 而进程只是给线程提供了虚拟内存、全局变量等资源
- 当进程只有一个线程时,可以任务进程=线程
- 当进程有多个线程时,线程会共享进程的虚拟内存和全局变量等资源,在线程上下文切换时这些资源是不需要修改的
- 线程也有独立的数据,比如栈、寄存器等,这些在线程上下文切换时是需要保存的
线程上下文切换的场景一
- 前后两个线程属于不同进程
- 此时,因为不同进程的资源不共享,所以线程上下文切换 等同于 进程上下文切换
线程上下文切换的场景二
- 前后两个线程属于同一个进程
- 此时,因为同一进程的资源是共享的,所以在切换时,虚拟内存这些资源就保持不动
- 只需要切换线程的私有数据、寄存器等不共享的数据
多线程的优势
线程上下文切换对比进程上下文切换,很明显切换消耗的资源会更少,所以多线程比多进程更有优势
中断上下文切换
中断处理
为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件
在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行
和进程上下文切换的不同点
- 中断上下文切换并不涉及到进程的用户态
- 即便中断过程打断了 一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源
- 中断上下文,只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数
中断上下文不会和进程上下文切换同时发生
- 对同一个 CPU 来说,中断处理比进程拥有更高的优先级
- 由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束
耗资源程度
- 跟进程上下文切换一样,中断上下文切换也需要消耗 CPU,切换次数过多也会耗费大量的 CPU,甚至严重降低系统的整体性能
- 当发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能问题
CPU 上下文切换的总结
- CPU 上下文切换,是保证 Linux 系统正常工作的核心功能之一,一般情况下不需要关注【CPU 上下文切换是正常核心功能值】
- 但过多的上下文切换,会把 CPU 时间消耗在寄存器、内核栈、虚拟内存等数据的保存和恢复上,从而缩短进程真正的运行时间,导致系统的整体性能大幅下降【数据保存和恢复时间增加,进程运行时间减少,性能下降】
性能测试必备知识(5)- 深入理解“CPU 上下文切换”的更多相关文章
- 如何理解CPU上下文切换(二)
如何理解CPU上下文切换(二) 1.引 你们好,可爱的小伙伴们.^_^ 多个进程竞争CPU就是一个经常被我们忽视的问题. 你们一定很好奇,进程在竞争CPU的时候并没有真正运行,为什么还会导致系统的负载 ...
- 性能测试必备知识(6)- 如何查看“CPU 上下文切换”
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 课前准备,安装 sysbench 下载 sy ...
- 性能测试必备知识(7)- 深入理解“CPU 使用率”
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 回顾 CPU 使用率是单位时间内 CPU 使 ...
- 性能测试必备知识(2)- 查看 Linux 的 CPU 相关信息
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 查看系统 CPU 信息 cat /proc/ ...
- 性能测试必备知识(11)- 怎么理解内存中的Buffer和Cache?
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 缓存 从 free 命令可以看到,缓存其实就 ...
- 性能测试必备知识(4)- 使用 stress 和 sysstat
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html stress 介绍 Linux 系统压力测试 ...
- 性能测试必备知识(10)- Linux 是怎么管理内存的?
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 内存映射 日常生活常说的内存是什么 比方说, ...
- 从Java视角理解CPU上下文切换(Context Switch)
从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态 在高性能编程时,经常接触到多线程. 起初我们的理解是, 多个线程并行地执行总比单个线程要快, 就像多个人一起干活总比一个人干要快 ...
- 03 | 基础篇:经常说的 CPU 上下文切换是什么意思?(上)
上一节,我给你讲了要怎么理解平均负载( Load Average),并用三个案例展示了不同场景下平均负载升高的分析方法.这其中,多个进程竞争 CPU 就是一个经常被我们忽视的问题. 我想你一定很好奇, ...
随机推荐
- java基础-8种基本类型
正文 java中的八种基础类型. boolean:只有两个值,false,true 带符号类型 byte:占用1个字节,一个字节也就是8位,那么由于是最高一位是用来表示 负还是正,所以范围就是 -2^ ...
- Java 多线程基础(十一)线程优先级和守护线程
Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...
- mysql语句基本练习
select ename,job from emp where job in ('MANAGER','ANALYET','SALESMAN') 1.查询出工作岗位为MANAGER.ANALYST.SA ...
- 为Linux主机安装图形化桌面环境
本文主要介绍在Linux实例中,centos 7 以及ubutun 14如何安装图形化桌面环境. CentOS 7 此处以安装MATE桌面环境为例,步骤如下. 说明:在安装重启后,如果卡在启动页面,需 ...
- jQuery控制倒计时
1.1 秒杀的倒计时 做秒杀网页总免不了倒计时,但没有很好的服务器,啥资源都没有,只能将部分任务交给浏览器去处理,比如秒杀首页的倒计时,因为真正秒杀是在具体页面,首页只是展示而已,所以误差一点是允许的 ...
- CSS中那些必须掌握的概念
一.盒子模型 1.什么是盒子模型 css盒模型本质上是一个盒子,封装周围的html元素,它包括:外边距(margin).边框(border).内边距(padding).实际内容(content)四个属 ...
- Spring — 循环依赖
读完这篇文章你将会收获到 Spring 循环依赖可以分为哪两种 Spring 如何解决 setter 循环依赖 Spring 为何是三级缓存 , 二级不行 ? Spring 为啥不能解决构造器循环依赖 ...
- Python3笔记010 - 3.1 程序结构
第3章 流程控制语句 3.1 程序结构 程序设计的基本结构: 顺序结构---顺序执行所有语句 选择结构---选择执行部分语句 循环结构---循环执行部分语句 1.顺序结构 按照顺序执行语句. 2.选择 ...
- web测试要点、方法_web端测试大全总结
一.功能测试 1.1链接测试 链接是web应用系统的一个很重要的特征,主要是用于页面之间切换跳转,指导用户去一些不知道地址的页面的主要手段,链接测试一般关注三点: 1)链接是否按照既定指示那样,确实链 ...
- CSS技术让高度自适应减少很多不必要的检测
高度自适应第一种情况 1.高度不去设置,或者高度设置auto 内容撑开父元素的高度.2.内容撑开父元素的高度 -> 最小高度的设置 min-height3.浮动元素添加高度自适应 -> 添 ...