0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux CPU上下文切换

jf_78858299 来源:码农的荒岛求生 作者:码农的荒岛求生 2023-02-15 14:44 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

我们都知道 Linux 是一个多任务操作系统,它支持的任务同时运行的数量远远大于 CPU 的数量。当然,这些任务实际上并不是同时运行的(Single CPU),而是因为系统在短时间内将 CPU 轮流分配给任务,造成了多个任务同时运行的假象。

CPU 上下文(CPU Context)

在每个任务运行之前,CPU 需要知道在哪里加载和启动任务。这意味着系统需要提前帮助设置 CPU 寄存器程序计数器

CPU 寄存器是内置于 CPU 中的小型但速度极快的内存。程序计数器用于存储 CPU 正在执行的或下一条要执行指令的位置。

它们都是 CPU 在运行任何任务之前必须依赖的依赖环境,因此也被称为 “CPU 上下文”。如下图所示:

图片

知道了 CPU 上下文是什么,我想你理解 CPU 上下文切换就很容易了。“CPU上下文切换”指的是先保存上一个任务的 CPU 上下文(CPU寄存器和程序计数器),然后将新任务的上下文加载到这些寄存器和程序计数器中,最后跳转到程序计数器。

这些保存的上下文存储在系统内核中,并在重新安排任务执行时再次加载。这确保了任务的原始状态不受影响,并且任务似乎在持续运行。

CPU 上下文切换的类型

你可能会说 CPU 上下文切换无非就是更新 CPU 寄存器和程序计数器值,而这些寄存器是为了快速运行任务而设计的,那为什么会影响 CPU 性能呢?

在回答这个问题之前,请问,你有没有想过这些“任务”是什么?你可能会说一个任务就是一个进程或者一个 线程 。是的,进程和线程正是最常见的任务,但除此之外,还有其他类型的任务。

别忘了硬件中断也是一个常见的任务,硬件触发信号,会引起中断处理程序的调用。

因此,CPU 上下文切换至少有三种不同的类型:

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

让我们一一来看看。

进程上下文切换

Linux 按照特权级别将进程的运行空间划分为内核空间和用户空间,分别对应下图中 Ring 0Ring 3 的 CPU 特权级别的 。

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

从另一个角度看,一个进程既可以在用户空间也可以在内核空间运行。当一个进程在用户空间运行时,称为该进程的 用户态 ,当它落入内核空间时,称为该进程的 内核态

用户态内核态的转换需要通过系统调用来完成。例如,当我们查看一个文件的内容时,我们需要以下系统调用:

  • open():打开文件
  • read():读取文件的内容
  • write():将文件的内容写入到输出文件(包括标准输出)
  • close():关闭文件

那么在上述系统调用过程中是否会发生 CPU 上下文切换呢?当然是的。

这需要先保存 CPU 寄存器中原来的用户态指令的位置。接下来,为了执行内核态的代码,需要将 CPU 寄存器更新到内核态指令的新位置。最后是跳转到内核态运行内核任务。

那么系统调用结束后,CPU 寄存器需要恢复原来保存的用户状态,然后切换到用户空间继续运行进程。

因此,在一次系统调用的过程中,实际上有两次 CPU 上下文切换。

但需要指出的是,系统调用进程不会涉及进程切换,也不会涉及虚拟内存等系统资源切换。这与我们通常所说的“进程上下文切换”不同。进程上下文切换是指从一个进程切换到另一个进程,而系统调用期间始终运行同一个进程

系统调用过程通常被称为 特权模式切换 ,而不是 上下文切换 。但实际上,在系统调用过程中,CPU 的上下文切换也是不可避免的。

进程上下文切换 vs 系统调用

那么进程上下文切换和系统调用有什么区别呢?首先,进程是由内核管理的,进程切换只能发生在内核态。因此,进程上下文不仅包括 虚拟内存全局变量等用户空间资源,还包括内核栈寄存器等内核空间的状态。

所以进程上下文切换系统调用要多出一步:

在保存当前进程的内核状态和 CPU 寄存器之前,需要保存进程的虚拟内存、栈等;并加载下一个进程的内核状态。

根据 Tsuna 的测试报告,每次上下文切换需要几十纳秒至微秒的 CPU 时间。这个时间是相当可观的,尤其是在大量进程上下文切换的情况下,很容易导致 CPU 花费大量时间来保存和恢复寄存器、内核栈、虚拟内存等资源。这正是我们在上一篇文章中谈到的,一个导致平均负载上升的重要因素。

那么,该进程何时会被调度/切换到在 CPU 上运行?其实有很多场景,下面我为大家总结一下:

  • 当一个进程的 CPU 时间片用完时,它会被系统 挂起 ,并切换到其他等待 CPU 运行的进程。
  • 当系统资源不足(如内存不足)时,直到资源充足之前,进程无法运行。此时进程也会被 挂起 ,系统会调度其他进程运行。
  • 当一个进程通过 sleep 函数自动挂起自己时,自然会被重新调度。
  • 当优先级较高的进程运行时,为了保证高优先级进程的运行,当前进程会被高优先级进程 挂起运行
  • 当发生硬件中断时,CPU 上的进程会被 中断挂起 ,转而执行内核中的中断服务程序。

了解这些场景是非常有必要的,因为一旦上下文切换出现性能问题,它们就是幕后杀手。

线程上下文切换

线程和进程最大的区别在于,线程是任务调度的基本单位,而进程是资源获取的基本单位。

说白了,内核中所谓的任务调度,实际的调度对象是线程;而进程只为线程提供虚拟内存和全局变量等资源。所以,对于线程和进程,我们可以这样理解:

  • 当一个进程只有一个线程时,可以认为一个进程等于一个线程
  • 当一个进程有多个线程时,这些线程共享相同的资源,例如虚拟内存和全局变量。
  • 此外,线程也有自己的私有数据,比如栈和寄存器,在上下文切换时也需要保存。

这样,线程的上下文切换其实可以分为两种情况:

  • 首先,前后两个线程属于不同的进程。此时,由于资源不共享,切换过程与进程上下文切换相同。
  • 其次,前后两个线程属于同一个进程。此时,由于虚拟内存是共享的,所以切换时虚拟内存的资源保持不变,只需要切换线程的私有数据、寄存器等未共享的数据。

显然,同一个进程内的线程切换比切换多个进程消耗的资源要少。这也是多线程替代多进程的优势。

中断上下文切换

除了前面两种上下文切换之外,还有另外一种场景也输出 CPU 上下文切换的,那就是 中断

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

在中断其他进程时,需要保存进程的当前状态,以便中断后进程仍能从原始状态恢复。

与进程上下文不同,中断上下文切换不涉及进程的用户态。因此,即使中断进程中断了处于用户态的进程,也不需要保存和恢复进程的虚拟内存、全局变量等用户态资源。

另外,和进程上下文切换一样,中断上下文切换也会消耗 CPU。过多的切换次数会消耗大量的 CPU 资源,甚至严重降低系统的整体性能。因此,当发现中断过多时,需要注意排查它是否会对您的系统造成严重的性能问题。

小结
  • CPU上下文切换,是保证Linux系统正常工作的核心功能之一,一般情况下不需要我们特别关注。
  • 但过多的上下文切换,会把CPU时间消耗在寄存器,内核栈以及虚拟内存等数据的保存和恢复上,从而缩短进程真正运行的时间,导致系统的整体性能大幅下降。
  • 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题
  • 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈
  • 中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件来分析具体的中断类型。

参考

https://medium.com/geekculture/linux-cpu-context-switch-deep-dive-764bfdae4f01

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    11216

    浏览量

    222859
  • Linux
    +关注

    关注

    88

    文章

    11627

    浏览量

    217893
  • 操作系统
    +关注

    关注

    37

    文章

    7328

    浏览量

    128605
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Linux CPU上下文切换的类型

    在回答这个问题之前,请问,你有没有想过这些“任务”是什么?你可能会说一个任务就是一个进程或者一个线程。是的,进程和线程正是最常见的任务,但除此之外,还有其他类型的任务。
    的头像 发表于 05-17 10:40 4590次阅读

    编写一个任务调度程序,在上下文切换后遇到了一些问题求解

    大家好, 我正在编写一个任务调度程序,在上下文切换后遇到了一些问题。 为下一个任务恢复上下文后: __builtin_tricore_mtcr_by_name(\"pcxi\"
    发表于 05-22 07:50

    BT堆栈上下文切换

    100ms就会产生一个上下文切换上下文切换每秒似乎有点高。我想我真的不能抱怨10个开关,但是有什么东西吗?在BT协议中真的需要这个吗?不能处理中断驱动吗?(这是BT是可连接的,但既没有连接,也没有
    发表于 12-17 16:30

    多线程如何实现上下文切换

    处理系统中,CPU需要处理所有程序的操作,当用户来回切换它们时,需要记录这些程序执行到哪里。上下文切换就是这样一个过程,他允许CPU记录并恢复各种正在运行程序的状态,使它能够完成
    发表于 08-02 08:21

    上下文切换简介

    处理系统中,CPU需要处理所有程序的操作,当用户来回切换它们时,需要记录这些程序执行到哪里。上下文切换就是这样一个过程,他允许CPU记录并恢复各种正在运行程序的状态,使它能够完成
    发表于 08-06 08:08

    上下文切换的情况发生

    处理系统中,CPU需要处理所有程序的操作,当用户来回切换它们时,需要记录这些程序执行到哪里。上下文切换就是这样一个过程,他允许CPU记录并恢复各种正在运行程序的状态,使它能够完成
    发表于 08-07 08:38

    讨论ARM mbed OS(RTX) 的上下文切换

    来说,本文是一个回顾和总结,如我在《浅谈调度相关的元问题》一文所述,mbed OS 是一个支持分态的内核,其上下文切换实现的套路非常神似 linux,故而对 mbed OS 上下文切换的探讨有一定的推广
    发表于 02-16 14:26

    rt-thread上下文切换函数的意义在哪?

    Cortex-M3内核上下文切换函数rt_hw_context_switch()/ rt_hw_context_switch_interrupt()中有个判断rt_thread_switch_interrupt_flag的地方,不知道意义在哪?
    发表于 03-10 11:28

    中断中的上下文切换详解

    ();  /* 发起一次在中断中的上下文切换 */  cpu_irq_context_switch();  }  tos_knl_irq_enter接口(进入ISR时调用)将一个标识中断嵌套次数的变量
    发表于 03-23 17:18

    CPU上下文切换的详细资料讲解

    当UCOS-III转向执行另一项新任务的时候,他保存了当前任务的CPU寄存器到堆栈,并从新任务的堆栈CPU寄存器载入CPU,这个过程叫做上下文切换
    发表于 08-16 17:31 2次下载
    <b class='flag-5'>CPU</b><b class='flag-5'>上下文切换</b>的详细资料讲解

    Linux CPU上下文切换

    在回答这个问题之前,请问,你有没有想过这些“任务”是什么?你可能会说一个任务就是一个进程或者一个线程。是的,进程和线程正是最常见的任务,但除此之外,还有其他类型的任务。
    的头像 发表于 05-05 11:46 2194次阅读

    如何分析Linux CPU上下文切换问题

    在我的上一篇文章:《探讨 Linux CPU上下文切换》中,我谈到了 CPU 上下文切换的工作原理。快速回顾一下,
    的头像 发表于 05-05 20:11 2623次阅读

    详细解读Linux CPU上下文切换过程

    我们都知道 Linux 是一个多任务操作系统,它支持的任务同时运行的数量远远大于 CPU 的数量。当然,这些任务实际上并不是同时运行的(Single CPU),而是因为系统在短时间内将 CPU
    的头像 发表于 02-09 15:30 1722次阅读

    Linux技术:什么是cpu上下文切换

    过多的上下文切换会消耗 CPU 的时间来保存和恢复寄存器、程序计数器、内核栈和虚拟内存等数据,从而导致系统性能显着下降。 既然上下文切换对系统性能的影响如此之大,那么我们如何检查它呢?好了,你可以使用 vmstat 工具来查询你
    发表于 09-01 09:31 1024次阅读
    <b class='flag-5'>Linux</b>技术:什么是<b class='flag-5'>cpu</b><b class='flag-5'>上下文切换</b>

    FreeRTOS系列技术文章:上下文切换

    嵌入式实时操作系统(RTOS)中的上下文切换是指保存和恢复任务的状态,以使调度程序能够切换到另一个任务,从而促进多任务处理。
    的头像 发表于 11-21 15:48 2032次阅读