一、perf工具介绍

perf 命令(performance 的缩写),是Linux系统提供的性能分析工具集,包含多种子工具,能够监测多种硬件及软件性能指标,包括cpu、内存、io等,这些可监测指标我们称为event。

Brendan Gregg的文章中总结了perf 支持的event结构图,详情可见:

perf event结构图

二、perf工作模式

2.1 计数模式

记录perf执行过程中event的出现次数。

2.2 采样模式

在perf执行过程中,按照指定频率去采样event,每次采样时,记录当前性能指标信息(cpu、进程id、运行栈等)。这种方式由于每次都记录信息,所以额外的资源消耗是比较大的,需要权衡一下采样频率。

2.3 自定义模式

可以对对应的event执行用户自己设计的代码,也就是说记录的信息、执行的操作可以由用户定制。

三、perf安装

对于ubuntu等linux系统发行版,都提供了对应的包,只要根据内核版本进行安装即可。安装的命令如下:

# 在ubuntu下
sudo apt-get install linux-tools-common
sudo apt-get install linux-tools-"$(uname -r)"
sudo apt-get install linux-cloud-tools-"$(uname -r)"
sudo apt-get install linux-tools-generic
sudo apt-get install linux-cloud-tools-generic

四、perf使用方法

4.1 perf list

perf list查看当前系统支持的性能事件。

4.2 perf top

perf top类似top命令,主要用于实时分析各个函数在某个性能事件上的热度,能够快速的定位热点函数,包括应用程序函数、模块函数与内核函数,甚至能够定位到热点指令。执行需要root权限。

Perf top:实时显示系统/进程的性能统计信息

常用参数
-e:指定性能事件                               -a:显示在所有CPU上的性能统计信息
-C:显示在指定CPU上的性能统计信息              -p:指定进程PID
-t:指定线程TID                                -K:隐藏内核统计信息
-U:隐藏用户空间的统计信息                     -s:指定待解析的符号信息

‘-G’ or‘--call-graph’ <output_type,min_percent,call_order>

graph: 使用调用树,将每条调用路径进一步折叠。这种显示方式更加直观。每条调用路径的采样率为绝对值。也就是该条路径占整个采样域的比率。
fractal:默认选项。类似与 graph,但是每条路径前的采样率为相对值。
flat: 不折叠各条调用

选项 call_order 用以设定调用图谱的显示顺序,该选项有 2个取值,分别是callee 与caller。
将该选项设为callee 时,perf按照被调用的顺序显示调用图谱,上层函数被下层函数所调用。
该选项被设为caller 时,按照调用顺序显示调用图谱,即上层函数调用了下层函数路径,也不显示每条调用路径的采样率

4.3 perf stat

perf stat用于统计event出现的次数,我们还是先运行前面的测试代码,再简单运行一下perf stat看看:

4.4 perf record

perf record是采样模式,perf收集采样信息并记录在文件中,可以离线分析。使用下面的 perf report解析收集的采样数据文件。

Perf record:记录一段时间内系统/进程的性能参数
参数:
 -e:选择性能事件                    -p:待分析进程的id
 -t:待分析线程的id                  -a:分析整个系统的性能
 -C:只采集指定CPU数据               -F:采样频率,每秒多少次
 -c:事件的采样周期                  -o:指定输出文件,默认为perf.data
 -A:以append的方式写输出文件        -f:以OverWrite的方式写输出文件
 -g:记录函数间的调用关系

举例:
sudo perf record -e cpu-clock -g -p 2548
 -g 选项是告诉perf record额外记录函数的调用关系
 -e cpu-clock 指perf record监控的指标为cpu周期 
 -p 指定需要record的进程pid

采样一段时间,可以使用ctrl+c停止命令,这时会生成 perf.data 文件(默认文件名)

4.5 perf report

perf report 主要用来分析上面perf record生成的perf.data文件。

perf report:读取perf record生成的数据文件,并显示分析数据
参数
-i:输入的数据文件                             -v:显示每个符号的地址
-d <dos>:只显示指定dos的符号                  -C:只显示指定comm的信息(Comm. 触发事件的进程名)
-S:只考虑指定符号                             -U:只显示已解析的符号
-g[type,min,order]:显示调用关系               -c:只显示指定cpu采样信息
-M:以指定汇编指令风格显示                     –source:以汇编和source的形式进行显示
-p<regex>:用指定正则表达式过滤调用函数

举例: sudo perf report -n --stdio :统计每个调用栈出现的百分比,然后从高到低排列。

可以看到,通过perf report分析得到的结果不直观,可读性比较差,所以才有了火焰图。

五 火焰图 Flame Graph

下载方式:
1、手动下载:Flame Graph项目位于GitHub上:https://github.com/brendangregg/FlameGraph
2、可以用git将其clone下来:git clone https://github.com/brendangregg/FlameGraph.git

5.1 ON-CPU火焰图

on-cpu火焰图可以用于分析cpu是被哪些线程、哪些函数占用的,可以方便的找到热点代码便于后续分析优化。

生成火焰图的操作步骤如下:

第一步: 采样并记录性能数据

$sudo perf record -e cpu-clock -g -p 28591
// Ctrl+c结束执行后,在当前目录下会生成采样数据perf.data.

第二步:用perf script工具对perf.data进行解析

perf script -i perf.data &> perf.unfold

第三步:将perf.unfold中的符号进行折叠

./stackcollapse-perf.pl perf.unfold &> perf.folded

第四步:生成svg文件

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

5.2 OFF-CPU火焰图

对于IO消耗型的任务,on-cpu并不能捕获任务大部分的时间去了哪里,配合上off-cpu的统计则可以让我们更清楚的看到任务运行时间的分布,所以off-cpu火焰图用于显示非cpu耗时的问题:

1、进程进入系统调用执行io动作,io动作的延迟;

2、进程等待mutex锁的时间

3、内存被交换,swap的时间

4、内存不够的时候,执行直接内存回收的时间

5、进程被抢占调度走、或者时间片用完被调度走的时间(runqueue太大)

// 安装off-cpu 数据获取工具
#apt install bpfcc-tools
// 截取a.out30秒offcpu 耗时分析的栈数据
sudo offcputime-bpfcc -df -p `pgrep -nx a.out` 30 > out.stacks
// 转化为火焰图
./flamegraph.pl --color=io --title="Off-CPU Time Flame Graph" --countname=us ~/out.stacks > output.svg


5.3 红蓝差分火焰图

在代码优化后,还可以使用FlameGraph工具生成红蓝差分火焰图观察优化效果。前面优化前后的采样中生成了两个.floded,对其进行对比并绘制成图。

# stackcollapse-perf.pl perf.script > workrun.floded           # 优化前数据
# stackcollapse-perf.pl perf.script > workrun_2.floded         # 优化后数据
# difffolded.pl workrun.floded workrun_2.floded > diff.floded  # 获取差异数据
flamegraph.pl diff.floded > diff.svg                           #绘图

diff.svg即为优化前后的红/蓝差分火焰图,图中使用不同的颜色来表示两个文件中的差异部分。红色表示增长, 蓝色表示衰减,并带有百分比。(这里随便贴一张图)

5.4 解析火焰图

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

火焰图中的每一个方框是一个函数,方框的长度,代表了它的执行时间,所以越宽的函数,执行越久。火焰图的楼层每高一层,就是更深一级的函数被调用,最顶层的函数,是叶子函数。

y 轴表示调用栈, 每一层都是一个函数. 调用栈越深, 火焰就越高, 顶部就是正在执行的函数, 下方都是它的父函数。x 轴表示抽样数, 如果一个函数在 x 轴占据的宽度越宽, 就表示它被抽到的次数多, 即执行的时间长. 注意, x 轴不代表时间, 而是所有的调用栈合并后, 按字母顺序排列的。

火焰图就是看顶层的哪个函数占据的宽度最大. 只要有 “平顶”(plateaus), 就表示该函数可能存在性能问题。颜色没有特殊含义, 因为火焰图表示的是 CPU 的繁忙程度, 所以一般选择暖色调.

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

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

  • 点击放大:在某一层点击,火焰图会水平放大,该层会占据所有宽度,显示详细信息。

  • 左上角会同时显示 “Reset Zoom”, 点击该链接, 图片就会恢复原样.

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

本文转载自:https://zhuanlan.zhihu.com/p/614212908