FlameGraph 火焰图简介
火焰图(Flame Graph) 是由性能分析专家 Brendan Gregg 发明的一种调用栈采样(Profiling)数据的可视化分析工具。它能将成千上万条复杂的采样调用栈聚合为一张紧凑、直观的矢量图(通常为 SVG 格式),帮助开发者在几秒钟内快速定位系统的性能瓶颈。火焰图种类:
- On-CPU 火焰图,排查高 CPU 使用率、算法复杂度过高、密集计算热点。
- Off-CPU 火焰图,排查接口响应慢但 CPU 空闲的场景(如磁盘/网络阻塞、互斥锁竞争)
- Memory / Allocation 火焰图,定位内存泄漏、频繁小对象分配导致 GC 频繁的问题。
- 差异火焰图,版本发布前后的性能回归对比、优化代码效果验证。
kernel内核的配置
bash
CONFIG_PERF_EVENTS=y
CONFIG_FRAME_POINTER=y
CONFIG_KALLSYMS=y / CONFIG_KALLSYMS_ALL=y
CONFIG_TRACEPOINTS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
程序编译传参
bash
-fno-omit-frame-pointer -g -O2 #保留帧指针
系统运行配置参数和安装的组件
bash
# 允许普通用户采样 CPU 周期及大多数事件
sudo sysctl -w kernel.perf_event_paranoid=1
sudo sysctl -w kernel.kptr_restrict=0
sudo sysctl -w kernel.perf_event_max_sample_rate=100000
#需要安装的组件
sudo apt install linux-tools-common linux-tools-generic
sudo mkdir -p /usr/lib/linux-tools/$(uname -r)
#找到对应的perf的程序位置
sudo ln -s /usr/lib/linux-tools/5.15.0-198-generic/perf /usr/lib/linux-tools/$(uname -r)/perf
采集程序运行的信息
bash
#-F:参数5000Hz的采集速率,采集程序 ./test_app 0,的性能分析数据,默认是On-CPU 火焰图
perf record -F 5000 -g -- ./test_app 0
#采集进行进程程序的数据
perf record -F 99 -p <PID> -g -- sleep 30
#采集线程的数据
perf record -F 99 -t <TID> -g -- sleep 30
# 如果该应用是多进程架构(例如 Nginx、PostgreSQL),可以传入多个 PID(逗号分隔)
perf record -F 99 -p <PID1>,<PID2>,<PID3> -g -- sleep 30
采集完数据后,会在当前目录下生成:perf.data,重复采集生成perf.data.old,下载 FlameGraph,一键生成svg火焰图
bash
perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > flamegraph.svg
获取的svg图如下所示:

优化良好的火焰图特点
一个经过良好优化的 C/C++ 应用程序,其 On-CPU 火焰图通常呈现出"郁郁葱葱的松树林"或"参差起伏的丘陵群"形态,具体特征如下:
1. 没有孤立庞大的"宽平顶山"
- 特征: 优化良好的程序,没有哪一个函数能单独横跨 30%~50% 的宽度成为顶层平顶。
- 含义: 计算任务被充分细化、并行化或流水线化,计算热点已经经过了算法优化或硬件加速,没有单一函数在原地做极低效的重度循环。
2. 系统/内存底层开销极小
- 特征: 搜寻
memcpy、memmove、malloc、free、operator new、printf/ 日志输出等函数,它们在火焰图中的宽度非常窄(甚至肉眼很难直接点中)。 - 含义: 数据流实现了零拷贝(Zero-Copy)传递,对象生命周期复用合理(如内存池、预分配),没有频繁的堆内存分配与垃圾拷贝。
3. 栈顶大多落在"业务终点"而非"低效底层"
- 特征: 顶层的尖刺大多直接落在真实的 SIMD/NEON 向量指令、核心业务决策或底层驱动调用上,而不是卡在标准库容器查找(如低效的
std::map::find)或多层冗余封装转换上。
4. (多线程应用)各工作线程形态相似且宽度均匀
- 如果按线程(TID)分开绘制火焰图,每个 Worker 线程的调用栈宽度、形态高度一致,说明任务切分均匀,没有"一核有难、七核围观"的锁死或负载倾斜现象。
5. 异构平台(如 Jetson Orin)上 CPU 呈现"轻量调度型"
- 对于嵌入式 AI / 视觉平台,图像解包、变换、特征提取、深度学习推理若已充分下放给 GPU、DLA、VIC、PVA 硬件引擎,CPU 火焰图通常很矮、很分散(主要在做事件收发、管道调度),CPU 占用率整体很低。
其它采集火焰图种类的命令
采集 Off-CPU(阻塞、I/O 等待、锁竞争)
bash
# 1. 对指定目标采集 30 秒 Off-CPU 耗时(单位微秒,过滤休眠 >1000 微秒的栈)
# -d 会输出 folded 格式,直接接入 flamegraph.pl
sudo offcputime-bpfcc -df -p <PID> 30 > out.offcpu.folded
# 或采集启动单进程并记录:
sudo offcputime-bpfcc -df -c "./test_app 0" > out.offcpu.folded
# 2. 生成 Off-CPU 火焰图(--countname 提示单位为微秒/毫秒)
./FlameGraph/flamegraph.pl --color=io --countname="us" out.offcpu.folded > offcpu.svg
采集内存(Memory / Allocations)
bash
# 采集所有缺页异常 (page-faults)
perf record -e page-faults -c 1 -g -- ./test_app 0
# 如果想细分次缺页(软缺页)与主缺页(需要读盘 swap):
# -e minor-faults -g
# -e major-faults -g
# 折叠并生成内存缺页火焰图
perf script > out.perf
./stackcollapse-perf.pl out.perf > out.folded
./flamegraph.pl --color=mem --countname="pages" out.folded > mem_faults.svg
#-----------------------------------------------------------------------------
# 采集内核 kmalloc / kfree(适用于驱动与内核模块分析)
# 挂载内核 slab 分配 tracepoint
perf record -e kmem:kmalloc -e kmem:kmem_cache_alloc -g -- ./test_app 0
#-----------------------------------------------------------------------------
#采集用户态堆内存分配(malloc / free)
# 1. 探测 libc 的 malloc 入口
perf record -e probe_libc:malloc -g -- ./test_app 0
# 2. 或结合 eBPF/BCC memleak(更推荐,低开销追踪堆泄漏)
sudo memleak-bpfcc -p <PID> --combined-only