1.什么是CPU上下文切换?

linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行,当然这些任务实际上并不是真的同时在运行,而是因为系统在很短的时间内,将CPU轮流分配给它们,造成多任务同时运行的错觉

而在每个任务运行前,CPU都需要知道任务从哪里加载,又从哪里开始运行,也就是说需要系统事先帮它设置好CPU寄存器和程序计数器。

CPU寄存器,是CPU内置的容量小,但是速度极快的内存。而程序计数器,则是用来存储CPU正在执行的指令位置,或者即将执行的下一条指令位置。它们都是CPU在运行任何任务前,必须依赖的环境,因此也被叫做CPU上下文

CPU的上下文切换就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

2.上下文切换的类型?(按照任务不同区分)

(1).进程上下文切换(不同进程之间上下文切换)

(2).线程上下文切换,包括同一个进程下线程上下文切换,不同进程下线程上下文切换

(3).中断上下文切换,即中断程序导致的上下文切换

(4).自愿上下文切换(cswch),是指进程无法获取所需资源,导致的上下文切换

(5).非自愿上下文切换(nvcswch),是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换,比如大量进程都在争抢CPU时,就容易发生非自愿上下文切换

3.Linux中如何查看上下文切换?

vmstat中cs, 表示每秒上下文切换的次数

pidstat(pidstat -w 5),查看每个进程的上下文切换情况,cswch表示每秒自愿上下文切换次数,nvcswch表示每秒非自愿上下文切换的次数

4.上下文切换的场景:

(1).进程上下文切换场景:

1.为了保证所有进程得到公平调度,CPU时间被划分成一段段的时间片,这些时间片再被轮流分配给各个进程,这样,当某个进程的时间片耗尽时,就会被系统挂起,切换到其他正在等待CPU的进程运行(即进程由于时间片已到,导致的进程上下文切换)

2.进程的系统资源不足(比如内存不足时),要等到资源满足后才可以运行,这个时候进程会被挂起,并由系统调度其他进程运行

3.进程通过睡眠函数sleep将自己主动挂起,自然也会重新调度

4.当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行。

5.发生硬中断时,CPU上的进程会被中断挂起,转而执行内核中的中断服务程序

进程上下文切换次数较多的情况下,很容易导致CPU将大量时间耗费在寄存器,内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。这也是导致平均负载升高的一个重要因素

(2).线程上下文切换:

线程与进程的最大区别在于,线程是调度的基本单位,而进程则是资源拥有的基本单位。所谓内核中的任务调度,调度对象是线程,而不是进程,进程只是给线程提供了虚拟内存,全局变量等资源。对于进程和线程可以

这么理解:

1.当进程只有一个线程时,可以认为进程就等于线程

2.当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的。

3.线程也有自己的私有数据,比如栈和寄存器,这些在上下文切换时也是需要保存的。

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

1.前后两个线程属于不同进程,此时,因为资源不共享,所以切换过程就跟进程上下文切换一样

2.前后两个线程属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保存不动,只需要切换线程的私有数据,寄存器等不共享数据

虽然同为上下文切换,但同进程内的上下文切换,要比多进程间的切换消耗更少的资源,而这也是多线程代替多进程的一个优势。

5.上下文切换升高导致的性能问题(案例场景):

1.准备工作:安装sysbench,准备linux环境,开启3个终端,切换root用户运行

2.操作步骤:

1.在第一个终端运行sysbench,模拟多线程调度的瓶颈:

# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题

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

    2.在第二个终端运行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

从vmstat的输出可以发现,cs列的上下文切换次数上升到139万,同时,注意观察其他几个指标:

(1).R列,就绪队列的长度已经到了8,远远超过CPU个数,所以肯定会有大量的CPU竞争

(2).us和sy,这两列的CPU使用率加起来上升到了100%,其中系统CPU使用率,也就是sy列高达84%,说明CPU主要被内核占用

(3).in列:中断次数也上升到了1万左右,说明中断处理也是个潜在的问题

综合这几个指标,可以知道,系统的就绪队列过长,也就是正在运行和等待CPU的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统CPU使用率升高。

那么,到底是什么进程导致了这些问题呢?

3.继续分析,在第三个终端再用pidstat来看一下,CPU和进程上下文切换的情况:  

# 每隔 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

从pidstat的输出可以发现,CPU使用率升高果然是sysbench导致的,它的CPU使用率高达100%,但上下文切换则来自其他进程。

pidstat输出的上下文切换次数,加起来也就几百,比vmstat的139W明显小了太多。

通过运行man pidstat,发现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
   ...

从这次pidstat的输出中,虽然sysbench进程的上下文切换次数不多,但是它的子进程上下文切换次数却很多。看来,上下文切换罪魁祸首,还是过多的sysbench线程。

4.接下来,继续分析中断次数上升的根源,既然是中断,我们都知道,它只发生在内核态,而pidstat只是一个进程的性能分析工具,并不能提供任何关于中断的信息,怎样才能知道中断发生的类型呢?

从/proc/interrupts这个只读文件读取,/proc实际上是Linux的一个虚拟文件系统,用于内核空间与用户空间之间的通信。/proc/interrupts就是这种通信机制的一部分,提供了一个只读的中断使用情况

在第三个终端,运行下面的命令,查看中断的变化情况:

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

观察一段时间,发现变化速度最快的是重调度中断,这个中断类型表示,唤醒空闲状态的CPU来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同CPU的机制,通常也被称为

处理器间中断。所以这里的中断升高还是因为多任务的调度问题,跟前面的上下文切换次数的分析结果是一致的。

这次通过一个sysbench的案例,讲解了上下文切换问题的分析思路,碰到上下文切换次数过多的问题时,可以借助vmstat,pidstat和/proc/interrupts等工具,来辅助排查性能问题的根源。

总结:

上下文切换指标:

(1).上下文切换次数取决于系统本身的CPU性能,如果系统的上下文切换次数比较稳定,那么从数百到1万以内都是正常的

(2).当上下文切换次数超过1万次,或者切换次数出现数量级增长时,就很可能已经出现了性能问题

同一个进程下线程上下文切换,因为共享虚拟内存,切换过程中,虚拟内存这些资源保持不变,只需要切换线程的私有数据,寄存器等不共享的数据。(多线程代替多进程)

自愿上下文切换变多了,说明进程都在等待资源,有可能发生IO等其他问题

非自愿上下文切换变多了,说明进程都在被强制调度,都在争抢CPU,说明CPU的确成了瓶颈

中断上下文切换变多了,说明CPU被中断处理程序占用,需要通过查看 /proc/interrupts文件分析具体的中断类型

关于linux系统CPU篇--->上下文切换的更多相关文章

  1. 关于linux系统CPU篇--->不容易发现的占用CPU较高进程

    1.系统的CPU使用率,不仅包括进程用户态和内核态的运行,还包括中断处理,等待IO以及内核线程等等.所以,当你发现系统的CPU使用率很高的时候,不一定能找到相对应的高CPU使用率的进程 2.案例分析, ...

  2. 关于linux系统CPU篇--->CPU使用率升高

    1.CPU使用率为单位时间内CPU使用情况的统计,以百分比的方式展示. LINUX作为一个多任务操作系统,将每个CPU的时间划分为很短的时间片,再通过调度器轮流分配给各个任务使用,因此造成多任务同时运 ...

  3. 关于linux系统CPU篇--->平均负载

    1.什么是平均负载?(load average) 平均负载是指单位时间内平均活跃进程数,包括可运行状态的进程数,以及不可中断状态的进程(如等待IO,等待硬件设备响应) 2.如何查看平均负载? 使用to ...

  4. Linux系统cpu 100%修复案例

    Linux系统cpu 100%修复案例 ​阿里云技术支持团队:完颜镇江 案例背景: Linux主机连续三天CPU% 处理思路: 1.  登录服务器查看/var/log/messages+/var/lo ...

  5. linux系统CPU,内存,磁盘,网络流量监控脚本

    前序 1,#cat /proc/stat/ 信息包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累积到当前时刻 2,#vmstat –s 或者#vmstat 虚拟内存统计 3, #cat ...

  6. Linux系统CPU相关信息查询

    Linux系统CPU相关信息查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.lscpu常用参数介绍 1>.查看帮助信息 [root@node105 ~]# lscpu ...

  7. C/C++获取Linux系统CPU和内存及硬盘使用情况

    需求分析: 不使用Top  df  free 等命令,利用C/C++获取Linux系统CPU和内存及硬盘使用情况 实现: //通过获取/proc/stat (CPU)和/proc/meminfo(内存 ...

  8. Java获取Linux系统cpu使用率

    原文:http://www.open-open.com/code/view/1426152165201 import java.io.BufferedReader; import java.io.Fi ...

  9. linux系统cpu和内存占用率

    1.top 使用权限:所有使用者 使用方式:top [-] [d delay] [q] [c] [S] [s] [i] [n] [b] 说明:即时显示process的动态 d :改变显示的更新速度,或 ...

随机推荐

  1. JavaScript学习day1

    JavaScript 特点: javascript 是一种脚本语言,它的解释器被称为javascript引擎,JavaScript被发明用于在HTML网页上使用,给HTML 网页增加动态功能 由于ja ...

  2. 一次Spring Bean初始化顺序问题排查记录

    最近在使用Springboot的时候需要通过静态的方法获取到Spring容器托管的bean对象,参照一些博文里写的,新建了个类,并实现ApplicationContextAware接口.代码大致如下: ...

  3. css学习_css布局案例

    1.中间栏先加载  !!!(若不是这个条件的话  ,那可以用  calc 或者flex布局来实现  中间栏自适应,左右栏定宽) 2.中间栏自适应   width:100% 3.左右栏固定宽 左中右  ...

  4. Django搭建网站笔记

    参考文档 https://www.cnblogs.com/yoyoketang/p/10195102.html https://www.cnblogs.com/yoyoketang/p/1022094 ...

  5. java-方法重载、参数传递、

    1.Java的方法重载overload:同一个类内,可以有多个同名的方法,只要参数不同即可(包括参数类型和个数.多类型顺序) 2.基本类型(8种:byte\short\int\long\double\ ...

  6. char和QChar(Unicode的编码与内存里的值还不是一回事)

    char类型是c/c++中内置的类型,描述了1个字节的内存信息的解析.比如: char gemfield=’g’;那么在由gemfield标记的这块内存的大小就是1个字节,信息就是01100111,8 ...

  7. 监听器 Listener

    监听器:监听某个对象状态的变化 被监听的对象:request.session.servletContext 监听对象的创建和销毁/对象属性的变化 ServletContext HttpSession ...

  8. P1368 工艺 SA/最小表示法

    正解:SA/最小表示法 解题报告: 传送门! 听说正解是最小表示法,,,O(n)然后常数还挺小的,,, 但是我不会QAQ! 所以先写下SA的做法趴,,,等get了最小表示法再来写正解QAQ 就这种题算 ...

  9. python生成数据后,快速导入数据库

    1.使用python生成数据库文件内容 # coding=utf-8import randomimport time def create_user():    start = time.time() ...

  10. Acrobat Pro DC 2019 mac中文版(pdf编辑器)

    为大家准备了最新版本的Adobe Acrobat Pro DC 2019 for Mac,这是Adobe官方推出的pdf编辑器,acrobat pro dc 2019破解版可以轻松将扫描件.图像.网页 ...