[转帖]使用火焰图(FlameGraph)分析程序性能

使用,火焰,flamegraph,分析程序,性能 · 浏览次数 : 0

小编点评

1. 安装必要的软件: ``` sudo apt-get updates sudo apt-get upgrades ``` 2. 安装 perf 工具: ``` sudo apt-get install linux-tools-5.4.0-77-genericlinux-cloud-tools-5.4.0-77-generic ``` 3. 生成火焰图: ``` # 生成折叠后的调用栈 sudo perf script -i perf.data &> perf.unfold # 生成火焰图 ./stackcollapse-perf.pl perf.unfold &> perf.folded # 最后生成 svg 图 ./flamegraph.pl perf.folded > perf.svg ```

正文

火焰图概念

火焰图(FlameGraph)是 svg 格式的矢量图,是先通过 perf 等工具分析得到结果,并将该结果生成的具有不同层次且支持互动的图片,看起来就像是火焰,这也是它的名字的由来。表现形式如下所示:

img

需要注意以下几点:

  1. 纵向(Y 轴)高低不平,表示的是函数调用栈的深度。每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。

  2. 横向(X 轴)表示该函数执行消耗的时间,横向上会按照字母顺序排序,而且如果是同样的调用会做合并(注意:如果一个函数在 X 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长,所以这里不是严格意义上的执行消耗的时间),所以一个横向宽度越大的函数调用,一般很可能是程序的瓶颈。

  3. 火焰图的颜色是随机分配的,并不是颜色越深就是越瓶颈。因为火焰图表示的是 CPU 的繁忙程度,所以一般都是暖色调。我们需要留意的就是那些比较宽大的火苗。只要有"平顶",就表示该函数可能存在性能问题。

要生成火焰图,就需要一个 Tracer 软件,通过该软件在系统上的运行过程采样,得到结果,并将该结果图形化,才可得到人眼直观可视化的 svg 格式数据矢量图。

在 Linux 系统上,通常选择的是 perf 或者 systemtap,但是 perf 更为常用,因为它是 Linux 内核内置的性能调优工具,大多数 Linux 都包含了该工具。而 systemtap 虽然更强大,但你需要先学习它本身的编程语言。

On/Off-CPU火焰图

火焰图的类型有:On-CPU、Off-CPU,Memory等,可以参考官方以及 Blazing Performance with Flame Graphs

什么时候用 On-CPU 火焰图,什么时候才用 Off-CPU 火焰图呢?这取决于程序的瓶颈是什么:

如果是 CPU 则使用 On-CPU 火焰图。

如果是 IO 或锁则使用 Off-CPU 火焰图。

如果不能确定,则需要使用压力测试工具来确认一下:在压测下,如果 CPU 使用率趋于饱和,则使用 On-CPU 火焰图。如果无论怎么压,CPU 使用率始终不饱和,说明程序中存在 IO 或锁的瓶颈,这是就适合用 Off-CPU火焰图。实在不行,就两个都试试,正常情况下,两个差异会比较大。但如果差异不大,通常认为 CPU 被其他进程抢占了。需要注意的是,采样数据需要通过压测工具对程序持续施压,以便采集到足够的样本,关于压测工具选择,如果选择 apache bench 的话,务必开启 -k 选项,以避免系统可用端口耗尽,也可以尝试如 wrk 之类更现代的压测工具。

火焰图可视化生成器

Flame Graph 工程实现了一套生成火焰图的脚本。可以将其 clone 下来:

git clone https://github.com/brendangregg/FlameGraph.git
  • 1

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

  1. 捕获堆栈。可以使用 perf、systemtap、dtrace 等工具抓取程序的运行堆栈。

  2. 折叠堆栈。Tracer 工具抓取的程序每时刻的堆栈信息,需要对他们进行分析组合,将重复的堆栈累计在一起,从而体现出负载和关键路径。由 FlameGraph 中的 stackcollapse 程序执行。

  3. 生成火焰图。分析由 stackcollapse 程序输出的堆栈信息生成的火焰图。

不同的 Tracer 工具抓取到的信息不同,因此 FalmeGraph 提供了一系列的 stackcollapse 工具如下:

stackcollapse描述
stackcollapse.plfor DTrace stacks
stackcollapse-perf.plfor Linux perf_events “perf script” output
stackcollapse-pmc.plfor FreeBSD pmcstat -G stacks
stackcollapse-stap.plfor SystemTap stacks
stackcollapse-instruments.plfor XCode Instruments
stackcollapse-vtune.plfor Intel VTune profiles
stackcollapse-ljp.awkfor Lightweight Java Profiler
stackcollapse-jstack.plfor Java jstack(1) output
stackcollapse-gdb.plfor gdb(1) stacks
stackcollapse-go.plfor Golang pprof stacks
stackcollapse-vsprof.plfor Microsoft Visual Studio profiles

使用 Perf 生成火焰图

安装 perf

很多 Linux 系统已经自带了 perf 工具,但是 Ubuntu 需要手动安装,安装命令如下:

sudo apt install linux-tools-common
sudo apt install linux-tools-generic linux-cloud-tools-generic

    直接打 perf 命令测试一般会出现如下提示:

    $ perf 
    WARNING: perf not found for kernel 5.4.0-77
    

    You may need to install the following packages for this specific kernel:
    linux-tools-5.4.0-77-generic
    linux-cloud-tools-5.4.0-77-generic

      这时只需要再安装:

      sudo apt-get update
      sudo apt-get upgrade
      sudo apt-get install linux-tools-5.4.0-77-generic linux-cloud-tools-5.4.0-77-generic
      
      • 1
      • 2
      • 3

      然后就安装 OK 了。

      perf采集数据

      perf(performance)是 Linux 系统原生提供的性能分析工具,会返回 CPU 正在执行的函数名以及调用栈。使用 perf 采集数据命令如下:

      sudo perf record -F 99 -p 2512 -g -- sleep 60
      

        record:表示采集系统事件,没有采用 -e 执行采集事件,则默认采集 cycles(即 CPU clock 周期)。

        -F 99:指定采样频率为 99Hz(每秒99次),如果 99次都返回同一个函数名, 那就说明 CPU 这一秒钟都在执行同一个函数,可能存在性能问题。

        -p 2512:指定进程号,对某一个进程分析。

        -g:表示记录调用栈。

        sleep 30:表示持续 30 秒

        之后就会得到一个 perf.data 的文件,输出如下:

        $ sudo perf record -F 99 -p 3092020 -g -- sleep 30
        [ perf record: Woken up 1 times to write data ]
        [ perf record: Captured and wrote 0.013 MB perf.data ]
        

        $ ls
        perf.data

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

          $ sudo perf report -n --stdio
          
          • 1

          出现内容如下:

          # To display the perf.data header info, please use --header/--header-only options.
          #
          # Total Lost Samples: 0
          # Samples: 67  of event 'cpu-clock:pppH'
          # Event count (approx.): 676767670
          #
          # Children      Self       Samples  Command    Shared Object        Symbol                              >
          # ........  ........  ............  .........  ...................  ....................................>
          #
              88.06%     0.00%             0  test_perf  [unknown]            [k] 0000000000000000
                      |
                      ---0
                         |          
                         |--86.57%--__GI___libc_write
                         |          |          
                         |           --47.76%--entry_SYSCALL_64_after_hwframe
                         |                     do_syscall_64
                         |                     |          
                         |                      --44.78%--__x64_sys_write
                         |                                ksys_write
                         |                                vfs_write
                         |                                __vfs_write
                         |                                tty_write
                         |                                |          
                         |                                |--40.30%--n_tty_write
                         |                                |          |          
                         |                                |          |--17.91%--do_output_char
                         |                                |          |          |          
                         |                                |          |          |--16.42%--pty_write
          

            因为这个结果还是很难读懂,所以才有了火焰图。

            生成火焰图

            首先使用 perf script 工具对上面生成的 perf.data 进行解析:

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

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

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

                最后生成 svg 图:

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

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

                sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > perf.svg
                
                • 1

                解析火焰图

                直接使用浏览器打开 perf.svg 即可,或者将其下载到本地用浏览器打开也 OK。

                互动性

                火焰图因为是 svg 图片,可以与用户互动:

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

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

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

                局限性

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

                1. 调用栈不完整。当调用栈过深时,某些系统只返回前面的一部分(比如前10层)。
                2. 函数名缺失。有些函数没有名字,编译器只用内存地址来表示(比如匿名函数)。有可能是因为编译器优化等级太高。

                火焰图的拓展

                上面的火焰图 FlameGraph 我们习惯性称之为 CPU 火焰图。其实火焰图还有其他的种类,比如下面介绍的几种。

                浏览器的火焰图

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

                开发者工具,切换到 Performance 面板。然后,点击“录制”按钮,开始记录数据。这时可以在页面进行各种操作,然后停止“录制”。然后,开发者工具会显示一个时间轴,它的下方就是火焰图。

                使用火焰图分析程序性能-图2

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

                红蓝分叉火焰图

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

                所以,就有红/蓝差分火焰图(red/blue differential flame graphs)。其形式大概如下:

                使用火焰图分析程序性能-图3

                红蓝交叉火焰图也是一副交互式 svg 格式图片,但是用了两种不同颜色来表示,红色表示增长,蓝色表示衰减。

                与 CPU 火焰图不同的是,在红/蓝交叉火焰图中,使用不同的颜色来表示两个 profile 文件中的差异部分。在第二个 profile 中 deflate_slow( ) 函数以及它后续调用的函数运行的次数要比前一次更多,所以在上图中这个栈帧被标为了红色。可以看出问题的原因是 ZFS 的压缩功能被启用了,而在系统升级前这项功能是关闭的。

                想象一下, 如果是在分析一个微小的性能下降,比如说小于 5%,而且代码也更加复杂的时候,红蓝交叉火焰图就比普通 CPU 火焰图强大了。

                但其也有不足之处:如果一个代码执行路径完全消失了,那么在火焰图中就找不到地方来标注蓝色。你只能看到当前的 CPU 使用情况,而不知道为什么会变成这样。一个办法是,将对比顺序颠倒,画一个相反的差分火焰图。

                具体这里不做赘述,只做一个介绍,还有一些其他的差分火焰图,可以自行了解。

                如果你遇到了性能回退问题,红/蓝差分火焰图是找到根因的最快方式。这种方式抓取了两张普通的火焰图,然后进行对比,并对差异部分进行标色:红色表示上升,蓝色表示下降。 差分火焰图是以当前(“修改后”)的 profile 文件作为基准,形状和大小都保持不变。因此你通过色彩的差异就能够很直观的找到差异部分,且可以看出为什么会有这样的差异。差分火焰图可以应用到项目的每日构建中,这样性能回退的问题就可以及时地被发现和修正。

                参考

                • https://www.brendangregg.com/flamegraphs.html
                • https://www.ruilog.com/notebook/view/9ff8def96d9c.html
                • https://wenfh2020.com/2020/07/30/flame-diagram/
                • http://www.ruanyifeng.com/blog/2017/09/flame-graph.html
                </article>
                

                与[转帖]使用火焰图(FlameGraph)分析程序性能相似的内容:

                [转帖]使用火焰图(FlameGraph)分析程序性能

                火焰图概念 火焰图(FlameGraph)是 svg 格式的矢量图,是先通过 perf 等工具分析得到结果,并将该结果生成的具有不同层次且支持互动的图片,看起来就像是火焰,这也是它的名字的由来。表现形式如下所示: 需要注意以下几点: 纵向(Y 轴)高低不平,表示的是函数调用栈的深度。每一层都是一个函

                [转帖]使用Flame Graph进行系统性能分析

                http://t.zoukankan.com/arnoldlu-p-10148558.html 关键词:Flame Graph、perf、perl。 FlameGraph是由BrendanGregg开发的一款开源可视化性能分析工具,形象的成为火焰图。 从底向上像火苗一样逐渐变小,也反映了相互之间的包

                [转帖]flamegraph(火焰图)性能分析

                `https://www.cnblogs.com/HadesBlog/p/13877761.html` 使用perf工具以及flamegraph可以将调试的程序运行栈以及在每个函数中停留的时间以火焰图的形式展现出来。 perf工具可以在内核源码tools/perf中编译安装。 make && mak

                [转帖]火焰图基本使用教程

                火焰图基本使用教程 1. 基本流程 下载FlameGrapth包:https://github.com/brendangregg/FlameGraph,无需安装,直接使用。也可以直接使用命令git clone https://github.com/brendangregg/FlameGraph.gi

                [转帖]使用perf生成Flame Graph(火焰图)

                https://www.cnblogs.com/keanuyaoo/p/3313378.html 具体的步骤参见这里: 《flame graph:图形化perf call stack数据的小工具》 使用SystemTap脚本制作火焰图,内存较少时,分配存储采样的数组可能失败,需要编写脚本,还要安装k

                [转帖]Java使用火焰图查看系统瓶颈

                场景 一般情况下,我们会对现有系统进行压测等方式,来了解系统最大的吞吐量等等,通过这种方式得知系统在生产环境下可扛住的压力,如果我们想了解在压测的链路过程中,是哪些地方执行时间过长,影响了系统的吞吐量,可以使用火焰图的方式来观察。 工具 生成火焰图需要两个工具: 1. async-profiler:

                [转帖]性能优化必备——火焰图

                引言 本文主要介绍火焰图及使用技巧,学习如何使用火焰图快速定位软件的性能卡点。结合最佳实践实战案例,帮助读者加深刻的理解火焰图构造及原理,理解 CPU 耗时,定位性能瓶颈。 背景 当前现状 假设没有火焰图,你是怎么调优程序代码的呢?让我们来捋一下。 1. 功能开关法 想当年我刚工作,还是一个技术小白

                [转帖]netflix火焰圖(profile + 轉為圖像)

                本文转载自 ligeforrent 查看原文 2017-06-30 0 file/file/ 运维/运维/ profile/profile/ 图像/图像/ netnet 使用方法:利用google的lightweight-Java-profiler獲取java進程的profile(類hprof格式)

                [转帖]人工智能 Java混合模式火焰图

                https://www.dazhuanlan.com/smallnight/topics/1040103 在做性能调优的时候,我们通常会借助一些性能分析工具(比如 perf,DTrace)分析系统资源的使用情况,比如 CPU、内存等,但这些工具分析的结果通常是文本形式,不够直观,不便于快速定位系统瓶

                [转帖]人工智能 Java混合模式火焰图

                https://www.dazhuanlan.com/smallnight/topics/1040103 在做性能调优的时候,我们通常会借助一些性能分析工具(比如 perf,DTrace)分析系统资源的使用情况,比如 CPU、内存等,但这些工具分析的结果通常是文本形式,不够直观,不便于快速定位系统瓶