linux perf 结合火焰图是定位 cpu 热点函数最直观高效的方式,核心在于采集带调用栈的低开销样本,经折叠转换后生成交互式 svg 火焰图,通过视觉聚焦识别深层耗时路径,并依图中宽高、火柱、系统调用及 unknown 符号等模式指导优化。

Linux perf 结合火焰图(Flame Graph)是定位 CPU 热点函数最直观高效的方式。核心在于:采集足够代表性、低开销的栈采样数据,再用标准工具链转换为交互式 SVG 图形,最终通过视觉聚焦快速识别耗时最深的调用路径。
一、使用 perf record 采集带调用栈的性能数据
关键是要启用帧指针(frame pointer)或 DWARF 栈展开,确保能还原完整调用链:
- 若内核和程序编译时保留了 frame pointer(推荐,开销更低),运行:
sudo perf record -g -F 99 -p <pid> -- sleep 30</pid>
其中-g启用调用图采样,-F 99表示每秒采样约 99 次(避免干扰又保证精度),-p指定目标进程,-- sleep 30控制采样时长。 - 若程序无 frame pointer(如 GCC 默认开启
-fomit-frame-pointer),需用 DWARF 展开:sudo perf record -g --call-graph dwarf,1024 -p <pid> -- sleep 30</pid>
注意dwarf,1024中的 1024 是栈缓冲区大小(单位字节),复杂调用链可适当调大。 - 采集后生成
perf.data,可用perf script快速验证是否含栈信息(输出中应有多个缩进层级的函数名)。
二、导出折叠格式(folded stack trace)
火焰图工具不直接读 perf.data,需先转为文本格式的“折叠栈”(每行一个调用路径,函数间用分号连接):
- 执行:
perf script -F comm,pid,tid,cpu,time,period,Event,ip,sym,dso,iregs,stack | ./stackcollapse-perf.pl > out.perf-folded - 若未安装
stackcollapse-perf.pl,可从 FlameGraph 仓库 下载该脚本(无需编译,perl 脚本)。 - 常见简写方式(依赖 perf 自带的 alias):
perf script | stackcollapse-perf.pl > out.perf-folded
前提是已将stackcollapse-perf.pl加入 PATH 或当前目录。
三、生成 SVG 火焰图
用 flamegraph.pl 将折叠文件绘制成交互式火焰图:
- 执行:
./flamegraph.pl out.perf-folded > flamegraph.svg - 打开生成的
flamegraph.svg(推荐用 chrome 或 firefox 浏览器),横向宽度代表相对耗时,纵向深度代表调用层级。 - 鼠标悬停可查看精确百分比与函数签名;点击某函数可聚焦其子树(zoom in);右键可重置视图。
- 若想高亮特定模块(如只看用户态 C++ 函数),可在生成时加过滤:
grep -v '[unknown]|/lib|/usr/lib' out.perf-folded | ./flamegraph.pl > user-only.svg
四、准确定位热点函数与优化方向
火焰图不是终点,而是分析起点。重点关注以下模式:
- 宽而高的矩形:单个函数自身耗时长(如
memcpy、malloc、自定义计算函数),优先检查算法复杂度或内存访问模式。 - 窄但贯穿多层的“火柱”:高频小函数被反复调用(如迭代器
operator++、锁争用点),考虑批处理、缓存或无锁优化。 - 意外出现在顶层的系统调用或库函数(如
sys_futex、pthread_mutex_lock):暗示锁竞争或 I/O 阻塞,配合perf record -e sched:sched_stat_sleep,sched:sched_switch进一步分析等待行为。 - 右上角出现大量
[unknown]或地址(如0x7fabc1234567):说明符号缺失,需确保调试信息可用(debuginfo包已安装,或程序编译时加-g)。