一、Linux CPU性能问题
在开发Linux项目的过程中,会时常出现CPU的高消耗而出现的一些异常问题。例如网络包的频繁收发引起系统阻塞,从而导致软狗超时问题等。本文总结了本人项目开发过程中使用的CPU性能调试方案。
二、Linux CPU性能查看方法
本文主要介绍三种基于Linux系统测试CPU性能的方法:TOP指令、proc/stat文件和火焰图。
1、TOP命令查看cpu性能
top指令是Linux系统中用于实时监控系统状态的重要工具,能够显示系统中各个进程的资源占用情况,包括CPU、内存的使用情况等。执行top指令后系统的统计信息如下:
root&user1:top //执行top指令
top - 10:54:26 up 1:08, 29 users, load average: 25.01, 7.88, 6.01
Tasks: 544 total, 2 running, 394 sleeping, 0 stopped, 0 zombie
%Cpu(s): 8.6 us, 2.5 sy, 0.0 ni, 88.4 id, 0.3 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 32929240 total, 13518068 free, 1220844 used, 18190328 buff/cache
KiB Swap: 4194300 total, 4194300 free, 0 used. 31226032 avail Mem
PID USER PR NI VIRI RES SHR S %CPU %MEM TIME+ COMMAND
26283 root 20 0 0 0 0 I 5.6 0.0 0:00.88 [kworker/1:2]
1 root 20 0 225816 9344 6560 S 0.0 0.0 0:04.19 /sbin/init maybe-ubiquity
2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 [kthreadd]
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 [kworker/0:0H]
6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 [mm_percpu_wq]
7 root 20 0 0 0 0 S 0.0 0.0 0:01.33 [ksoftirqd/0]
8 root 20 0 0 0 0 I 0.0 0.0 0:04.94 [rcu_sched]
主要关注%Cpu(S)、KiB Mem、KiB Swap和进程信息S、%CPU、%MEM.
1)%Cpu(S):8.6 us--用户空间占用CPU百分比
2.5 sy--内核空间占用百分比
88.4 id--空闲CPU百分比
2)KiB Mem:total--物料内存总量,单位B
free--空闲的物理内存总量
used--使用的物理内存总量
buff/cache--用作内核缓存的内存总量
3)KiB Swap:--交换区内存情况
4)S(进程状态):D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 I=空闲
5)%CPU:上次更新到现在的CPU时间占用百分比
6)%MEM:进程使用的物理内存百分比
top命令可通过以下参数详细查看CPU性能。
top //每隔5秒显式所有进程的资源占用情况
top -d 2 //每隔2秒显式所有进程的资源占用情况
top -c //每隔5秒显式进程的资源占用情况,并显示进程的命令行参数(默认只有进程名)
top -Hp 进程id // 显示某个进程下所有线程的资源占用情况
top -b //以批次的方式执行top
2、根据 /proc/stat 文件计算cpu性能
<1>proc/stat
proc/stat节点记录的是系统进程整体的统计信息
root&user:cat /proc/stat
//CPU指标:user,nice, system, idle, iowait, irq, softirq
cpu 130216 19944 162525 1491240 3784 24749 17773 0 0 0
cpu0 40321 11452 49784 403099 2615 6076 6748 0 0 0
cpu1 26585 2425 36639 151166 404 2533 3541 0 0 0
cpu2 22555 2957 31482 152460 330 2236 2473 0 0 0
cpu3 15232 1243 20945 153740 303 1985 3432 0 0 0
cpu4 5903 595 6017 157410 30 10959 605 0 0 0
cpu5 4716 380 3794 157909 23 118 181 0 0 0
cpu6 8001 515 8995 157571 48 571 180 0 0 0
cpu7 6903 377 4869 157885 31 271 613 0 0 0
intr ...
ctxt 22523049
btime 1500827856
processes 23231
procs_running 1
procs_blocked 0
softirq 3552900 843593 733695 19691 93143 468832 12783 257382 610426 0 513355
CPU时间=user+system+nice+idle+iowait+irq+softirq
需要重点关注的是user、nice、system和idle:
1)user:从系统启动开始累积到当前时刻,处于用户态的运行时间,不包括 nice 值为负进程。
2)nice:从系统启动开始累积到当前时刻,nice 值为负的进程所占用的CPU时间。
3)system:从系统启动开始累积到当前时刻,处于内核态的运行时间。
4)idle:从系统启动开始累积到当前时刻,除IO等待时间外的其它等待时间。
CPU利用率可以使用以下两个方法。先取两个采样点,然后计算其差值:
cpu usage=(idle2-idle1)/(cpu2-cpu1)*100
cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*100
<2>/proc/<pid>/stat和/proc/<pid>/task/<tid>/stat
/proc/<pid>/stat用于获取某一个进程的统计信息;
/proc/<pid>/task/<tid>/stat
用于获取某进程中某一个线程的统计信息;
root&user:cat /proc/19717/stat
19717 (sshd) S 19507 19507 19507 0 -1 4194624 200 0 0 0 0 2 0 0 20 0 1 0 738171 116998144 1418 18446744073709551615 1 1 0 0 0 0 0 4096 65536 0 0 0 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0
需要重点关注的是$14--utime、$15--stime、$18--nice:
1)$14--utime:该任务在用户态运行的时间,单位为jiffies;
2)$15--stime:该任务在核心态运行的时间,单位为jiffies;
3)$18--nice:任务的静态优先级
通过执行./show_tid_stat.sh <PID>(也可使用pidof+用户进程)可打印出固定<PID>进程中各线程的CPU使用情况,将数据导出后,通过数据分析手段将数据可视化。
#!/bin/sh
#保存为show_tid_stat.sh文件用于打印固定进程中的各线程cpu使用情况
path="/proc/`$1`/task"
printf "%-10s %-32s %-20s %-20s %-20s\n" "tid" "comm" "utime" "stime" "nice"
for file in $patha/*;
do
echo $file
awk '{printf("%-10s %-32s %-20s %-20s %-20s\n", $1,$2,$14,$15,$18)}' $file/stat
done
3、火焰图
火焰图(Flame Graph)是一种强大的性的性能分析工具,专门用于可视化cpu时间消耗咋各个函数栈上的情况,可以很快帮助开发这识别程序中的性能瓶颈和热点函数,从而有效的进行程序优化。火焰图通常以SVG格式提供,可以在现在浏览器中直接打开并进行交互,用户可以通过点击感兴趣的区域来查看函数名称、源码行等详细信息。
生成和创建火焰图需要如下几个步骤,具体操作在第三节中。
流程 | 描述 | 脚本 |
---|---|---|
捕获堆栈 | 使用 perf工具抓取程序的运行堆栈 | perf |
折叠堆栈 | trace 工具抓取的系统和程序运行每一时刻的堆栈信息, 需要对他们进行分析组合, 将重复的堆栈累计在一起, 从而体现出负载和关键路径 | FlameGraph 中的 stackcollapse 程序 |
生成火焰图 | 分析 stackcollapse 输出的堆栈信息生成火焰图 | flamegraph.pl |
本文主要关注于liunx的CPU性能测试,使用的是on-cpu火焰图。其他火焰图(off-cpu火焰图、内存火焰图、Hot/Cold火焰图)详情可阅读:【火焰图生成与分析】_火焰图怎么分析-CSDN博客
火焰图官方博客:Flame Graphs
三、火焰图的制作
1、查找linux版本
cat /proc/version
2、查找并下载相应的linux版本
linux官网:https://www.kernel.org/
可参考#如何下载Linux源码,看这篇就够了!_linux源码下载-CSDN博客
3、解压linux压缩包
tar -zxv -f ./linux-xx.xx.xx.tar.gz -C ./
4、linux源码tools目录下编译perf工具
make ARCH=arm CROSS_COMPILE=arm-ca9-linux-gnueabihf- perf LDFLAGS+=--static NO_LIBELF=1 V=1 WERROR=0 NO_SLANG=1 NO_GTK2=1 NO_LIBAUDIT=1 NO_LIBNUMA=1 NO_LIBPERL=1 NO_STRLCPY=1
CROSS_COMPILE=/aarch64_eabi_gcc6.2.0_glibc2.24.0_fp/bin/aarch64-unknown-linux-gnueabi- 指定交叉编译器;
perf 进入perf目录编译;
LDFLAGS+=–static 静态编译 。
5、挂载到设备并执行perf采集数据(ps -T)
(1)mount
(2)./perf record -F 99 -p 1247 -g -- sleep 30
perf record 表示采集系统事件, 没有使用 -e 指定采集事件, 则默认采集 cycles(即 CPU clock 周期);
-F 99 表示每秒 99 次;
-p 1247 是进程号, 即对哪个进程进行分析;
-g 表示记录调用栈;
--sleep 30 则是持续 30 秒。
6、perf script 工具对 perf.data 进行解析
./perf script -i perf.data &> perf.unfold
7、对perf.unfold 内容中的符号进行折叠
用 stackcollapse-perf.pl 将 perf 解析出的内容 perf.unfold 中的符号进行折叠 :(需要改一下./stackcollapse-perf.p的权限chmod +x)
./stackcollapse-perf.pl perf.unfold &> perf.folded
8、生成 svg 图
需要改一下./flamegraph.pl的权限chmod +x
./flamegraph.pl .perf.folded > perf.svg
四、火焰图的分析
火焰图是基于 stack 信息生成的 SVG 图片, 用来展示 CPU 的调用栈。
-
y 轴表示调用栈, 每一层都是一个函数. 调用栈越深, 火焰就越高, 顶部就是正在执行的函数, 下方都是它的父函数.
-
x 轴表示抽样数, 如果一个函数在 x 轴占据的宽度越宽, 就表示它被抽到的次数多, 即执行的时间长. 注意, x 轴不代表时间, 而是所有的调用栈合并后, 按字母顺序排列的.
-
火焰图就是看顶层的哪个函数占据的宽度最大. 只要有 “平顶”(plateaus), 就表示该函数可能存在性能问题。