如何生成火焰图
如何使用perf工具和火焰图工具生成火焰图
火焰图仅用一张小图,就可以定量展示所有的性能瓶颈的全景图,而不论目标软件有多么复杂。
传统的性能分析工具通常会给用户展示大量的细节信息和数据, 而用户很难看到全貌,反而容易去优化那些并不重要的地方,经常浪费大量时间和精力却看不到明显效果。传统分析器的另一个缺点是,它们通常会孤立地显示每个函数调用的延时,但很难看出各个函数调用的上下文,而且用户还须刻意区分当前函数本身运行的时间(exclusive time)和包括了其调用其他函数的时间在内的总时间(inclusive time)。
而相比之下,火焰图可以把大量信息压缩到一个大小相对固定的图片当中(通常一屏就可以显示全)。 不怎么重要的代码路径会在图上自然地淡化乃至消失,而真正重要的代码路径则会自然地凸显出来。越重要的,则会显示得越明显。火焰图总是为用户提供最适当的信息量,不多,也不少。
1 火焰图简介
官方博客:https://www.brendangregg.com/flamegraphs.html,火焰图的源资料皆出自该博客。
火焰图能做什么:
- 可以分析函数执行的频繁程度
- 可以分析哪些函数经常阻塞
- 可以分析哪些函数频繁分配内存
以分析程序的性能瓶颈。
火焰图整个图形看起来就像一个跳动的火焰,这就是它名字的由来。
火焰图有以下特征(这里以 on-cpu 火焰图为例):
- 每一列代表一个调用栈,每一个格子代表一个函数
- 纵轴展示了栈的深度,按照调用关系从下到上排列。最顶上格子代表采样时,正在占用 cpu 的函数。
- 横轴的意义是指:火焰图将采集的多个调用栈信息,通过按字母横向排序的方式将众多信息聚合在一起。需要注意的是它并不代表时间。
- 横轴格子的宽度代表其在采样中出现频率,所以一个格子的宽度越大,说明它是瓶颈原因的可能性就越大。
- 火焰图格子的颜色是随机的暖色调,方便区分各个调用信息。
- 其他的采样方式也可以使用火焰图, on-cpu 火焰图横轴是指 cpu 占用时间,off-cpu 火焰图横轴则代表阻塞时间。
- 采样可以是单线程、多线程、多进程甚至是多 host,进阶用法可以参考附录进阶阅读。
1.1 火焰图类型
常见的火焰图类型有 On-CPU,Off-CPU,还有 Memory,Hot/Cold,Differential 等等。它们有各自适合处理的场景。
火焰图类型 | 横轴含义 | 纵轴含义 | 解决问题 | 采样方式 |
---|---|---|---|---|
on-cpu火焰图 | cpu占用时间 | 调用栈 | 找出cpu占用搞的问题函数;分析代码热路径 | 固定频率采样cpu调用栈 |
off-cpu火焰图 | 阻塞时间 | 调用栈 | i/o、网络等阻塞场景导致的性能下降;锁竞争、死锁导致的性能下降问题 | 固定频率采样阻塞事件调用栈 |
内存火焰图 | 内存申请/释放函数调用次数 | 调用栈 | 内存泄漏问题;内存占用高的对象/申请内存多的函数;虚拟内存或物理内存泄漏问题 | 有四种方式:跟踪malloc/free;跟踪brk;跟踪mmap;跟踪页错误 |
Hot/Cold火焰图 | on-cpu和off-cpu综合展示 | 调用栈 | 需要结合cpu占用以及阻塞分析的场景;off-cpu火焰图无法直观判断的场景 | on-cpu火焰图和off-cpu火焰图结合 |
1.2 什么时候使用 On-CPU 火焰图? 什么时候使用 Off-CPU 火焰图呢?
取决于当前的瓶颈到底是什么:
- 如果是 CPU 则使用 On-CPU 火焰图,
- 如果是 IO 或锁则使用 Off-CPU 火焰图.
- 如果无法确定, 那么可以通过压测工具来确认:
- 通过压测工具看看能否让 CPU 使用率趋于饱和, 如果能那么使用 On-CPU 火焰图
- 如果不管怎么压, CPU 使用率始终上不来, 那么多半说明程序被 IO 或锁卡住了, 此时适合使用 Off-CPU 火焰图.
- 如果还是确认不了, 那么不妨 On-CPU 火焰图和 Off-CPU 火焰图都搞搞, 正常情况下它们的差异会比较大, 如果两张火焰图长得差不多, 那么通常认为 CPU 被其它进程抢占了
1.3 火焰图分析技巧
- 纵轴代表调用栈的深度(栈桢数),用于表示函数间调用关系:下面的函数是上面函数的父函数。
- 横轴代表调用频次,一个格子的宽度越大,越说明其可能是瓶颈原因。
- 不同类型火焰图适合优化的场景不同,比如 on-cpu 火焰图适合分析 cpu 占用高的问题函数,off-cpu 火焰图适合解决阻塞和锁抢占问题。
- 无意义的事情:横向先后顺序是为了聚合,跟函数间依赖或调用关系无关;火焰图各种颜色是为方便区分,本身不具有特殊含义
- 多练习:进行性能优化有意识的使用火焰图的方式进行性能调优(如果时间充裕)
2 如何绘制火焰图?
2.1 生成火焰图的流程
Brendan D. Gregg 的 Flame Graph 工程实现了一套生成火焰图的脚本。Flame Graph 项目位于 GitHub上
https://github.com/brendangregg/FlameGraph
当GitHub网络不通畅的时候可以使用码云的链接:
git clone https://gitee.com/mirrors/FlameGraph.git
用 git 将其 clone下来
生成和创建火焰图需要如下几个步骤
流程 | 描述 | 脚本 |
---|---|---|
捕获堆栈 | 使用 perf/systemtap/dtrace 等工具抓取程序的运行堆栈 | perf/systemtap/dtrace |
折叠堆栈 | trace 工具抓取的系统和程序运行每一时刻的堆栈信息, 需要对他们进行分析组合, 将重复的堆栈累计在一起, 从而体现出负载和关键路径 | FlameGraph 中的 stackcollapse 程序 |
生成火焰图 | 分析 stackcollapse 输出的堆栈信息生成火焰图 | flamegraph.pl |
不同的 trace 工具抓取到的信息不同, 因此 Flame Graph 提供了一系列的 stackcollapse 工具.
stackcollapse | 描述 |
---|---|
stackcollapse.pl | for DTrace stacks |
stackcollapse-perf.pl | for Linux perf_events “perf script” output |
stackcollapse-pmc.pl | for FreeBSD pmcstat -G stacks |
stackcollapse-stap.pl | for SystemTap stacks |
stackcollapse-instruments.pl | for XCode Instruments |
stackcollapse-vtune.pl | for Intel VTune profiles |
stackcollapse-ljp.awk | for Lightweight Java Profiler |
stackcollapse-jstack.pl | for Java jstack(1) output |
stackcollapse-gdb.pl | for gdb(1) stacks |
stackcollapse-go.pl | for Golang pprof stacks |
stackcollapse-vsprof.pl | for Microsoft Visual Studio profiles |
查看帮助./FlameGraph/flamegraph.pl -h
2.2 安装 perf工具
perf 命令(performance 的缩写)讲起, 它是 Linux 系统原生提供的性能分析工具, 会返回 CPU 正在执行的函数名以及调用栈(stack)
具体用法:
- perf Examples https://www.brendangregg.com/perf.html
- Linux kernel profiling with perf https://perf.wiki.kernel.org/index.php/Tutorial
2.2.1 安装perf
ubuntu下
1 | apt install linux-tools-common |
centos下
1 | yum install perf |
2.2.2 测试perf是否可用
1 | # perf record -F 99 -a -g -- sleep 10 |
如果报错
WARNING: perf not found for kernel 4.15.0-48
You may need to install the following packages for this specific kernel:
linux-tools-4.15.0-48-generic
linux-cloud-tools-4.15.0-48-genericYou may also want to install one of the following packages to keep up to date:
linux-tools-generic
linux-cloud-tools-genericapt install linux-tools-generic
apt install linux-cloud-tools-generic
则需要安装linux-tools-generic和linux-cloud-tools-generic,但需选择对应的版本,比如提示的是4.15.0-48,则我们安装4.15.0-48版本。
# apt-get install linux-tools-4.15.0-48-generic linux-cloud-tools-4.15.0-48-generic linux-tools-generic linux-cloud-tools-generic
再次测试
1 | # perf record -F 99 -a -g -- sleep 10 |
如果没有报错则在执行的目录产生perf.data
2.2.3 perf常用命令
查看帮助文档,perf功能非常强大,我们这里只关注record和report功能,record和report也可以继续通过二级命令查询帮助文档。
perf -h
常用的五个命令:
- perf list:查看当前软硬件环境支持的性能事件
- perf stat:分析指定程序的性能概况
- perf top:实时显示系统/进程的性能统计信息
- perf record:记录一段时间内系统/进程的性能事件perf report:读取perf record生成的perf.data文件,并显示分析数据(生成火焰图用的采集命令)
- perf report:交互式命令查看资源使用情况
2.3 perf 采集数据
1 | perf record -F 99 -p 3887 -g -- sleep 30 |
perf record 表示采集系统事件, 没有使用 -e 指定采集事件, 则默认采集 cycles(即 CPU clock 周期), -F 99 表示每秒 99 次, -p 13204 是进程号, 即对哪个进程进行分析, -g 表示记录调用栈, sleep 30 则是持续 30 秒.
一定要加上 - g,否则无法记录数据!
-F 指定采样频率为 99Hz(每秒99次), 如果 99次 都返回同一个函数名, 那就说明 CPU 这一秒钟都在执行同一个函数, 可能存在性能问题.
运行后会产生一个庞大的文本文件. 如果一台服务器有 16 个 CPU, 每秒抽样 99 次, 持续 30 秒, 就得到 47,520 个调用栈, 长达几十万甚至上百万行.
为了便于阅读, perf record 命令可以统计每个调用栈出现的百分比, 然后从高到低排列.
1 | perf report -n --stdio |
2.4 生成火焰图
- 首先用 perf script 工具对 perf.data 进行解析
# 生成折叠后的调用栈
perf script -i perf.data &> perf.unfold
这里在任意文件夹都可使用
- 然后将解析出来的信息存下来, 供生成火焰图
用 stackcollapse-perf.pl 将 perf 解析出的内容 perf.unfold 中的符号进行折叠 :
# 在FlameGraph同路径下的文件夹生成火焰图
# ./FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded或者使用全路径
/opt/rh/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
- 最后生成 svg 图
# ./FlameGraph/flamegraph.pl perf.folded > perf.svg
/opt/rh/FlameGraph/flamegraph.pl perf.folded > perf.svg
3.1 火焰图的含义
火焰图是基于 stack 信息生成的 SVG 图片, 用来展示 CPU 的调用栈。
- y 轴表示调用栈, 每一层都是一个函数. 调用栈越深, 火焰就越高, 顶部就是正在执行的函数, 下方都是它的父函数.
- x 轴表示抽样数, 如果一个函数在 x 轴占据的宽度越宽, 就表示它被抽到的次数多, 即执行的时间长. 注意, x 轴不代表时间, 而是所有的调用栈合并后, 按字母顺序排列的.
- 火焰图就是看顶层的哪个函数占据的宽度最大. 只要有 “平顶”(plateaus), 就表示该函数可能存在性能问题。
- 颜色没有特殊含义, 因为火焰图表示的是 CPU 的繁忙程度, 所以一般选择暖色调.
4 互动
火焰图是 SVG 图片,可以与用户互动
火焰的每一层都会标注函数名,鼠标悬浮时会显示完整的函数名、抽样抽中的次数、占据总抽样次数的百分比。下面是一个例子
在某一层点击,火焰图会水平放大,该层会占据所有宽度,显示详细信息。