火焰图的生成和分析
Ubuntu 平台的火焰图生成
在 Ubuntu 平台上,安装 FlameGraph 到 FlameGraph 目录下。
- 运行想要生成火焰图的进程
top
获取需要生成火焰图的进程号- 按照下面的脚本输入命令
#!/bin/bash
echo "please input pid"
read processid
echo "your processid:" $processid# 给权限执行 perf 指令
sudo perf record -F 99 -p $processid -g -- sleep 30
# 数据解析,生成折叠后的调用栈
sudo perf script -i perf.data &> perf.unfold
# 下面的 FlameGraph 路径需要改成系统本地的路径
../FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
../FlameGraph/flamegraph.pl perf.folded > out.svg
以上的命令也可以简化为:
perf script | ../FlameGraph/stackcollapse-perf.pl | ../FlameGraph/flamegraph.pl > out.svg
指令参数分析
perf 工具会按照指令间隔访问 CPU 获取 CPU 当前执行的函数和调用栈,将函数调用栈做一个统计,得到火焰图。
# perf record 采集系统事件,没有指定采集事件则默认为 CPU 时钟周期
# -F 99 采样频率,表示每秒 99 次
# -p $processid 表示进程号,针对哪个进程进行分析
# -g 表示记录调用栈
# sleep 30 表示持续 30 秒
sudo perf record -F 99 -p $processid -g -- sleep 30
分析火焰图
火焰图分析方法来自如何读懂火焰图?
以这张火焰图为例,纵轴表示函数的调用栈,下方函数调用上方,调用的层级越多,火焰越高。火焰的高度表示调用栈的深度,最顶部就是当前正在执行的函数。
横轴并非是单一元素决定,而是在当前函数的执行时间以及所有调用栈合并之后,得到横轴的宽度。
这张图某个 CPU 消耗很大的进程生成的火焰图,可以发现有一个异常情况,有一支火焰的调用栈很深。
点击这支火焰的底层,获得放大的火焰分支图,最上层是:
说明下方[unknown]
在不断向更深调用,栈越积越高,CPU 不断访问更深的调用栈却没有释放。
进入代码排查,这是一个 OpenGL 的 while 循环渲染代码,在循环中读取动态的数组纹理并写入纹理,这个地方会让调用栈越来越深。
更改代码中循环刷新的数组,将纹理数组从 OpenGL while 写入改为循环之前添加。新的火焰图为:
火焰变得均衡了很多,CPU 消耗也变低了。
参考资料
火焰图的生成原理与构建方式
Flame Graphs