火焰图

1. 火焰图的概念

以下是比较官方的解释:

一种软件执行情况的形象化的反映,用于做性能profile和debug。

在Flame Graph在呈现出整个最终结果之前,其中主要的工作并不是图形的展现,而是前面profile数据的采集。
这里数据的采集首先按照profile的类型分为以下几类:

  • (1)CPU的profile分析,那需要进行的stack trace的采集,可以借助于Linux的perf命令
  • (2)Off-CPU的profile,那些没有消耗CPU的线程的profile,可以理解为被block住的线程。
    以上不同类型的profile需要依赖不同的采集工具,对于CPU的profile,它要做的其实就是进程stack trace的收集。这个收集可以按照采集总时间,采集频率来进行。

2. CPU的profile分析

我们要分析的是某个任务在cpu被执行的过程中,具体的调用栈长啥样。所以我们关注的是这个任务在运行态时,执行它的cpu的栈长啥样。


image.png

因此,明确当此任务不在cpu上的时候(处于就绪态或者阻塞态),该cpu采样的结果不统计。
执行:

perf record -F 99 -a -g -p $pid -- sleep 1

就表示在所有cpu上,在1s的时间窗口内,每1/99s的时间间隔采样。如下图,示例了一个cpu上采样的过程。


<div align=center>


image.png

</div>

然后收集当前指令地址(程序计数器)或整个堆栈信息——得到99个快照,我们把这99个快照聚合,Off-CPU阶段,perf采集不到cpu上这个任务的任何信息,所以下图参与聚合的快照,可能只有80张。这样我们就得到了该cpu上一个包含统计信息的数据。


<div align=center>


image.png

</div>

实际上的多CPU得到的统计结果是很乱的,生成的stack trace全部展现出来会相当的庞大。虽然perf命令可以帮助对此进行折叠,汇总,但是仍然不便于我们分析。所以火焰图就是我们最后一步使用的聚合工具。展现效果如下图中所示。


<div align=center>


image.png

</div>

上述图中,y轴高度表示的stack trace的调用深度,从上往下为从child–>parent的关系,x轴宽度表示调用的频率,所以我们在观察flame Graph的时候,要观察最顶部的那些宽度比较宽的stack信息。Flame Graph通过图形的方式能够帮助开发者迅速定位出明显消耗资源的调用

3. 一个案例:On-cpu火焰图分析fm_item性能

4. cpu利用率太高的一些优化措施

  • (1)减少多余的操作,例如案例里的map search,json obj里的findMember代替hasMember,obj[member_name]的方式。
  • (2)减少数据的深拷贝。
  • (3)局部性原理,对数组按行进行访问时,具有更好的空间局部性,Cache命中率更高。

5. On-cpu火焰图分析的简要步骤:

官网资料:http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

  • (1)准备工作:服务器上下载好包FlameGraph.tar.gz并解压
    wget http://minio.eos.grid.sina.com.cn:9100/software/FlameGraph.tar.gz

  • (2)先启动进程,再启动perf记录,sleep后的参数是指perf采集的时间 99表示的采样频率,pid就是我们要测量的进程id
    perf record -F 99 -a -g -p $pid -- sleep 60

  • (3)perf 进程结束后,数据记录在perf.data中,如下图:
    <div align=center>


    image.png

    </div>

  • (4)接下来执行生成out.perf-folded中间文件
    perf script | ./FlameGraph/stackcollapse-perf.pl > out.perf-folded

  • (5)接着继续执行,把out.perf-folded转换成perf-kernel.svg文件:
    ./FlameGraph/flamegraph.pl out.perf-folded > perf-kernel.svg

  • (6)启动一个web server 比如运行python -m SimpleHTTPServer 8080

出现如下页面,点击红色箭头指向的perf-kernel.svg即可显示火焰图:


<div align=center>


image.png

</div>

最后就得到长这个样子的火焰图了,接下来的目标就是看看那些调用栈大平顶对应的函数,找到优化的方法。


<div align=center>


image.png

</div>

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容