最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

linux 性能自我学习 ———— cpu 切换带来的性能损耗 [二] 世界热点

来源:博客园

前言

我们知道现在操作系统,都是多进程和多线程,那么会有一个操作系统帮助我们去切换进程和线程,这个是要消耗cpu资源的,那么就来了解一下cpu资源消耗情况。


(资料图)

正文

一般是下面几个场景切换:

  1. 进程上下文切换

  2. 线程上下文切换

  3. 中断上下文切换

在了解进程切换的时候,需要了解另外一个东西,进程的运行环境,进程的运行环境分为内核空间和用户空间。

linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分布对应着上图中的,cpu 特权等级ring0 和 ring3。

进程既可以在用户态空间运行,又可以在内核空间中运行,进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。

举个例子,我们需要进行读取文件。

  1. 首先需要调用open 打开文件

  2. 然后调用read 读取文件内容

  3. 并调用write 将内容写到标志输出

  4. 然后close。

那么这个时候cpu的上下文切换是怎么样的呢?

cpu 寄存器里原来用户态的指令位置(寄存器),先保存起来。为了执行内核态代码,cpu 寄存器需要更新为内核态指令的新位置。然后就跑到了内核态执行内核任务了。

而系统调用后,cpu 寄存器需要恢复到原来保存的用户态,然后再切换到用户空间,继续运行进程。

一次系统调用,那么需要两次cpu切换。

系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程,这和进程切换不一致。

也就是说系统调用是同一个进程,发生了cpu 上下文切换(也叫特权模式切换),而进程切换,是进程进行了切换。

那么进程的上下文切换是怎么样的呢?

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

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

这些现在不需要过于了解,在我后面介绍操作系统系列的时候,会详细描述。

只需要知道其复杂高于系统调用即可,其步骤多了保存用户空间资源的描述等。

那么讲完了进程的上下文切换,那么讲一下线程的上下文切换。

我们知道线程才是cpu 运行的最小单位,其实进程切换就是两个线程来自不同的进程,那么两个线程来自同一进程呢?这时候的cpu 操作是怎么样的呢?

有一个很关键的知识需要了解: 线程是调度的基本单位,而进程则是资源拥有的基本单位。说白了,内核的任务调度的对象是线程;而进程提供给线程虚拟内存,全局变量等资源。

这个时候就明白了,如果线程来自同一个进程,那么就不需要切换虚拟内存,只需要切换线程的私有数据、寄存器等不共享的数据。

那么还有一类场景是中断上下文切换。

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

而在打断其他进程时,就需要将进程状态保存下来,这样在中断结束后,进程依然可以从原来的状态恢复。

跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以即便中断过程打断一个正处于用户态的进程,也不需要保留和恢复进程的虚拟内存、全局变量等用户态资源。

中断上下文,其实只包含内核态中断服务执行必须的状体,包括cpu 寄存器、内核堆栈、硬件中断参数等。

对同一个cpu来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。

同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序短小精悍,以便可能快的执行结束。

另外,跟进程上下文切换一样,中断上下文切换也需要消耗cpu,切换次数过多也会导致消耗大量的cpu,甚至英雄降低系统的整体性能。

所以,你发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能影响。

实验

我们知道除了线程需要调用cpu外,上下文还可能导致cpu高,那么怎么确定是不是上下文切换导致cpu高呢?

那么我们怎么来定位呢?

  1. cs (context switch) 每秒上下文切换的次数

  2. in (interrupt) 则是每秒中断的次数

  3. r (running or runnable) 是就绪队列的长度,也就是正在运行和等待cpu的进程数。

  4. b (blocked) 则是处于不可中断睡眠的进程数。

上图中可以看到cs 上下文切换了大概1.4k左右,in 中断大概接近 1k,r 是0, b 是0.

那么如何我们想知道到底是哪个进程中断次数比较多呢?

cswch 表示每秒资源上下文切换的次数 (voluntary context switchs)

另外一个是nvcswch (none voluntary context switchs) 的次数

那么什么是自愿,什么是非自愿呢?

自愿救赎指系统无法获取所需资源,导致上下文切换。比如i/o、内存等系统资源不足时,就会发生资源上下文切换。

而非自愿切换,则是进程由于时间片等原因,被系统强制调度进而发生的上下文切换。比如大量进程都在争抢cpu时,就容易发生非资源上下文切换。

那么上下文切换多次次数算是正常呢?

使用sysbench 模拟线程直接的切换:

sysbench --thread=10 --max-time=300 threads run

然后vmstat 进行切换。

可以看到 cs 非常高,in 相对少,说明线程或者进程直接的切换,而不是系统中断发生的。

r 列非常高,远超cpu 内核2个。

然后us 和 sy,分别是33 和67,说明内核占用比较大。

虽然in 比较少,但是上升也很快,说明系统中断也是有一部分。

那么到底是哪个进程导致的呢?

通过:

pidstat -w -u 1

可以看到sysbench cpu 190%。

那么是sysbench 的问题。

那么问题就来了,这里不管自愿还是非自愿的上下文切换次数,远远达不到我们看到的十几万次数。

这是为什么呢? 因为这是进程的切换次数,如果这个进程一直捕获的cpu,那么哪有什么机会去获得进程切换的机会?

那么需要这样查看:

pidstat -wt 1

那么现在上下文切换的次数找到了,那么看下系统中断的原因。

查看cpu 中断的原因:

watch -d cat /proc/interrupts

可以看到res 变化很大,res 是重调度中断,这个中断类型表示,唤醒空闲状态cpu来调度新的任务运行。

调度器用来分散任务到不同cpu的机制,通常也被称为处理器间中断。

所以中断升高还是因为任务的调度问题,跟前面一致。

那么问题来了,多少cpu 上下文切换算是正常呢? 一般是1w以内。

  1. 自愿切换变多了,说明进程在等待资源,那么是io问题

  2. 非自愿切换变多了,那么就是进程被强制调度,也就是在争抢cpu,说明cpu到达瓶颈了。

  3. 中断次数变多了,说明cpu被中断处理程序占用,还需要通过查看/proc/interrupts 文件查看。

后面两节实战一些例子。

关键词: