把采样调用栈折叠成 SVG 火焰图,定位 CPU 与阻塞热点
火焰图不是采集器,而是把 perf、eBPF 或语言级 profiler 采到的调用栈按“栈帧出现次数”聚合后绘制的 SVG。横向宽度表示采样占比,不是耗时绝对值;纵向是调用栈深度。常见输入有 perf record -g、bpftrace 以及 async-profiler/py-spy 的折叠栈。
perf 受 perf_event_paranoid 限制,通常需要 root;99Hz 采样可减少与周期性任务锁步。stackcollapse-perf.pl、flamegraph.pl)仍是通用后端,需要 Perl。async-profiler,Python 用 py-spy,它们直接输出 SVG,符号和解释器栈更准确。# 以 99Hz 采样目标进程 30 秒,-g 采集调用栈
sudo perf record -F 99 -g -p <PID> -o /tmp/perf.data -- sleep 30
# 把 perf.data 折叠并生成 SVG(FlameGraph 仓库路径按实际修改)
sudo perf script -i /tmp/perf.data | \
/opt/FlameGraph/stackcollapse-perf.pl | \
/opt/FlameGraph/flamegraph.pl --title "CPU flame graph" > /tmp/cpu.svg
# Java 进程:async-profiler 3.x 用 asprof 直接输出交互式 HTML
asprof -d 30 -e cpu -f /tmp/java.html <PID>
# Python 进程:py-spy 采样并直接生成 SVG
sudo py-spy record -o /tmp/python.svg --pid <PID>
# 先确认符号是否可解析,避免整张图都是 [unknown]
sudo perf report -i /tmp/perf.data --stdio | head -20
perf script report flamegraph 在较新的 perf 中也能直接生成 HTML,但各发行版版本差异较大;生产上更常用上面的折叠脚本。
-g 时只有一层栈,火焰图退化成按函数名排列的柱状图,无法看出调用关系。-fomit-frame-pointer 编译时帧指针展开会失败;改用 --call-graph dwarf(开销更高)或语言级 profiler。[unknown];安装对应 debuginfo/dbgsym 包,或用 --symfs 指向符号目录。offcputime、bpftrace)或语言级 wall-clock 模式。nsenter),并且需要 perf 权限。--minwidth 隐藏占比极小的帧;但不要用它掩盖长尾。perf record 忘记加 -g 会发生什么?