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

前言: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选项就可以查看进程上下文切换的情况

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

需要特别关注的是:

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

这两个概念的分别含义:

  • 自愿上下文切换:进程无法获取所需的资源,导致的上下文切换,例如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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

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

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

相关文章

个人网站搭建-步骤(持续更新)

域名申请 域名备案 域名解析 服务器购买 端口转发 Nginx要在Linux上配置Nginx进行接口转发,您可以按照以下步骤进行操作: 安装Nginx(如果尚未安装): 使用包管理工具(如apt, yum, dnf, 或zypper&#x…

高考志愿不知道怎么填?教你1招,用这款AI工具,立省4位数

高中的岁月,就像一本厚厚的书,我们一页页翻过,现在,终于翻到了最后一页。但这不是结束,这是新的开始,是人生的新篇章。 高考落幕,学子们在短暂的放松后,又迎来了紧张的志愿填报。 “…

使用bootstrap框架做一个Aotm Blog个人博客

使用bootstrap框架做一个Aotm Blog个人博客,展示一些自己的个人信息,有四个博客分类:心情记录、学习笔记、旅行相册、美食打卡。 主界面图: 心情记录界面 学习笔记界面: 旅行相册界面: 美食打卡界面&#…

深入探索:大型语言模型消除幻觉的解决之道

随着人工智能技术的飞速发展,大型语言模型(LLMs)已经成为自然语言处理领域的明星。它们以其庞大的知识库和生成连贯、上下文相关文本的能力,极大地推动了研究、工业和社会的进步。然而,这些模型在生成文本时可能会产生…

Unity保存玩家的数据到文件中(Unity的二进制序列化)

文章目录 文章运行环境什么是二进制序列化读写文件构造函数 自定义二进制序列化 文章运行环境 Unity2022 什么是二进制序列化 Unity中的二进制序列化是一种将游戏对象或数据结构转换为二进制格式的过程,以便于存储或网络传输。这使数据能够以高效的方式保存&…

富唯智能推出的AMR复合机器人铝板CNC上下料方案

随着科技的不断进步,CNC加工行业正面临着前所未有的变革。传统的CNC上下料方式已无法满足现代生产对效率、精度和安全性的高要求。在这样的背景下,富唯智能推出的AMR复合机器人铝板CNC上下料方案,以其智能化、自动化的特点,引领了…

Mind+在线图形编程软件(Sractch类软件)

Scratch作为图形编程软件,可以为小朋友学习编程提供很好的入门,是初次接触编程的小朋友的首选开发软件。这里介绍的Mind软件与Sractch用法几乎完全一致,并且可以提供在线免安装版本使用,浏览器直接打开网址: ide.mindp…

LeetCode.32最长有效括号详解

问题描述 给你一个只包含 ( 和 ) 的字符串,找出最长有效(格式正确且连续)括号子串的长度。 解题思路1 有效的括号字符串意味着每一个左括号 ( 都可以找到一个相匹配的右括号 )。栈可以帮助我们追踪尚未匹配的括号,并有效地处理…

Micro-ROS是什么?

Micro-ROS是ROS(Robot Operating System,机器人操作系统)生态系统的一个重要组成部分,专为微控制器(Microcontrollers)设计的轻量级ROS版本。它的目标是在资源有限的嵌入式平台上实现ROS 2的功能&#xff0…

RocketMQ:日常开发中有哪些使用MQ的场景

什么是消息队列? 消息队列是一种通信方法,允许应用程序通过发送和接收消息来互相通信。这些消息/任务/指令存储在一个中间介质中(即队列),并由生产者发送,消费者接收。 使用场景 场景一:任务…

昇思25天学习打卡营第1天|基本介绍

MindSpore 基本介绍设计理念层次结构 基本介绍 昇思MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景统一部署三大目标。 易开发:API友好、调试难度低高效执行:包括计算效率、数据预处理效率和分布式训练效率全场景&am…

手写SpringMVC之ApplicationContextListener

什么是Spring MVC? Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC”来自其源模块的名称( spring-webmvc ),但它通常被称为“Spring MVC”。 手写…

【python】OpenCV—Color Map

文章目录 cv2.applyColorMapcv2.putText小试牛刀自定义颜色 参考学习来自 OpenCV基础(21)使用 OpenCV 中的applyColorMap实现伪着色 cv2.applyColorMap cv2.applyColorMap() 是 OpenCV 中的一个函数,用于将灰度图像或单通道图像应用一个颜色…

The First Descendant卡顿怎么办?快速处理第一后裔卡顿

第一后裔/The First Descendant是一款刷宝类RPG射击游戏,以虚幻引擎5为基础,使其对决场景十分精彩、刺激,从而吸引了大批冒险者前往,这里揭开属于英格里斯和继承者的秘密。不过有很多玩家,反馈在对局时遇到了卡顿、画面…

Ubuntu 20.04.3 LTS 安装打印服务器 局域网发现系统服务 共享给 windows 10/11 使用

ubuntu安装部署打印服务器可参考: Ubuntu 20.04.3 LTS 安装hp 1020 plus 打印机 通过cups共享给 windows 10/11 使用-CSDN博客 1 windows 10 ,局域网搜索不到共享的hp1020打印机 2 Ubuntu使用Avahi进行局域网服务发现和设备发现,安装avahi-daemon sudo apt-updat…

【Linux】Linux下使用套接字进行网络编程

🔥博客主页: 我要成为C领域大神🎥系列专栏:【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 ​ 用于网络应用开…

Java基础(四)——字符串、StringBuffer、StringBuilder、StringJoiner

个人简介 👀个人主页: 前端杂货铺 ⚡开源项目: rich-vue3 (基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL) 🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展 &#x1…

【技巧】如何检查多个GPU之间是否支持P2P通信

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 需要用到cuda_samples:GitHub - NVIDIA/cuda-samples 该工具的详细解释可以看这个: 【知识】详细介绍 CUDA Samples 示例工程…

不止是只有维度建模,数据仓库还有Data Vault建模

引言 在数据仓库设计中,传统的星型和雪花型模型有着各自的优势和劣势。随着数据量的增大和数据源的多样化,Data Vault(数据仓库)建模方法逐渐受到关注和应用。Data Vault建模是一种灵活、可扩展、适应性强的建模方法,…

Java知识点整理 12 — 前端 Ant Design Pro 初始化模板使用

一. 项目初始化 Ant Design Pro 是基于 Ant Design 和 umi 封装的一整套企业级中后台前端设计框架,致力于在设计规范和基本组件的基础上,继续向上构建,提炼出典型模板或配套设计资源,进一步提升企业级中后台产品设计研发过程中的…