Linux perf 的火焰图生成与热点函数定位完整流程

1次阅读

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

Linux perf 的火焰图生成与热点函数定位完整流程

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(推荐用 chromefirefox 浏览器),横向宽度代表相对耗时,纵向深度代表调用层级。
  • 鼠标悬停可查看精确百分比与函数签名;点击某函数可聚焦其子树(zoom in);右键可重置视图。
  • 若想高亮特定模块(如只看用户态 C++ 函数),可在生成时加过滤:
    grep -v '[unknown]|/lib|/usr/lib' out.perf-folded | ./flamegraph.pl > user-only.svg

四、准确定位热点函数与优化方向

火焰图不是终点,而是分析起点。重点关注以下模式:

  • 宽而高的矩形:单个函数自身耗时长(如 memcpymalloc、自定义计算函数),优先检查算法复杂度或内存访问模式。
  • 窄但贯穿多层的“火柱”:高频小函数被反复调用(如迭代器 operator++、锁争用点),考虑批处理、缓存或无锁优化。
  • 意外出现在顶层的系统调用或库函数(如 sys_futexpthread_mutex_lock):暗示锁竞争或 I/O 阻塞,配合 perf record -e sched:sched_stat_sleep,sched:sched_switch 进一步分析等待行为。
  • 右上角出现大量 [unknown] 或地址(如 0x7fabc1234567):说明符号缺失,需确保调试信息可用(debuginfo 包已安装,或程序编译时加 -g)。
text=ZqhQzanResources