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的栈长啥样。
因此,明确当此任务不在cpu上的时候(处于就绪态或者阻塞态),该cpu采样的结果不统计。 执行:
perf record -F 99 -a -g -p $pid -- sleep 1
就表示在所有cpu上,在1s的时间窗口内,每1/99s的时间间隔采样。如下图,示例了一个cpu上采样的过程。
然后收集当前指令地址(程序计数器)或整个堆栈信息——得到99个快照,我们把这99个快照聚合,Off-CPU阶段,perf采集不到cpu上这个任务的任何信息,所以下图参与聚合的快照,可能只有80张。这样我们就得到了该cpu上一个包含统计信息的数据。
实际上的多CPU得到的统计结果是很乱的,生成的stack trace全部展现出来会相当的庞大。虽然perf命令可以帮助对此进行折叠,汇总,但是仍然不便于我们分析。所以火焰图就是我们最后一步使用的聚合工具。展现效果如下图中所示。
上述图中,y轴高度表示的stack trace的调用深度,从上往下为从child–>parent的关系,x轴宽度表示调用的频率,所以我们在观察flame Graph的时候,要观察最顶部的那些宽度比较宽的stack信息。Flame Graph通过图形的方式能够帮助开发者迅速定位出明显消耗资源的调用
3. 一个案例:On-cpu火焰图分析fm_item性能
离线时间从413s(80c)优化到180s(80c)以内。时间显著降低,在进程的cpu利用率已经非常高的情况下满足了业务同学对fm_item物料向量生成时间降低的需求(业务同学在32c机器运行>600s,64c 460s)。以下是fm_item的流程简图
首次测试,以上流程各阶段耗时分析:
换80c的机器测试main_ps_editons并行数80, 耗时 t = 413ms,此处top的数据未记录,cpu利用率已经在90%以上。
针对这种机器cpu几乎打满,机器负载很高的情况,我们再做并行的优化意义不大,所以考虑用火焰图对fm_item进程进行On-cpu分析,看看究竟是哪些函数耗尽了cpu,然后看看这些函数有没有机会优化来减少计算或查找。采集的数据通过火焰图呈现如下:
接下来就是对compute_mid_w2进行优化,这里是因为多余的map search次数高达75%。优化后线程数 = 80不变,耗时 t = 156ms, 物料向量生成时常降低了62%。可见结合火焰图分析进程占用cpu的情况,可以有效搜集到关键函数,从而给进一步优化指明方向。
4. cpu利用率太高的一些优化措施
- (1)减少多余的操作,例如案例里的map search,json obj里的findMember代替hasMember,obj[member_name]的方式。
- (2)减少数据的深拷贝。
- (3)局部性原理,对数组按行进行访问时,具有更好的空间局部性,Cache命中率更高。
5. On-cpu火焰图分析的简要步骤:
官网资料:www.brendangregg.com/FlameGraphs…
-
(1)准备工作:服务器上下载好包FlameGraph.tar.gz并解压 wget minio.eos.grid.sina.com.cn:9100/software/Fl…
-
(2)先启动进程,再启动perf记录,sleep后的参数是指perf采集的时间 99表示的采样频率,pid就是我们要测量的进程id perf record -F 99 -a -g -p $pid -- sleep 60
-
(3)perf 进程结束后,数据记录在perf.data中,如下图:
-
(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即可显示火焰图:
最后就得到长这个样子的火焰图了,接下来的目标就是看看那些调用栈大平顶对应的函数,找到优化的方法。