perf 初探

最近在做spark的优化,需要用perf和jvm profiling 去找热点函数。
虽然最后发现perf并不管用,但是还是记录一下, 它在别的方面同样为我提供了不少灵感。

先熟悉perf和jvm profiling的使用。

部分内容参考perf wiki
https://perf.wiki.kernel.org/index.php/Main_Page
github
https://github.com/torvalds/linux/tree/master/tools/perf/Documentation
我感觉wiki写的已经很清楚了,比看文档来的快

perf的基本原理还是采样, 不多说,wiki上有很多介绍,基于事件event进行采样。
通过perf list命令了解支持的性能事件,

对程序的大概了解应该首先从perf -stat开始
这个命令主要分析程序的性能状况,处理器、存储器占用时间等,可以直观的观察程序资源的占用情况。
常用-p指定pid进程号。

perf top是从函数角度进行分析的,可以看到函数在各个事件上的热度,定位热点函数甚至指令。如果要进行热点函数分析,可以先用这个。
但是它处理不了spark,map过程中的函数调用无法显示。
常用-g 显示函数的包含关系,-p指定pid

perf -record -report 我觉得是top的升级版,是将采样的所有信息存储在文件中并可以阅读分析。后期可以用火焰图等方式进行处理。
通常 -record 是存储文件的阶段,在存储过程中最好加上-g属性,显示函数的包含关系,这个很有用。
-report是阅读文件的阶段,它默认显示的各列内容如下:

perf report

Events: 1K cycles

#

Overhead Command Shared Object Symbol

…….. …………… ………………………… ……………………………….

#
28.15% firefox-bin libxul.so [.] 0xd10b45
4.45% swapper [kernel.kallsyms] [k] mwait_idle_with_hints
4.26% swapper [kernel.kallsyms] [k] read_hpet
2.13% firefox-bin firefox-bin [.] 0x1e3d
1.40% unity-panel-ser libglib-2.0.so.0.2800.6 [.] 0x886f1
[…]
第一列显示样本在总事件中占用的百分比,第二列显示的是收集样本的过程,也就是命令名。第三列是样本来源,最后是特权级别。
新版本的perf在第二列会加入该事件占用的百分比(因为第一列显示的是包括它的子函数的样本点的累计)

[.] : user level
[k]: kernel level
[g]: guest kernel level (virtualization)
[u]: guest os user space
[H]: hypervisor

注意,在record阶段加入 -g选项后,每一行的最左侧会新增一个+。
可以对该行打enter,会显示它调用的子函数。子函数显示可以是多级的
但是要注意,这里第一列的数值,是所有子函数的内容的累加和,在我分析单独函数的性能的时候,很不方便,所以考虑如下代码:

perf report -g graph –no-children

可以去掉children列(第一列)内容

如果要深入到指令级别的调优,可以用
perf annotate
我只是尝试了一下,浅尝辄止

最后,perf -report的文字报表显示不太直观,很多时候可以用flame-graph进行分析,它是用perf -record生成的perf.data生成一张函数调用关系的.svg进行展示。
在github上有开源项目可用。
clone即可
https://github.com/brendangregg/FlameGraph

1、第一步
$sudo perf record -e cpu-clock -g -p 2859
Ctrl+c结束执行后,在当前目录下会生成采样数据perf.data.
2、第二步
用perf script工具对perf.data进行解析
perf script -i perf.data &> perf.unfold
3、第三步
将perf.unfold中的符号进行折叠:
#./stackcollapse-perf.pl perf.unfold &> perf.folded
4、最后生成svg图:
./flamegraph.pl perf.folded > perf.svg
另,这个项目不止可以分析perf数据。
效果如图