linux flame_graph - yaokun123/php-wiki GitHub Wiki

火焰图

常见的火焰图类型有 On-CPU、Off-CPU、Memory、Hot/Cold、Differential等等。简而言之 : 整个图形看起来就像一团跳动的火焰, 这也正是其名字的由来。燃烧在火苗尖部的就是 CPU 正在执行的操作, 不过需要说明的是颜色是随机的, 本身并没有特殊的含义, 纵向表示调用栈的深度, 横向表示消耗的时间. 因为调用栈在横向会按照字母排序, 并且同样的调用栈会做合并, 所以一个格子的宽度越大越说明其可能是瓶颈. 综上所述, 主要就是看那些比较宽大的火苗, 特别留意那些类似平顶山的火苗。

要生成火焰图, 必须要有一个顺手的 Tracer 工具, 如果操作系统是 Linux 的话, 那么选择通常是 perf, systemtap 中的一种。

perf 相对更常用, 因为它是 Linux Kernel 内置的性能调优工具, 多数 Linux 都包含了它, 有兴趣的读者稍后可以参考 Linux Profiling at Netflix 中的介绍, 尤其是里面关于如何处理 Broken stacks 问题的描述, 建议多看几遍。

systemtap 相对更强大, 不过缺点是你需要先学会它本身的编程语言。

早期火焰图在 Nginx 和 社区比较活跃, 如果你是一个 Nginx 开发或者优化人员, 那么我强烈推荐你使用 春哥nginx-systemtap-toolkit, 乍一看名字你可能会误以为这个工具包是 nginx 专用的, 实际上这里面很多工具适用于任何 C/CPP 语言编写的程序:

程序 功能
sample-bt 用来生成 On-CPU 火焰图的采样数据
sample-bt-off-cpu 用来生成 Off-CPU 火焰图的采样数据

一、On/Off-CPU 火焰图

那么什么时候使用 On-CPU 火焰图? 什么时候使用 Off-CPU 火焰图呢?

取决于当前的瓶颈到底是什么, 如果是 CPU 则使用 On-CPU 火焰图, 如果是 IO 或锁则使用 Off-CPU 火焰图。

如果无法确定, 那么可以通过压测工具来确认 : 通过压测工具看看能否让 CPU 使用率趋于饱和, 如果能那么使用 On-CPU 火焰图, 如果不管怎么压, CPU 使用率始终上不来, 那么多半说明程序被 IO 或锁卡住了, 此时适合使用 Off-CPU 火焰图。

如果还是确认不了, 那么不妨 On-CPU 火焰图和 Off-CPU 火焰图都搞搞, 正常情况下它们的差异会比较大, 如果两张火焰图长得差不多, 那么通常认为 CPU 被其它进程抢占了。

在采样数据的时候, 最好通过压测工具对程序持续施压, 以便采集到足够的样本. 关于压测工具的选择, 如果选择 ab 的话, 那么务必记得开启 -k 选项, 以避免耗尽系统的可用端口. 此外, 我建议尝试使用诸如wrk 之类更现代的压测工具

二、火焰图可视化生成器

Brendan D. Gregg 的 Flame Graph 工程实现了一套生成火焰图的脚本。

Flame Graph 项目位于 GitHub上

https://github.com/brendangregg/FlameGraph

用 git 将其 clone下来:
git clone https://github.com/brendangregg/FlameGraph.git

生成和创建火焰图需要如下几个步骤

流程 描述 脚本
捕获堆栈 使用 perf/systemtap/dtrace 等工具抓取程序的运行堆栈 perf/systemtap/dtrace
折叠堆栈 trace 工具抓取的系统和程序运行每一时刻的堆栈信息, 需要对他们进行分析组合, 将重复的堆栈累计在一起, 从而体现出负载和关键路径 FlameGraph 中的 stackcollapse 程序
生成火焰图 分析 stackcollapse 输出的堆栈信息生成火焰图 flamegraph.pl

三、用 perf 生成火焰图

3.1、perf 采集数据 让我们从 perf 命令(performance 的缩写)讲起, 它是 Linux 系统原生提供的性能分析工具, 会返回 CPU 正在执行的函数名以及调用栈(stack)

sudo perf record -F 99 -p 3887 -g -- sleep 30


perf record 表示采集系统事件, 没有使用 -e 指定采集事件, 则默认采集 cycles(即 CPU clock 周期),
-F 99 表示每秒 99 次
-p 13204 是进程号, 即对哪个进程进行分析
-g 表示记录调用栈
sleep 30 则是持续 30 秒

运行后会产生一个庞大的文本文件. 如果一台服务器有 16 个 CPU, 每秒抽样 99 次, 持续 30 秒, 就得到 47,520 个调用栈, 长达几十万甚至上百万行。

为了便于阅读, perf record 命令可以统计每个调用栈出现的百分比, 然后从高到低排列

sudo perf report -n --stdio

3.2、生成火焰图

首先用 perf script 工具对 perf.data 进行解析

# 生成折叠后的调用栈
perf script -i perf.data &> perf.unfold

将解析出来的信息存下来, 供生成火焰图。首先用 stackcollapse-perf.pl 将 perf 解析出的内容 perf.unfold 中的符号进行折叠

# 生成火焰图
./stackcollapse-perf.pl perf.unfold &> perf.folded

最后生成 svg 图

./flamegraph.pl perf.folded > perf.svg

们可以使用管道将上面的流程简化为一条命令

perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > process.svg

将生成的svg文件process.svg拖到浏览器中即可。

四、解析火焰图

4.1、火焰图的含义

火焰图是基于 stack 信息生成的 SVG 图片, 用来展示 CPU 的调用栈。

  • 1、每一列代表一个调用栈,每一个格子代表一个函数

  • 2、纵轴展示了栈的深度,按照调用关系从下到上排列,最顶上格子代表采样时,正在占用 cpu 的函数。

  • 3、横轴的意义是指:火焰图将采集的多个调用栈信息,通过按字母横向排序的方式将众多信息聚合在一起。需要注意的是它并不代表时间

  • 4、横轴格子的宽度代表其在采样中出现频率,所以一个格子的宽度越大,说明它是瓶颈原因的可能性就越大。

  • 5、颜色没有特殊含义, 因为火焰图表示的是 CPU 的繁忙程度, 所以一般选择暖色调。

  • 6、其他的采样方式也可以使用火焰图, on-cpu 火焰图横轴是指 cpu 占用时间,off-cpu 火焰图横轴则代表阻塞时间。

火焰图就是看顶层的哪个函数占据的宽度最大. 只要有 “平顶”(plateaus), 就表示该函数可能存在性能问题。

4.2、互动性

火焰图是 SVG 图片, 可以与用户互动

  • 鼠标悬浮

火焰的每一层都会标注函数名, 鼠标悬浮时会显示完整的函数名、抽样抽中的次数、占据总抽样次数的百分比

  • 点击放大

在某一层点击,火焰图会水平放大,该层会占据所有宽度,显示详细信息。左上角会同时显示 “Reset Zoom”, 点击该链接, 图片就会恢复原样。

  • 搜索

按下 Ctrl + F 会显示一个搜索框,用户可以输入关键词或正则表达式,所有符合条件的函数名会高亮显示

4.3、局限

两种情况下, 无法画出火焰图, 需要修正系统行为

  • 调用栈不完整

当调用栈过深时,某些系统只返回前面的一部分(比如前10层)。

  • 函数名缺失

有些函数没有名字,编译器只用内存地址来表示(比如匿名函数)。

4.4、浏览器的火焰图

Chrome 浏览器可以生成页面脚本的火焰图, 用来进行 CPU 分析

打开开发者工具, 切换到 Performance 面板. 然后, 点击"录制" 按钮, 开始记录数据. 这时, 可以在页面进行各种操作, 然后停止"录制".

这时, 开发者工具会显示一个时间轴. 它的下方就是火焰图.

浏览器的火焰图与标准火焰图有两点差异 : 它是倒置的(即调用栈最顶端的函数在最下方); x 轴是时间轴, 而不是抽样次数

五、红蓝分叉火焰图

幸亏有了 CPU 火焰图(flame graphs), CPU 使用率的问题一般都比较好定位. 但要处理性能回退问题, 就要在修改前后或者不同时期和场景下的火焰图之间, 不断切换对比, 来找出问题所在, 这感觉就是像在太阳系中搜寻冥王星. 虽然, 这种方法可以解决问题, 但我觉得应该会有更好的办法.

所以, 下面就隆重介绍 红/蓝差分火焰图(red/blue differential flame graphs)

5.1、红蓝差分火焰图示例

上面是一副交互式 SVG 格式图片. 图中使用了两种颜色来表示状态, 红色表示增长, 蓝色表示衰减.

这张火焰图中各火焰的形状和大小都是和第二次抓取的 profile 文件对应的 CPU 火焰图是相同的. (其中, y 轴表示栈的深度, x 轴表示样本的总数, 栈帧的宽度表示了 profile 文件中该函数出现的比例, 最顶层表示正在运行的函数, 再往下就是调用它的栈).

在下面这个案例展示了, 在系统升级后, 一个工作载荷的 CPU 使用率上升了. 下面是对应的 CPU 火焰图(SVG 格式)

通常, 在标准的火焰图中栈帧和栈塔的颜色是随机选择的. 而在红/蓝差分火焰图中, 使用不同的颜色来表示两个 profile 文件中的差异部分.

参考:https://blog.csdn.net/gatieme/article/details/78885908