| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> CPU上下文切换、进程上下文、中断上下文 -> 正文阅读 |
|
[嵌入式]CPU上下文切换、进程上下文、中断上下文 |
????????由于Linux是一个多任务操作系统,能够支持远大于CPU数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是由CPU进行调度,将时间分片,每个任务占用1个时间片,通过轮流的方式运行,但由于时间片粒度非常小,而CPU速度非常高,造成多任务同时运行的错觉。实际上,对于单个CPU核,其处理数据是串行的,就比如做核酸检测,只有一个检测口,组织人员会在检测口排几个队列,每个队列头部数出10个人构成一组。检测口就相当于CPU,无论怎么排队,所有人都得经过检测口,它的工作量一点没有变。但是各队列中的10人小组是轮换的,这样稍微增加一些效率(减少了数10个人的时间),保证了公平性(每个队列都是等同的,大家随便排到哪个队列里),如果检测速度非常快,那么单个队列里的各10个人小组可能并不觉得有另外几个队列的存在。对于多队列多CPU核的情况就复杂了,这里不讨论了。 ?????????在每个任务(进程、线程、中断)运行前,CPU都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好 CPU寄存器和程序计数器。以核酸检测为例,每个队列都有一个编号,从1-N;每个队列里的人都有一个号码,从1到K,但每个人胖瘦不同、检测耗时不同;核酸检测的时候,组织人员得知道下一次到了那个队列的哪个人员(这里假设做完核酸的人员还回到队列里)。如果组织人员不维护队列号码和队列内部的人员编号,那么整个过程将会混乱不堪。而组织人员做的事情就是给CPU的各寄存器装订正确的参数。这里面,队列就相当于任务,人员就相当于指令。 什么是CPU上下文????????CPU寄存器和程序计数器(也是一个寄存器)就是CPU上下文,因为它们都是CPU在运行任何任务前,必须的依赖环境。也就是上面的队列ID和人员编号。
什么是CPU上下文切换????????就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务的过程。 ????????而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。 CPU上下文切换的类型????????根据任务的不同,可以分为以下三种类型:
进程上下文切换????????Linux按照特权等级,把进程的运行空间分为内核空间和用户空间,CPU特权等级的Ring0和Ring3。
????????进程既可以在用户空间运行,又可以在内核空间中运行。进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。 系统调用????????从用户态到内核态的转变,需要通过系统调用来完成。比如,当我们查看文件内容时,就需要多次系统调用来完成:首先调用open()打开文件,然后调用read()读取文件内容,并调用write()将内容写到标准输出,最后再调用close()关闭文件。 ????????在这个系统调用的执行过程中就发生了CPU上下文切换,整个过程是这样的:
????????所以,一次系统调用的过程,其实是发生了两次CPU上下文切换。(用户态-内核态-用户态) ????????不过,需要注意的是,系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程。这跟我们通常所说的进程上下文切换是不一样的:进程上下文切换,是指从一个进程切换到另一个进程运行;而系统调用过程中一直是同一个进程在运行。 ????????所以,系统调用过程通常称为特权模式切换,而不是上下文切换。系统调用属于同进程内的CPU上下文切换。但实际上,系统调用过程中,CPU的上下文切换还是无法避免的。 发生进程上下文切换的场景????????为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行。 进程上下文切换????????进程上下文切换可以描述为kernel执行下面的操作:
? ? ? ? 进程上下文切换只能发生在内核态,所以还会触发用户态与内核态切换。 ?上图中,我个人觉得右边的两次上下文切换中间没有写清楚。应该是A进程的用户模式--A进程的内核模式--B进程的内核模式--B进程的用户模式--B进程的内核模式--A进程的内核模式--A进程的用户模式。 ????????所谓进程上下文切换应该是指的是从A进程的用户态切换到B进程的用户态的过程,这中间需要内核来帮忙。内核相当于沟通所有进程的桥梁,每个进程都有一个门可以穿越到这个桥上,想从一个进程跳到另外一个进程,都得先走到桥上,然后找到另外一个进程的门,这就完成了内核态的转移,然后穿出这个门,就到了另外一个进程的用户态。这个是我个人理解,不一定对。 进程上下文切换跟系统调用又有什么区别呢????????进程是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。 ????????因此,进程的上下文切换就比系统调用时多了一步:在保存内核态资源(当前进程的内核状态和CPU寄存器)之前,需要先把该进程的用户态资源(虚拟内存、栈等)保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。总的来说就是进程的切换涉及到进程的内核栈和用户栈的保存与恢复,这比单个进程内部的系统调用造成的用户栈和内核栈复杂。这主要是因为时间片是定长的,A进程即时是在内核态运行,时间一到,也得切到别的进程。 ????????如下图所示,保存上下文和恢复上下文的过程并不是“免费”的,需要内核在CPU上运行才能完成。 ?进程上下文切换潜在的性能问题????????根据Tsuna的测试报告,每次上下文切换都需要几十纳秒到数微秒的CPU时间。这个时间还是相当可观的,特别是在进程上下文切换次数较多的情况下,很容易导致CPU将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。这也正是导致平均负载升高的一个重要因素。 ????????另外,我们知道,Linux通过TLB(TranslationLookasideBuffer)来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB也需要刷新,内存的访问也会随之变慢。特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。 线程上下文切换????????线程与进程最大的区别在于:线程是调度的基本单位,而进程则是资源拥有的基本单位。说白了,所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。 ????????所以,对于线程和进程,我们可以这么理解:
发生线程上下文切换的场景????????前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。 中断上下文什么是中断机制?????????中断机制是现代计算机系统中的基本机制之一,它在系统中起着通信网络的作用,以协调系统对各种外部事件的响应和处理,中断是实现多道程序设计的必要条件,中断是CPU 对系统发生的某个事件作出的一种反应。
中断的一个例子 ????????在你敲打键盘的时候,键盘控制器(控制键盘的硬件设备)会发送一个中断,通知操作系统有键按下。中断本质是一种特殊的电信号,由硬件设备发向处理器。处理器接受到中断后,会马上向操作系统反映此信号的到来,然后就由os负责处理这些新到来的数据。硬件设备生成中断的时候并不考虑与处理器的时钟同步——换句话说就是中断随时可以产生。因此,内核随时可能因为新到来的中断而被打断。 ?????????虽然人们在谈到中断(Interrupt)时,总会拿轮询(Polling)来做“反面”例子,但中断和轮询并不是完全对立的两个概念,它们是对立统一的。 “CPU执行完每条指令时,都会去检查一个中断标志位”,这句话是所有关于中断长篇大论的开场白,但很容易被人忽略,其实,这就是中断的本质。 ????????举个例子,CPU老板是一家公司的光杆司令,所有的顾客都要他亲自跑去处理,还要跟有关部门打点关系,CPU觉得顾客和公关这两样事它一个人搞不来,这就是轮询;终于这家公司升级发展了,CPU老板请了一个秘书,所有的顾客都先由秘书经手,CPU心情好的时候就去看一下,大部分时间都忙着去公关了,这时它觉得轻松了很多,这就是中断了~~ ????????也就是说,中断和轮询是从CPU老板的角度来看的,不管怎样,事件都还是有人来时刻跟踪才能被捕获处理,不过是老板还是秘书的问题。所有的中断(或者异步,回调等)背后都有一个轮询(循环,listener)。 中断上下文切换????????为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。 ????????跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等。 ? ? ? ? 对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。 ????????另外,跟进程上下文切换一样,中断上下文切换也需要消耗 CPU,切换次数过多也会耗费大量的 CPU,甚至严重降低系统的整体性能。所以,当你发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能问题。 总结一下,不管是哪种场景导致的上下文切换,你都应该知道:
如何查看系统的上下文切换????????我们可以通过
? ??我们需要重点关注下列内容:
????????想要查看每个进程的详细情况,需要使用 pidstat,给它加上
????????上述结果有两列是我们重点关注的对象,一个是 cswch,表示每秒自愿上下文切换的次数;另一个是 nvcswch,表示每秒非自愿上下文切换的次数。
????????如果由于系统的就绪队列过长,也就是正在运行和等待 CPU 的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统 CPU 的占用率升高。我们可以使用 pidstat 继续分析到底是哪个进程导致了这些问题!(下述内容是在只有2核cpu的虚拟机上执行的)
????????可以发现, 默认
????????虽然 ????????我们可以通过
????????可以发现,变化速度最快的是 每秒上下文切换多少次算正常这个数值其实取决于系统本身的 这时,你还需要根据上下文切换的类型,再做具体分析,比方说:
另外,本版内容被我改了好几次,主要是里面有不少内容还没有说清楚,我也一直在查资料。比如进程上下文切换为什么必须在内核空间发生?我会再写一篇解释这些问题。实际上上下文切换的内容还是很多的,光靠一两篇文档也解释不全。 参考链接: https://blog.csdn.net/qq_44861675/article/details/107736922 |
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 1:29:03- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |