背景
通常在分析性能问题时,我们会用 `top , sar , perf` 来观测 CPU 的使用情况;多数据情况下是观测别人的程序。
如果从熟悉工具的角度来看,观测自己的程序,根据观测到的结果再结合程序源代码,对于我们掌握性能分析工具会更有帮助。
构造程序
写一个 cpu 密集型的程序,让它既要使用 user 空间,也要使用 sys 空间;这个我就直接用 C 写吧,实现也简单。
代码语言:javascript复制#include<unistd.h>
int main(int, char**) {
// for 循环这个会占用 user 空间
for(;;) {
// 不断的查询父进程的 pid ,这个会占用 sys 空间
getppid();
}
}
sar 看 cpu 的使用率
要观测所有 cpu 核心,每一秒打印一次报告,共打印 5 次,命令可以这样写。
代码语言:javascript复制sar -P ALL 1 5
平均时间: CPU %user %nice %system %iowait %steal %idle
平均时间: all 2.53 0.00 4.34 0.00 0.00 93.13
平均时间: 0 0.20 0.00 0.40 0.00 0.00 99.40
平均时间: 1 0.20 0.00 0.00 0.00 0.00 99.80
平均时间: 2 0.00 0.00 0.99 0.00 0.00 99.01
平均时间: 3 0.20 0.00 0.40 0.00 0.00 99.40
平均时间: 4 0.40 0.00 0.00 0.00 0.00 99.60
平均时间: 5 0.00 0.00 0.20 0.00 0.00 99.80
平均时间: 6 0.20 0.00 0.00 0.00 0.00 99.80
平均时间: 7 3.99 0.00 0.40 0.00 0.00 95.61
平均时间: 8 0.00 0.00 0.00 0.00 0.00 100.00
平均时间: 9 33.60 0.00 66.40 0.00 0.00 0.00
平均时间: 10 0.60 0.00 0.40 0.00 0.00 99.00
平均时间: 11 0.00 0.00 0.20 0.00 0.00 99.80
平均时间: 12 0.40 0.00 0.00 0.00 0.00 99.60
平均时间: 13 0.00 0.00 0.00 0.00 0.00 100.00
平均时间: 14 0.40 0.00 0.20 0.00 0.00 99.40
平均时间: 15 0.20 0.00 0.00 0.00 0.00 99.80
到这里我们可以看到程序的压力都在核心 9 上,其中 user 使用率 33.6%,sys 使用率 66.4% 。到目前为止我们还是只知道使用率,至于这 66.4% 的 sys 使用率花在了哪里,从程序的源代码中我们可以看到是 `getppid`。
通常我们面对的是别人的程序,要么就是没有源代码,要么就是源代码的行数众多;如果要相对精确的找到是哪一行的问题,这个时候我们就要用到 perf (事实上 perf 也不能保证一定有用)。
perf 打火焰图
`perf ` 可以帮我们对 cpu 进行采样,采样的结果再交由 `FlameGraph` 生成火焰图。结合这两个工具我们就能方便地从函数调用堆栈的角度来分析性能问题。
1、ps 一下找到我们要采样的进程号
代码语言:javascript复制ps -ef | grep hello
root 29835 29834 99 16:52 pts/8 00:14:07 /data/testing-cpps/build/hello001
root 22861 22837 0 17:06 pts/1 00:00:00 grep --color=auto hell
2、采样 pid 29835 的 cpu 使用情况,每秒采 99 次,采 60 秒。
代码语言:javascript复制# 采样
perf record -F 99 -p 29835 -g -o perf-reord.log -- sleep 60
perf script -i in-fb.data > perf-script.log
# 制图
stackcollapse-perf.pl perf-script.log > stackcollapse-perf.log
flamegraph.pl stackcollapse-perf.log >hello001-cpu.svg
3、由于输出的是 svg 文件,所以我们可以在浏览器中直接查看。
现在有了函数的调用堆栈,对于热点函数名就明确了。