如何理解Linux的CPU上下文切换

发布时间:2021-11-01 10:36:20 作者:柒染
来源:亿速云 阅读:94

今天就跟大家聊聊有关如何理解Linux的CPU上下文切换,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

如何理解Linux的上下文切换

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

如何理解Linux的CPU上下文切换

进程上下文切换

1. 用户空间与内核空间

Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着 CPU 特权等级的 Ring 0 和 Ring 3。

2. 系统调用

从用户态到内核态的转变,需要通过系统调用来完成。比如查看文件时,需要执行多次系统调用:open、read、write、close等。系统调用的过程如下:

但系统调用的过程中并不会涉及虚拟内存等进程用户态的资源,也不会切换进程,这和平时说的进程上下文切换是不一样的:

因此,系统调用的过程通常称为特权模式切换,而不是上下文切换。

3. 进程上下文切换

进程是由内核来管理和调度的,进程的切换只能发生在内核态,因此进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。

因此进程的上下文切换就比系统调用时多了一步:在保存当前进程的内核状态和 CPU  寄存器之前,需先把该进程的虚拟内存、栈等保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。

保存上下文和恢复上下文的过程并不是免费的,需要内核在 CPU 上运行才能完成。据测试,每次上下文切换都需要几十纳秒到数微妙的 CPU  时间。特别是在进程上下文切换次数较多的情况下,很容易导致 CPU  将大量时间消耗在寄存器、内核栈、虚拟内存等资源的保存和恢复上,从而大大缩短了真正运行进程的时间。

Linux 通过 TLB 来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB  也需要刷新,内存的访问也会随之变慢。特别是多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其它处理器的进程。

4. 进程上下文何时切换

Linux 为每个 CPU 维护了一个就绪队列,将活跃进程按照优先级和等待 CPU 的时间排序,然后选择最需要 CPU 的进程,也就是优先级最高和等待  CPU 时间最长的进程来运行。那么,进程在什么时候才会被调度到 CPU 上运行呢?

线程上下文切换

线程与进程最大的区别在于,线程是操作系统调度的最小单位,而进程是操作系统分配资源的最小单位。所谓内核调度,实际上的调度对象是线程,而进程只是给线程提供了虚拟内存、全局变量等资源。对于线程和进程我们可以这么理解:

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

可以发现同进程内的线程切换,要比多进程间的切换消耗更少的资源,这也正是多线程代替多进程的一个优势。

中断上下文切换

为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其它进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。

概念小结

总结一下,不管是哪种场景导致的上下文切换,你都应该知道:

如何查看系统的上下文切换

我们可以通过 vmstat 工具来查看系统的上下文切换情况。vmstat 主要用来分析系统内存使用情况,也常用来分析 CPU  上下文切换和中断的次数。

# 每隔 5 秒输出 1 组数据 $ vmstat 5 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----  r  b  swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st  0  0    0 7005360  91564 818900    0    0     0     0   25   33  0  0 100  0  0

我们需要重点关注下列四项内容:

想要查看每个进程的详细情况,需要使用 pidstat,给它加上 -w 选项,就可以查看每个进程上下文切换的情况。

# 每隔 5 秒输出 1 组数据 $ pidstat -w 5 Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU) 08:18:26      UID       PID   cswch/s nvcswch/s  Command 08:18:31        0         1      0.20      0.00  systemd 08:18:31        0         8      5.40      0.00  rcu_sched

上述结果有两列是我们重点关注的对象,一个是 cswch,表示每秒自愿上下文切换的次数;另一个是 nvcswch,表示每秒非自愿上下文切换的次数。

案例分析

1. 准备环境

sysbench  是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况,本次案例把它当作一个异常进程来看,作用是模拟上下文切换过多的问题。

# 预先安装 sysbench $ yum install sysbench -y

2. 操作和分析

首先在第一个终端里运行 sysbench,模拟系统多线程调度的瓶颈:

# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题 $ sysbench --threads=10 --max-time=300 threads run

接着在第二个终端运行 vmstat,观察上下文切换情况:

# 每隔 1 秒输出 1 组数据(需要 Ctrl+C 才结束) $ vmstat 1 procs --------memory-------- ---swap-- -----io---- -system-- ------cpu-----  r  b swpd   free   buff  cache  si so bi bo   in   cs us sy id wa st  6  0  0 6487428 118240 1292772    0   0  0  0 9019 1398830 16 84  0  0  0  8  0  0 6487428 118240 1292772    0   0  0  0 10191 1392312 16 84  0  0  0

可以发现,cs 列的上下文切换次数从之前的 35 上升到了 139 万,观察其他几个指标:

综合分析,由于系统的就绪队列过长,也就是正在运行和等待 CPU 的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统 CPU  的占用率升高。

我们可以使用 pidstat 继续分析到底是哪个进程导致了这些问题?

# 每隔 1 秒输出 1 组数据(需要 Ctrl+C 才结束) # -w 参数表示输出进程切换指标,而 -u 参数则表示输出 CPU 使用指标 $ pidstat -w -u 1 08:06:33      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command 08:06:34        0     10488   30.00  100.00    0.00    0.00  100.00     0  sysbench 08:06:34        0     26326    0.00    1.00    0.00    0.00    1.00     0  kworker/u4:2  08:06:33      UID       PID   cswch/s nvcswch/s  Command 08:06:34        0         8     11.00      0.00  rcu_sched 08:06:34        0        16      1.00      0.00  ksoftirqd/1 08:06:34        0       471      1.00      0.00  hv_balloon 08:06:34        0      1230      1.00      0.00  iscsid 08:06:34        0      4089      1.00      0.00  kworker/1:5 08:06:34        0      4333      1.00      0.00  kworker/0:3 08:06:34        0     10499      1.00    224.00  pidstat 08:06:34        0     26326    236.00      0.00  kworker/u4:2 08:06:34     1000     26784    223.00      0.00  sshd

可以发现,CPU 使用率的升高是 sysbench 导致的,但上下文切换则来自其他进程,包括非自愿上下文切换频率最高的  pidstat,以及自愿上下文切换频率最高的内核线程 kworker 和 sshd。

默认 pidstat 显示进程的指标数据,加上 -t 参数后,才会输出线程的指标

# 每隔 1 秒输出一组数据(需要 Ctrl+C 才结束) # -wt 参数表示输出线程的上下文切换指标 $ pidstat -wt 1 08:14:05      UID      TGID       TID   cswch/s nvcswch/s  Command ... 08:14:05        0     10551         -      6.00      0.00  sysbench 08:14:05        0         -     10551      6.00      0.00  |__sysbench 08:14:05        0         -     10552  18911.00 103740.00  |__sysbench 08:14:05        0         -     10553  18915.00 100955.00  |__sysbench 08:14:05        0         -     10554  18827.00 103954.00  |__sysbench ...

虽然 sysbench 进程的上下文切换次数不多,但它的子线程的上下文切换次数非常多,可以判定上下文切换罪魁祸首的是 sysbench  进程。还没完,记得我们通过 vmstat 看到的中断次数到了 1 万,到底是什么类型的中断上升了呢?

我们可以通过 /proc/interrupts 来读取中断的使用情况,通过运行下面的命令:

# -d 参数表示高亮显示变化的区域 $ watch -d cat /proc/interrupts            CPU0       CPU1 ... RES:    2450431    5279697   Rescheduling interrupts ...

可以发现,变化速度最快的是重调度中断(RES),表示唤醒空闲状态的 CPU 来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务队列到不同  CPU 的机制,通常也被称为处理器间中断。根本原因还是因为过多任务的调度问题,跟前边分析结果是一致的。

每秒上下文切换多少次算正常

这个数值其实取决于系统本身的 CPU  性能。如果系统的上下文切换次数比较稳定,从数百到一万以内,都应该算是正常的。如果当上下文切换次数超过一万次,或者切换次数出现数量级增长时,很可能已经出现了性能问题。

这时,你还需要根据上下文切换的类型,再做具体分析,比方说:

看完上述内容,你们对如何理解Linux的CPU上下文切换有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

推荐阅读:
  1. 如何理解CPU的大小端模式
  2. linux如何查看cpu信息

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux cpu

上一篇:DevOps中阅读源代码的实用技巧有哪些

下一篇:Windows 10中没有文本的空或空白对话框怎么办

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》