Linux性能分析 – CPU篇
一、性能分析负载均衡的理解
平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数
。包括了正在使用 CPU 的进程,还包括等待 CPU 和等待I/O 的进程。
不可中断状态实际上是系统对进程和硬件设备的一种保护机制
平均负载高有可能是 CPU 密集型进程导致的;
平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高;
当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源
stress 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景
# -d 参数表示高亮显示变化的区域
$ watch -d uptime
模拟一个 CPU 使用率 100% 的场景
$ stress --cpu 1 --timeout 600
模拟 I/O 压力,即不停地执行 sync
$ stress -i 1 --timeout 600
模拟的是 8 个进程
$ stress -c 8 --timeout 600
sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能。我们的案例会用到这个包的两个命令 mpstat 和 pidstat。
mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。
pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。
# -P ALL 表示监控所有 CPU,后面数字 5 表示间隔 5 秒后输出一组数据
$ mpstat -P ALL 5
# 间隔 5 秒后输出一组数据
$ pidstat -u 5 1
# 显示所有 CPU 的指标,并在间隔 5 秒输出一组数据
$ mpstat -P ALL 5 1
二、CPU上下文切换
CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。而程序计数器,则是用来存储CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文。CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
根据任务的不同,CPU 的上下文切换就可以分为几个不同的场景,也就是进程上下文切换、线程上下文切换以及中断上下文切换
进程上下文切换
Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,CPU 特权等级的 Ring 0 和 Ring 3。
内核空间(Ring 0)具有最高权限,可以直接访问所有资源;
用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。
系统调用过程通常称为特权模式切换,而不是上下文切换。
线程是调度的基本单位,而进程则是资源拥有的基本单位
vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数
xwq@xwq:~$ 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 6493448 62204 957172 0 0 78 20 1698 969 4 1 93 2 0
0 0 0 6492728 62204 957204 0 0 0 0 191 441 0 0 100 0 0
- cs(context switch)是每秒上下文切换的次数。
- in(interrupt)则是每秒中断的次数。
- r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
- b(Blocked)则是处于不可中断睡眠状态的进程数。
pidstat 给它加上 -w 选项可以查看每个进程上下文切换的情况了
xwq@xwq:~$ pidstat -w 5
Linux 4.15.0-30deepin-generic (xwq) 2019年07月30日 _x86_64_ (2 CPU)
17时02分20秒 UID PID cswch/s nvcswch/s Command
17时02分25秒 0 8 9.38 0.00 rcu_sched
17时02分25秒 0 11 0.20 0.00 watchdog/0
17时02分25秒 0 14 0.20 0.00 watchdog/1
17时02分25秒 0 849 2.99 0.20 Xorg
这个结果中有两列内容是我们的重点关注对象。一个是 cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数,另一个则是 nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数。
所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说,I/O、内存等系统资源不足时,就会发生自愿上下文切换。
而非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换。
sysbench 是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况。
# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题
$ sysbench --num-threads=10 --max-time=300 --max-requests=10000000 --test=threads run
# 每隔 1 秒输出 1 组数据(需要 Ctrl+C 才结束)
# -w 参数表示输出进程切换指标,而 -u 参数则表示输出 CPU 使用指标
$ pidstat -w -u 1
# 每隔 1 秒输出一组数据(需要 Ctrl+C 才结束)
# -wt 参数表示输出线程的上下文切换指标
$ pidstat -wt 1
三、cpu达到100%怎么办
/proc/stat提供的就是系统的 CPU 和任务统计信息
# 只保留各个 CPU 的数据
$ cat /proc/stat | grep ^cpu
输出数据解析:
- user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
- nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
- system(通常缩写为 sys),代表内核态 CPU 时间。
- idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
- iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
- irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
- softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
- steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的CPU 时间。
- guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
- guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。
perf工具使用
# 记录性能事件,等待大约 15 秒后按 Ctrl+C 退出
$ perf record -g
# 查看报告
$ perf report
top命令详解:
- R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
- D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
- Z 是 Zombie 的缩写,如果你玩过“植物大战僵尸”这款游戏,应该知道它的意思。它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
- S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
- I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。
top ,可以查看进程的状态,这些状态包括运行(R)、空闲(I)、不可中断睡眠(D)、可中断睡眠(S)、僵尸(Z)以及暂停(T)等
top 输出界面的顶端,也显示了系统整体的内存使用情况,这些数据跟 free 类似不再重复解释。我们接着看下面的内容,跟内存相关的几列数据,比如 VIRT、RES、SHR 以及 %MEM 等。
这些数据,包含了进程最重要的几个内存使用情况,挨个来看:
- VIRT 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内。
- RES 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存。
- SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。
- %MEM 是进程使用物理内存占系统总内存的百分比。
作者:废权
链接:https://blog.yjscloud.com/archives/116
声明:如无特别声明本文即为原创文章仅代表个人观点,版权归《废权的博客》所有,欢迎转载,转载请保留原文链接。


共有 0 条评论