前言

linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行。当然,这个同时运行不是真的同时运行,而是系统在很短的时间内轮流分配CPU资源,由于CPU的速度很快,所以给人一种同时运行的错觉。

每个任务运行前,CPU需要知道任务从哪加载、从哪开始运行,也就是需要系统设置好任务的CPU寄存器和程序计数器。这俩是CPU执行任何任务前所必须的依赖环境,因此也被叫做CPU上下文。而CPU上下文切换便是,先把前一个任务的CPU上下文保存起来,然后加载新任务的上下文到CPU寄存器和程序计数器中,最后再跳转到程序计数器所指向的新位置来运行新任务。

根据任务的不同,CPU的上下文切换可以分为几个不同的场景:进程上下文切换、线程上下文切换,以及中断上下文切换。

进程上下文切换

linux进程的运行空间分为内核空间和用户空间。内核空间具有最高权限,可以访问所有资源;用户空间只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入内核,才能访问特权资源。当进程在用户空间运行时,被称为进程的用户态;当进程陷入到内核空间,被称为进程的内核态。

用户态通过系统调用陷入内核态的时候,会发生CPU上下文切换。系统需要先保存用户态的上下文,然后加载内核态代码的上下文,执行完内核态任务后,再进行一次CPU上下文切换,切换回用户态的上下文。因此一次系统调用会发生两次CPU上下文切换。这里需要注意,系统调用过程一直是同一个进程在运行,不是一个进程切换到另一个进程。

进程是由内核管理和调度的,进程的切换只能在内核空间。因此,进程的上下文不仅包括虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。由于进程上下文较多,切换时候不仅包括用户态信息,还包括内核态信息,所以上下文切换时耗费的时间更多。虽然一般只需要纳秒级的时间,但进程上下文切换次数较多的时候,总体耗费的时间就比较可观了。在大量进程上下文切换的情况下,CPU将大量时间耗费在寄存器、内核栈、虚拟内存等资源的保存和恢复上,进而缩短了真正运行进程的时间。

Linux通过TLB(Translation Lookaside Buffer)来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB也需要刷新,内存的访问也会随之变慢。

只有在进程调度的时候,才需要切换进程上下文。linux为每个CPU维护了一个就序队列,将活跃进程(在运行和等待中的进程)按照优先级和等待CPU的时间排序,然后选择最需要CPU的进程,也就是优先级最高和等待时间最长的进程来运行。

触发进程调度的常见场景:

  • 进程的CPU时间片用完,就会被系统挂起,切换到其他进程。
  • 进程所需的系统资源不足时,需要等到资源满足后才可以运行,这时候也会被挂起。
  • 进程通过sleep()函数主动挂起。
  • 有优先级更高的进程需要运行时,当前进程会被挂起。
  • 硬件中断时,进程会被挂起。

线程上下文切换

进程是资源分配的基本单位,线程是调度的基本单位。进程内有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时是不需要修改的。线程也有自己的私有资源,比如栈和寄存器等,这些在上下文切换时也需要保存。

  • 线程上下文切换前后的两个线程如果不属于同一个进程,此时资源不共享,切换过程同进程上下文切换。
  • 切换前后的两个线程若属于同一个进程,共享的虚拟内存等资源保持不动,切换线程的私有资源即可。在这种情况下,切换消耗的资源更少。

中断上下文切换

为了快速响应硬件的时间,中断处理会打断进程的正常调度和执行,转而调用中断处理程序。

中断上下文切换并不涉及进程的用户态,当中断发生在一个正处于用户态的进程时,不需要保存和恢复这个进程的用户态资源。中断上下文值包括内核态中断服务程序执行所必需的状态,包括CPU寄存器、内核堆栈、硬件中断参数等。

查看系统的上下文切换情况

使用vmstat(apt或yum安装sysstat)可查看系统的上下文切换情况

# 每2秒输出一组报告,共1份报告
vmstat 2 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b 交换 空闲 缓冲 缓存 si so bi bo in cs us sy id wa st
1 0 0 2118592 100844 1011392 0 0 211 259 188 249 3 1 96 0 0
  • cs(context switch):每秒上下文切换的次数。此处为249
  • in(interrupt): 每秒中断的次数。此处为188
  • r(running or runnable): 就绪队列的长度,即正在运行和等待CPU的进程数
  • b(blocked): 处于不可中断睡眠状态的进程数

查看每个进程的上下文切换情况

使用pidstat(同样依赖于sysstat)可查看进程的上下文切换情况。

# 每3秒输出一组报告,-w表示输出进程的上下文切换指标,-wt表示输出线程的上下文切换指标
pidstat -w 3 13时53分56秒 UID PID cswch/s nvcswch/s Command
13时53分59秒 0 7 4.95 0.00 kworker/0:1-ata_sff
13时53分59秒 0 13 2.64 0.00 rcu_sched
13时53分59秒 0 14 0.33 0.00 migration/0
13时53分59秒 0 19 0.33 0.00 migration/1
13时53分59秒 0 31 1.98 0.00 kcompactd0
13时53分59秒 0 122 1.32 0.00 kworker/1:1H-kblockd
13时53分59秒 0 247 0.99 0.33 jbd2/dm-0-8
13时53分59秒 116 501 0.66 0.00 avahi-daemon
13时53分59秒 0 505 0.99 0.00 NetworkManager
13时53分59秒 104 541 0.33 0.00 rsyslogd
13时53分59秒 0 549 0.33 0.00 wpa_supplicant
13时53分59秒 0 5102 2.31 0.33 kworker/1:1-events
13时53分59秒 0 5576 1.98 0.00 kworker/u4:0-events_freezable_power_
13时53分59秒 1000 5707 0.33 0.00 pidstat
  • cswch: 每秒自愿上下文切换的次数(资源不足时,进程自愿上下文切换)
  • nvcswch: 每秒非自愿上下文切换的次数(时间片到期等原因,被系统强制调度而发生的上下文切换)

查看系统中断情况

# 持续查看/proc/interrupts, 并高亮变化的地方
watch -d cat /proc/interrupts CPU0 CPU1
0: 29 0 IO-APIC 2-edge timer
1: 602 0 IO-APIC 1-edge i8042
8: 0 0 IO-APIC 8-edge rtc0
9: 0 0 IO-APIC 9-fasteoi acpi
12: 0 366 IO-APIC 12-edge i8042
14: 0 0 IO-APIC 14-edge ata_piix
15: 0 2563 IO-APIC 15-edge ata_piix
18: 0 2 IO-APIC 18-fasteoi vboxvideo
19: 13747 23341 IO-APIC 19-fasteoi enp0s3
20: 8310 0 IO-APIC 20-fasteoi vboxguest
21: 17084 18354 IO-APIC 21-fasteoi ahci[0000:00:0d.0], snd_intel8x0
22: 25 0 IO-APIC 22-fasteoi ohci_hcd:usb1
NMI: 0 0 Non-maskable interrupts
LOC: 309756 154510 Local timer interrupts
SPU: 0 0 Spurious interrupts
PMI: 0 0 Performance monitoring interrupts
IWI: 0 0 IRQ work interrupts
RTR: 0 0 APIC ICR read retries
RES: 95556 93683 Rescheduling interrupts
CAL: 7548 8726 Function call interrupts
TLB: 7126 6564 TLB shootdowns
TRM: 0 0 Thermal event interrupts
THR: 0 0 Threshold APIC interrupts
DFR: 0 0 Deferred Error APIC interrupts
MCE: 0 0 Machine check exceptions
MCP: 9 9 Machine check polls
ERR: 0
MIS: 0
PIN: 0 0 Posted-interrupt notification event
NPI: 0 0 Nested posted-interrupt event
PIW: 0 0 Posted-interrupt wakeup event
  • RES:重调度中断。表示唤醒空闲状态的CPU来调度新的任务运行。

参考

  • 极客时间 - linux性能优化实战

理解linux的CPU上下文切换的更多相关文章

  1. 聊聊Linux中CPU上下文切换

    目录 什么是CPU上下文 CPU上下文切换 上一任务的CPU上下文保存在哪? 进程上下文切换 内核空间和用户空间 top命令查看CPU资源 系统调用 进程上下文切换 和 系统调用的区别? 进程切换的常 ...

  2. 关于linux系统CPU篇--->上下文切换

    1.什么是CPU上下文切换? linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行,当然这些任务实际上并不是真的同时在运行,而是因为系统在很短的时间内,将CPU轮流分配给它们,造成多任 ...

  3. 如何理解CPU上下文切换(二)

    如何理解CPU上下文切换(二) 1.引 你们好,可爱的小伙伴们.^_^ 多个进程竞争CPU就是一个经常被我们忽视的问题. 你们一定很好奇,进程在竞争CPU的时候并没有真正运行,为什么还会导致系统的负载 ...

  4. 性能测试必备知识(5)- 深入理解“CPU 上下文切换”

    做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 前言 上一篇文章中,举例了大量进程等待 CP ...

  5. 深入理解 Linux Cgroup 系列(二):玩转 CPU

    原文链接:深入理解 Linux Cgroup 系列(二):玩转 CPU 上篇文章主要介绍了 cgroup 的一些基本概念,包括其在 CentOS 系统中的默认设置和控制工具,并以 CPU 为例阐述 c ...

  6. Linux性能优化从入门到实战:03 CPU篇:CPU上下文切换

      linux操作系统是将CPU轮流分配给任务,分时执行的.而每次执行任务时,CPU需要知道CPU寄存器(CPU内置的内存)和程序计数器PC(CPU正在执行指令和下一条指令的位置)值,这些值是CPU执 ...

  7. 读书笔记之Linux系统编程与深入理解Linux内核

    前言 本人再看深入理解Linux内核的时候发现比较难懂,看了Linux系统编程一说后,觉得Linux系统编程还是简单易懂些,并且两本书都是讲Linux比较底层的东西,只不过侧重点不同,本文就以Linu ...

  8. 理解Linux系统中的load average

    理解Linux系统中的load average(图文版) 博客分类: Linux linux load nagios  一.什么是load average? linux系统中的Load对当前CPU工作 ...

  9. 《深入理解Linux内核》 读书笔记

    深入理解Linux内核 读书笔记 一.概论 操作系统基本概念 多用户系统 允许多个用户登录系统,不同用户之间的有私有的空间 用户和组 每个用于属于一个组,组的权限和其他人的权限,和拥有者的权限不一样. ...

  10. CPU 上下文切换及案例分析

    什么是CPU 上下文 我们都知道,Linux是一个多任务操作系统,它远支持大于CPU数量的任务同时运行,当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短时间内,将CPU轮流分配给他们,造成 ...

随机推荐

  1. Unity中实现字段/枚举编辑器中显示中文(中文枚举、中文标签)

    在unity开发编辑器相关经常会碰到定义的字段显示在Inspector是中文,枚举也经常碰到显示的是字段定义时候的英文,程序还好,但是如果编辑器交给策划编辑,策划的英文水平不可保证,会很头大,所以还是 ...

  2. #AI 1分钟学会,利用AI制作思维导图 (NewBing&X-Mind )

    思维导图是一种有效的思考和学习工具,它可以帮助你整理和呈现信息,激发你的创造力和记忆力.但是,传统的思维导图软件往往需要你花费大量的时间和精力来设计和绘制,而且难以修改和分享.有没有一种更简单和智能的 ...

  3. 2022-12-30:某天小美进入了一个迷宫探险,根据地图所示,这个迷宫里有无数个房间 序号分别为1、2、3、...入口房间的序号为1 任意序号为正整数x的房间,都与序号 2*x 和 2*x + 1

    2022-12-30:某天小美进入了一个迷宫探险,根据地图所示,这个迷宫里有无数个房间 序号分别为1.2.3.-入口房间的序号为1 任意序号为正整数x的房间,都与序号 2x 和 2x + 1 的房间之 ...

  4. Django-5:前端模板路径设定TEMPLATES DIRS和调用

    前端模板路径设定:'DIRS': [BASE_DIR / 'templates'] TEMPLATES = [ { 'BACKEND': 'django.template.backends.djang ...

  5. 这款全自动自适应工具你用过了吗?autofit.js请求加入你的战场!

    前段时间做了一个自适应的小工具(autofit.js) 经过一段时间的试用,同学们发现了工具存在的一些问题,我自己也发现了一些,这篇文章是针对这些问题撰写的. autofit.js autofit.j ...

  6. ET介绍—— 一切皆实体的设计

    一切皆实体 目前十分流行ECS设计,主要是守望先锋的成功,引爆了这种技术.守望先锋采用了状态帧这种网络技术,客户端会进行预测,预测不准需要进行回滚,由于组件式的设计,回滚可以只回滚某些组件即可.ECS ...

  7. Abp Vnext 动态(静态)API客户端源码解析

    根据以往的经验,通过接口远程调用服务的原理大致如下: 服务端:根据接口定义方法的签名生成路由,并暴露Api. 客户端:根据接口定义方法的签名生成请求,通过HTTPClient调用. 这种经验可以用来理 ...

  8. Error: Cannot find module ‘webpack-cli/bin/config-yargs‘

    今配置一个webpack-dev-server进行服务端渲染时老是不正确 npm run dev 就崩了 起初的配置为 "devDependencies": { "web ...

  9. THM红队基础

    Red Team Fundamentals Learn the core components of a red team engagement, from threat intelligence t ...

  10. 10个 Istio 流量管理 最常用的例子,你知道几个?

    10 个 Istio 流量管理 最常用的例子,强烈建议收藏起来,以备不时之需. 为了方便理解,以Istio官方提供的Bookinfo应用示例为例,引出 Istio 流量管理的常用例子. Bookinf ...