前言

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. 聊一聊redis十种数据类型及底层原理

    概述 Redis 是一个开源的高性能键值数据库,它支持多种数据类型,可以满足不同的业务需求.本文将介绍 Redis 的10种数据类型,分别是 string(字符串) hash(哈希) list(列表) ...

  2. 2021-11-11:打乱数组。给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。实现 Solution class:Solutio(int[] nums) 使用整数数组 nums

    2021-11-11:打乱数组.给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组.实现 Solution class:Solutio(int[] nums) 使用整数数组 nums ...

  3. 2021-09-17:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。进阶:你能尝试使用一趟扫描实现吗?

    2021-09-17:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点.进阶:你能尝试使用一趟扫描实现吗? 福大大 答案2021-09-17: 双指针. 1.创建虚拟头节点preHea ...

  4. 一天吃透SpringCloud面试八股文

    1.什么是Spring Cloud ? Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序,提供与外部系统的集成.Spring cloud Tas ...

  5. 认识CPU底层原理(1)——MOSFET

    本文为B站UP主硬件茶谈制作的系列科普<[硬件科普]带你认识CPU>系列的学习笔记,仅作个人学习记录使用,如有侵权,请联系博主删除 近年来,由于国内外各种因素影响,半导体行业逐渐被推向风口 ...

  6. js 正则校验非法字符

    今日使用 vue + element 对数据录入进行非法字符校验,到处找了一圈都不是想要的,于是自己按需求写一个 1.内容可以包含 大小写字母,中文和 . ( ) . , : % 2.内容第一位不允许 ...

  7. vue+iview 动态调整Table的列顺序

    需求:因table列太多,且每个部门关注的信息不一样,拖来拖去不方便观看,客户想让Table列可以拖动,且可以保存顺序. 但是搞动态拖动太难了,我不会,于是改为操作columns数据 思路: < ...

  8. 代码随想录算法训练营Day5 数组、链表复习

    数组部分 数组最重要的思维方式是双指针的使用. 快慢指针 在进行元素移除和元素操作时会使用两个for循环嵌套,此时时间复杂度为O(n²).在for循环中通过双指针(快慢指针)的使用可以使时间复杂度将为 ...

  9. 驱动开发:内核PE结构VA与FOA转换

    本章将继续探索内核中解析PE文件的相关内容,PE文件中FOA与VA,RVA之间的转换也是很重要的,所谓的FOA是文件中的地址,VA则是内存装入后的虚拟地址,RVA是内存基址与当前地址的相对偏移,本章还 ...

  10. Vue——计算属性、监听属性、Vue生命周期、组件介绍和使用、组件间通信、ref属性

    计算属性 // 1 计算属性是基于他们的依赖变量进行缓存的 // 2 计算属性只有在它的相关依赖变量发生改变时才会重新求值,否则不会变(函数只要页面变化,就会重新运算) // 3 计算属性就像pyth ...