Linux操作系统通过实战理解CPU上下文切换

news2024/9/27 19:26:14
前言:Linux是一个多任务的操作系统,可以支持远大于CPU数量的任务同时运行,但是我们都知道这其实是一个错觉,真正是系统在很短的时间内将CPU轮流分配给各个进程,给用户造成多任务同时运行的错觉。所以这就是有一个问题,在每次运行进程之前CPU都需要知道进程从哪里加载、从哪里运行,也就是说需要系统提前帮它设置好CPU寄存器和程序计数器。

1、CPU上下文

CPU上下文其实是一些环境正是有这些环境的支撑,任务得以运行,而这些环境的硬件条件便是CPU寄存器和程序计数器。CPU寄存器是CPU内置的容量非常小但是速度极快的存储设备,程序计数器则是CPU在运行任何任务时必要的,里面记录了当前运行任务的行数等信息,这就是CPU上下文。

2、CPU上下文切换

根据任务的不同,CPU的上下文切换就可以分为进程上下文切换、线程上下文切换、中断上下文切换
,进程上下文切换。

在Linux中,Linux按照特权等级,将进程的运行空间分为内核空间和用户空间:

  • 内核空间具有最高权限,可以直接访问所有资源
  • 用户空间只能访问受限资源,不能直接访问内存等硬件设备,要想访问这些特权资源,必须通过系统调用

对于一个进程来说,一般是运行在用户态的,但是当需要访问内存、磁盘等硬件设备的时候需要陷入到内核态中,也就是要从用户态到内核态的转变,而这种转变需要通过系统调用来实现,例如一个打开文件的操作,需要调用open()打开文件,read()读取文件内容,write()将文件内容输出到控制台,最后close()关闭文件,这就是系统调用

在系统调用的过程中同样发发生了CPU上下文切换:

  • CPU寄存器里面原来用户态的指令位置,需要先保存起来,接着运行内核态代码
  • CPU寄存器需要更新为内核态指令的位置,执行内核态代码

系统调用结束后,CPU寄存器需要恢复原来保存的用户态,然后切换为用户空间,所以一次系统调用的过程,会发生两次的CPU上下文切换但是我们一般说系统调用是特权模式切换而不是上下文切换,因为这里没有涉及到虚拟内存等这些进程用户态的资源,也不会切换进程是属于进程之内的上下文切换,进程是由内核来管理和调度的,进程的切换只能发生在内核态,所以进程的上下文包含了虚拟内存、栈、全局变量等用户空间的资源,还包含了内核堆栈、寄存器等内核空间的状态,所以进程的上下文切换要比系统调用更多一步,保存该进程的虚拟内存、栈等用户空间的资源,进程上下文切换一般需要几十纳秒到数微秒的CPU时间,当进程上下文切换次数比较多的情况下爱,将导致CPU将大量的时间耗费在寄存器、内核栈即虚拟内存等资源的保存和恢复上,另外,Linux通过TLB快表来管理虚拟内存到物理内存的映射关系,当虚拟内存更新之后,需要刷新缓存,在这多处理系统上是很复杂的,因为多个处理器共享一个缓存。

下面再来说说什么时候会进行进程的上下文切换,其实就是进程在被调度的时候需要切换上下文,可能是主动地,也有可能是被动的

  • 系统进程正常调度算法导致进程上下文切换,例如目前使用的时间片轮转算法,当一个进程的时间片耗尽之后,CPU会进项进程的调度切换到其他进程
  • 进程在资源不足的时候,会被挂起例如在等待IO或者内存不足的时候,会主动挂起,并且等待系统调度其他进程
  • 当进程通过一些睡眠函数sleep()主动挂起的时候,也会重新调度
  • 当有高优先级的进程运行时,当前进程也会被挂起
  • 当发生硬件中断时,CPU上的进程会被中断挂起

3、线程上下文切换

线程是调度的基本单位,而进程则是资源拥有的基本单位,也就是说对于内核中的任务调度是以线程为单位,但是进程只是给线程提供了虚拟内存、全局变量等资源,进程与线程之间的区别这里不再介绍
那么线程上下文的切换,其实分为两种情况:

  • 前后两个线程属于不同进程,因为资源不共享,所以这时候的线程上下文切换和进程上下文切换是一致的
  • 前后两个线程属于同一个进程,因为虚拟内存是共享的,所以在切换的时候,虚拟内存这些资源保持不动,只有切换线程的私有数据、寄存器等不共享的资源

所以同进程内的线程切换要比多进程内的线程切换消耗更少的资源

 

4、中断上下文切换

中断是为了快速响应硬件的事件,简单来shu就是计算机停下当前的事情,去处理其他的事情,然后在回来继续执行之前的任务,例如我们在调用print函数的时候,其实汇编的底层会帮我们调用一条 int 0x80的指令,便是调用0x80号中断
当然,中断要先将当前进程的状态保存下来,这样中断结束后进程仍然可以从原来的状态恢复运行,中断上下文的切换并不涉及进程的用户态,所以当中断程序打断了正在处于用户态的进程,不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源,只需要保存和恢复这个进程的内核态中的资源包括CPU寄存器、内核堆栈等
对于同一个CPU来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生,一般来说中断程序都执行比较快短小精悍,以便快速结束执行之前的任务。当中断上下文切换次数比较多的时候,会耗费大量的CPU
怎么查看系统上下文
上面已经介绍到CPU上下文切换分为进程上下文切换、线程上下文切换、中断上下文切换,那么过多的上下文切换会把CPU的时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成为系统性能大幅下降的一个因素
所以我们可以使用vmstat这个工具来查询系统的上下文切换情况,vmstat是一个常用的系统性能分析工具,可以用来分析CPU上下文切换和中断的次数

需要特别关注的是:

  • cs(context switch):每秒上下文切换的次数
  • in(interrupt):每秒中断的次数
  • r(Running or Runnable):就绪队列的长度,也就是正在运行和等待CPU的进程
  • b(Blocked):处于不可中断睡眠状态的进程数

vmstat是给出整个系统总体的上下文切换情况,要想查看每个进程的详细情况就需要使用pidstat,加上-w选项就可以查看进程上下文切换的情况

img

需要特别关注的是:

  • cswch(voluntary context switches):表示每秒自愿上下文切换的次数
  • nvcswch(non voluntary context switches):表示每秒非自愿上下文切换的次数

  资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

这两个概念的分别含义:

  • 自愿上下文切换:进程无法获取所需的资源,导致的上下文切换,例如IO、内存等资源不足时,就会发生自愿上下文切换
  • 非自愿上下文切换:进程由于时间片已到等时间,被系统强制调度,进而发生的上下文切换,例如大量的进程都在争抢CPU时,就容易发生非自愿上下文切换

实战分析
通过上面的工具已经可以初步查看到系统上下文切换的次数,但是当系统上下文切换的次数为多少时是不正常的呢?
案例使用sysbench工具来模拟多线程调度切换的情况,sysbench是一个多线程的基准测试工具,可以模拟上下文切换过多的问题
首先在第一个终端运行stsbench,模拟多线程切换问题
# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题 sysbench --threads=10 --max-time=300 threads run
然后在第二个终端运行vmstat,每1秒查看上下文切换的情况

可以观察到如下指标:

  • r列:就绪队列的长度已经到了8左右,已经超过了2个cpu,所以会有大量的CPU竞争
  • us(user)列和sy(system)列,这两列的CPU使用率已经到达100%,并且大量是由sy造成的,说明CPU主要是被内核占用了
  • in(interrupt):in列的数值也到了解决1万,所以中断处理也是一个问题

那我们接着使用pidstat来查看是那一个进程出现了问题,由于pidstat默认是显示进程的指标数据,但是我们使用sysbench模拟的线程的数据,所以需要加上-t选项
gpw@gopuwe:~$ pidstat -wt

img

所以到这里可以分析出是sysbench的子线程的上下文切换次数有很多
还有一个问题,在使用vmstat的时候,发现in指标的数据也比较多,那么我们需要找出是什么类型的中断导致了中断上升,中断肯定是发生在内核态,但是pidstat只是一个进程的性能分析工具,并不提供任何关于中断的详细信息
我们可以从/proc/interrupts这个只读文件中读取,/proc是一个虚拟文件系统,用于内核空间和用户空间之间的通信,/proc/interrupts则提供了一个只读的中断使用情况,可以使用cat命令查看/proc/interrupts可以发现变化速度最快的是重调度中断RES,这个中断类型表示唤醒空闲状态的CPU来调度新的任务运行,也被成为处理器中断
那么到底上下文切换的次数为多少合适呢?
这个数值其实取决于系统本身的 CPU 性能,在我看来,如果系统的上下文切换次数比较稳
定,那么从数百到一万以内,都应该算是正常的。但当上下文切换次数超过一万次,或者切
换次数出现数量级的增长时,就很可能已经出现了性能问题,这个时候还要根据上下文切换的类型,做具体的分析,例如:

  • 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
  • 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU的确成了瓶颈;
  • 中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/695813.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis实战案例3-缓存概念和添加Redis缓存

1. 缓存 缓存是数据交换的缓冲区,是贮存数据的临时地方,一般读写性能较高; 其中数据库缓存,例如:索引数据,MySQL会给id创建索引,从而查询时可以在内存中快速检索,提升速度&#xff1…

MDK指定.sct(分散加载描述文件)文件位置

文章目录 MDK指定.sct(分散加载描述文件)文件位置概述END MDK指定.sct(分散加载描述文件)文件位置 概述 用STM32CubeMX生成的工程, 默认的.sct位置在临时输出目录, 里面都是.o. 都是工程编译时生成的临时文件(中间文件) 当工程归档时, 这个临时目录肯定是要删除的(编译过程…

用ThinkJs框架快速搭建博客网站

ThinkJS是一个企业级的NodeJS应用框架,整合了各种常用SDK以及企业级常用的技术方案,为减少了开发人员的学习成本,提高团队的开发效率而生。框架底层基于Koa2实现,并且结合ThinkPHP的思想,使代码更加简洁实用。 ThinkVu…

Dependency ‘io.spring.platform:platform-bom:Cario-SR7‘ not found

刚看到这个错的时候&#xff0c;以为是maven中需要配置aliyun镜像的缘故&#xff0c;所以&#xff0c;在/conf/settings.xml中加入了aliyun镜像&#xff1a; <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.al…

智能优化算法六种常见图—参数空间图、搜索历史图、第一维度轨迹图、多样性曲线、平均适应度曲线、收敛曲线图(以黏菌算法为例)

一、基本介绍&#xff1a; 智能优化算法六种常见图绘制—参数空间图、搜索历史图、第一维度轨迹图、多样性曲线、平均适应度曲线、收敛曲线图。一篇文章有几张高颜值的图片&#xff0c;能给审稿人留下良好的第一印象。以上这些图像均可用于仿真实验中。各图像功能如下&#xf…

五个维度,解析 Spring 中 @Autowired 和 @Resource 的区别

Autowired注解是由Spring提供的&#xff0c;它可以用来对构造方法、成员变量及方法参数进行标注&#xff0c;它能够根据对象类型完成自动注入&#xff0c;代码如下&#xff1a; public class Service {// 构造方法注入Autowiredpublic Service(Service service) {this.service…

实现一个转盘随机选择器

实现效果 完整代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title><…

Java的Stream流详细讲解

一.Stream 是什么 Stream是Java 8新增的重要特性, 它提供函数式编程支持并允许以管道方式操作集合. 流操作会遍历数据源, 使用管道式操作处理数据后生成结果集合, 这个过程通常不会对数据源造成影响。 ​ 同时stream不是一种数据结构&#xff0c;它只是某种数据源的一个视图&…

Neo4j desktop在界面上使用dump备份还原

Neo4j数据库的版本在4.4版本中有dump &#xff08;Neo4j 3.5的版本没有dump文件&#xff09;&#xff0c;选中某个数据库可以使用dump导出一个.dump文件。 导出后的文件 导入dump文件&#xff0c;创建新的数据库

基于InteloneAPI的油锅爆燃预警系统

基于InteloneAPI的油锅爆燃预警系统 前言一、方案介绍1.系统概述2.设计思路 二、方案实现1.ResNet-18模型2.Intel OneAPI AI Kit 使用1.Intel Neural Compressor&#xff1a;2.Intel Optimization for PyTorch* 三、方案价值总结 前言 家居场景下&#xff0c;最容易起火的原因…

selenium自动化登录(实战解析)

目录 1.纯英文验证码 1.首先需要了解运行所需要的模块 2.获取我们的目标地址链接 3.进入古诗词首页面&#xff0c;找到验证码的标签&#xff0c;获取并且保存 4.调用超级鹰打码平台 5.调用超级鹰内的方法 6.输入账号密码 7.模拟登陆需要用cookie保持登陆状态 相信有很多…

人工智能 | 技能人才评价证书分析及人工智能/计算机类证书推荐

目录 简介技能人才评价证书相关介绍1. 国家职业资格证书2. 职业技能等级证书 推荐证书目录1. 计算机类的国家职业资格证书a. 证书推荐b. “软高***”和“PMP”的区别 2. 计算机类的职业技能等级证书a. 工信部认证b. 中国人工智能学会证书 专业证书的作用1. 抵税2. 领取职业技能…

想要让视频素材格式快速调整转换的方法分享

有时候有些视频播放软件不支持播放某些格式的视频文件&#xff1f;那要怎么解决呢&#xff1f;换一个播放软件&#xff1f;不妨试试批量转换视频格式&#xff0c;简单的几步操作就能快速解决烦恼&#xff0c;跟着小编一起来看看具体的操作环节吧。 首先先进入“固乔科技”的官网…

Apikit 自学日记:发起快速测试

功能入口&#xff1a;API管理应用 / 选中某个项目 / API文档菜单 / 选中标签页旁加号 发起快速测试 如果未创建该接口文档&#xff0c;仅临时调试接口&#xff0c;则可创建API快速测试页面。可在这个页面输入接口相关的信息并进行快速测试。具体各协议的测试字段配置&#xf…

NoSQL之Redis配置

NoSQL 一、关系型数据库与非关系型数据库关系型数据库非关系型数据库区别 二、Redis简介Redis的优点Redis的使用场景 三、Redis安装部署四、Redis命令工具redis-cli 命令行工具redis-benchmark 测试工具 五、Redis 数据库常用命令六、Redis多数据库常用命令 一、关系型数据库与…

深入浅出设计模式 - 观察者模式

博主介绍&#xff1a; ✌博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家✌ Java知识图谱点击链接&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; &#x1f495;&#x1f495; 感兴趣的同学可以收…

【Sql】win11系统安装sqlserver2008r2数据库,找不到文件user.config line 5

【问题描述】 在win11系统环境下&#xff0c; 安装sql server 2008 r2数据库的时候&#xff0c;提示【Microsoft.NET Framework】窗口错误。 如果点击继续&#xff0c;应用程序将忽略此错误并尝试继续。 具体错误明细&#xff1a; 创建userSettings/Microsoft.SqlServer.Config…

centos下的Nginx的安装 --yum安装

1.没有可用软件包 nginx 2.检查yum源下nginx相关软件包 3.解决yum源无nginx软件包问题 yum install epel-release yum update更新yum源后查询结果 4.安装nginx yum -y install nginx5.yum安装后的nginx相关目录 6.查看nginx.conf&#xff0c;确定nginx相关具体目录 详细配置…

ECCV2020-DY-RELU

论文地址&#xff1a;https://arxiv.org/abs/2003.10027论文代码&#xff1a;https://github.com/Islanna/DynamicReLU三方复现&#xff1a;Dynamic ReLU: 与输入相关的动态激活函数 - 知乎 ReLU是深度学习中很重要的里程碑&#xff0c;简单但强大。目前有很多ReLU的改进版&am…

【uniapp学习之分享小程序页面】

一、设置分享功能之前的样子 二、在代码中开启分享转发按钮 <script>export default {data() {return {}},methods: {},onLoad() {wx.showShareMenu({withShareTicket: true,menus: [shareAppMessage, shareTimeline]});},onShareAppMessage(res) { //发送给朋友return …