linux 性能自我学习 ———— cpu 切换带来的性能损耗 [二]
Posted 程序员其实就是一个写文档的工作,代码只是文档的一部分,一切皆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux 性能自我学习 ———— cpu 切换带来的性能损耗 [二]相关的知识,希望对你有一定的参考价值。
前言
我们知道现在操作系统,都是多进程和多线程,那么会有一个操作系统帮助我们去切换进程和线程,这个是要消耗cpu资源的,那么就来了解一下cpu资源消耗情况。
正文
一般是下面几个场景切换:
-
进程上下文切换
-
线程上下文切换
-
中断上下文切换
在了解进程切换的时候,需要了解另外一个东西,进程的运行环境,进程的运行环境分为内核空间和用户空间。
linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分布对应着上图中的,cpu 特权等级ring0 和 ring3。
进程既可以在用户态空间运行,又可以在内核空间中运行,进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。
举个例子,我们需要进行读取文件。
-
首先需要调用open 打开文件
-
然后调用read 读取文件内容
-
并调用write 将内容写到标志输出
-
然后close。
那么这个时候cpu的上下文切换是怎么样的呢?
cpu 寄存器里原来用户态的指令位置(寄存器),先保存起来。为了执行内核态代码,cpu 寄存器需要更新为内核态指令的新位置。然后就跑到了内核态执行内核任务了。
而系统调用后,cpu 寄存器需要恢复到原来保存的用户态,然后再切换到用户空间,继续运行进程。
一次系统调用,那么需要两次cpu切换。
系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程,这和进程切换不一致。
也就是说系统调用是同一个进程,发生了cpu 上下文切换(也叫特权模式切换),而进程切换,是进程进行了切换。
那么进程的上下文切换是怎么样的呢?
首先进程是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间资源,还包含了内核堆栈、寄存器等内核空间的状态。
因此进程的上下文就比系统调用多了一步,在保存当前进程的内核状态和cpu寄存器之前,需要把该进程的虚拟内存,栈等保留下来;而加载下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。
这些现在不需要过于了解,在我后面介绍操作系统系列的时候,会详细描述。
只需要知道其复杂高于系统调用即可,其步骤多了保存用户空间资源的描述等。
那么讲完了进程的上下文切换,那么讲一下线程的上下文切换。
我们知道线程才是cpu 运行的最小单位,其实进程切换就是两个线程来自不同的进程,那么两个线程来自同一进程呢?这时候的cpu 操作是怎么样的呢?
有一个很关键的知识需要了解: 线程是调度的基本单位,而进程则是资源拥有的基本单位。说白了,内核的任务调度的对象是线程;而进程提供给线程虚拟内存,全局变量等资源。
这个时候就明白了,如果线程来自同一个进程,那么就不需要切换虚拟内存,只需要切换线程的私有数据、寄存器等不共享的数据。
那么还有一类场景是中断上下文切换。
为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备时间。
而在打断其他进程时,就需要将进程状态保存下来,这样在中断结束后,进程依然可以从原来的状态恢复。
跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以即便中断过程打断一个正处于用户态的进程,也不需要保留和恢复进程的虚拟内存、全局变量等用户态资源。
中断上下文,其实只包含内核态中断服务执行必须的状体,包括cpu 寄存器、内核堆栈、硬件中断参数等。
对同一个cpu来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。
同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序短小精悍,以便可能快的执行结束。
另外,跟进程上下文切换一样,中断上下文切换也需要消耗cpu,切换次数过多也会导致消耗大量的cpu,甚至英雄降低系统的整体性能。
所以,你发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能影响。
实验
我们知道除了线程需要调用cpu外,上下文还可能导致cpu高,那么怎么确定是不是上下文切换导致cpu高呢?
那么我们怎么来定位呢?
-
cs (context switch) 每秒上下文切换的次数
-
in (interrupt) 则是每秒中断的次数
-
r (running or runnable) 是就绪队列的长度,也就是正在运行和等待cpu的进程数。
-
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以内。
-
自愿切换变多了,说明进程在等待资源,那么是io问题
-
非自愿切换变多了,那么就是进程被强制调度,也就是在争抢cpu,说明cpu到达瓶颈了。
-
中断次数变多了,说明cpu被中断处理程序占用,还需要通过查看/proc/interrupts 文件查看。
结
后面两节实战一些例子。
Linux性能学习(1.3):CPU_CPU上下文切换
文章目录
参考资料:
1.
https://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html
1 简介
在Linux下,如果我们使用ps指令可以看到有很多进程在同时运行,但是实际上并不是同一时刻运行的,单核CPU在某一时刻只会运行一个任务,而系统则会通过调度算法(时间片轮转、中断优先、高优先级优先等算法)将不同的任务给到CPU运行,从而造成可以同时执行很多进程的假象。
在系统将某一个任务给到CPU运行时候,CPU则需要将当前正在执行的指令进行存储,以便下次执行这个任务,以及需要知道下一个任务的指令的位置,以便加载进来运行,而程序计数器则是用于存放指令所在地址的地方;寄存器是加载速度比缓存更快的内存,用于存储CPU需要的参与运算的数据和运算结果;上面的程序计数器和寄存器组合起来就是一个任务的上下文,即CPU的上下文。
PS:程序计数器也是属于CPU寄存器中的一类。
上下文切换则是指CPU在运行新任务前,将当前任务的数据以及指令等信息保存起来,即这个任务的上下文保存起来到系统内核中,然后加载新任务的上下文数据到程序计数器和寄存器中,然后跳转到程序计数器指定的新位置,开始运行任务。
CPU保存旧任务的上下文,以及加载新任务的上下文,即上下文切换是需要时间的,所以频繁的上下文切换也会导致CPU耗费时间在数据保存以及数据读取上。
根据任务的不同,上下文切换分为进程上下文切换、线程上下文切换以及中断上下文切换。
2 进程上下文切换
在以下场景中,会触发进程上下文切换:
进程正常执行完毕;
进程分配的CPU时间片使用完了,需要调度另外的任务;
使用sleep等休眠函数,则会被挂起;
系统资源不足时,进程被挂起,要等待系统资源满足,进程则再次运行;
高优先级的进程需要运行;
硬件中断发送,优先级最高,需要运行。
3 线程上下文切换
线程是系统调度的基本单位,进程是资源拥有的基本单位,为线程提供虚拟内存,全局变量等资源。
如果一个进程只有一个线程,那么这个进程就相当于线程;如果一个进程有多个线程,那么这些线程就会共享这个进程的虚拟内存、全局变量等资源,这些资源因为是共享的,如果发生进程内的线程切换,则不会切换这些资源,但是线程也会有自己一些数据,发生进程内的线程切换,这些数据是需要保存和切换的。
因此,如果发生切换的线程如果属于不同的进程,则上下文切换相当于进程的上下文切换;如果发生切换的线程如果属于相同的进程,共享资源不切换,值切换线程独有的数据。
4 中断上下文切换
硬件中断的优先级高于普通进程的优先级,因此当硬件中断发生,CPU会优先执行中断事件,从而发生中断上下文切换。
中断上下文切换不涉及到进程的用户态,因此不需要保存和恢复用户态资源(虚拟内存、全局变量等资源),而是涉及到内核态。因此性能消耗上会比进程上下文切换低。
以上是关于linux 性能自我学习 ———— cpu 切换带来的性能损耗 [二]的主要内容,如果未能解决你的问题,请参考以下文章