理解linux的CPU上下文切换

简介: 理解linux的CPU上下文切换

前言

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性能优化实战
相关文章
|
6月前
|
运维 Linux 虚拟化
Linux 查看 CPU 使用情况
在 Linux 系统中,查看 CPU 使用情况是性能分析和故障排查的重要环节。查看 CPU 使用情况,使用 top 命令或者 htop 命令来查看。
|
6月前
|
Ubuntu Linux 应用服务中间件
Linux使用cpulimit对CPU使用率进行限制
cpulimit是一款简单易用的CPU使用率限制工具,支持对特定程序或整个CPU使用率进行限制。可通过源安装(如`yum`或`apt-get`)或编译安装获取。使用时,可针对程序名、进程号或绝对路径设置CPU占用上限(如`cpulimit -e xmrig -l 60 -b`)。ROOT用户可限制所有进程,普通用户仅限于权限范围内进程。注意,CPU百分比基于实际核心数(单核100%,双核200%,依此类推)。
402 7
|
6月前
|
存储 缓存 Linux
Linux系统中如何查看CPU信息
本文介绍了查看CPU核心信息的方法,包括使用`lscpu`命令和读取`/proc/cpuinfo`文件。`lscpu`能快速提供逻辑CPU数量、物理核心数、插槽数等基本信息;而`/proc/cpuinfo`则包含更详细的配置数据,如核心ID和处理器编号。此外,还介绍了如何通过`lscpu`和`dmidecode`命令获取CPU型号、制造商及序列号,并解释了CPU频率与缓存大小的相关信息。最后,详细解析了`lscpu`命令输出的各项参数含义,帮助用户更好地理解CPU的具体配置。
720 8
|
8月前
|
缓存 安全 Linux
Linux系统查看操作系统版本信息、CPU信息、模块信息
在Linux系统中,常用命令可帮助用户查看操作系统版本、CPU信息和模块信息
1430 23
|
缓存 监控 Linux
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
|
10月前
|
缓存 监控 Linux
|
10月前
|
缓存 Linux
揭秘Linux内核:探索CPU拓扑结构
【10月更文挑战第26天】
225 1
|
10月前
|
缓存 运维 Linux
深入探索Linux内核:CPU拓扑结构探测
【10月更文挑战第18天】在现代计算机系统中,CPU的拓扑结构对性能优化和资源管理至关重要。了解CPU的核心、线程、NUMA节点等信息,可以帮助开发者和系统管理员更好地调优应用程序和系统配置。本文将深入探讨如何在Linux内核中探测CPU拓扑结构,介绍相关工具和方法。
192 0
|
缓存 Linux 调度
Linux服务器如何查看CPU占用率、内存占用、带宽占用
Linux服务器如何查看CPU占用率、内存占用、带宽占用
4295 0
在Linux中,如何找出占用CPU或内存最多的进程?
在Linux中,如何找出占用CPU或内存最多的进程?