perf实用指南

perf简介

perf命令原名为Linux性能计数器(Performanc Counters for Linux,PCL),已经演化成为一整套剖析和跟踪的工具,现名为LInux性能事件(Linux Performance Events,LPE)。每个工具分别作为一个子命令,例如,perf stat执行stat命令,提供基于CPC的统计信息。perf可以跟踪到进程内部具体函数耗时情况,并可以指定内核函数进行统计。

perf实用指南

perf安装

# yum安装
yum install -y perf

# 编译安装,perf在内核源码的tools/perf中,下载与内核版本一致的内核源码即可
uname -a 
yum install -y gcc make bison flex elfutils libelf-dev libdw-dev libaudit-dev python-dev binutils-dev
wget https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.10.104.tar.xz
tar -xvf linux-3.10.104.tar.xz
cd linux-3.10.104/tools/perf/
make

perf子命令

命令描述

annotate

读取perf.data(由perf record创建)并显示注释过的代码

diff

读取两个perf.data文件并显示两份剖析信息之间的差异

evlist

列出一个perf.data文件里的事件名称

inject

过滤以加强事件流,在其中加入额外的信息

kmem

跟踪/测量内核内存(slab)属性的工具

kvm

跟踪/测量kvm客户机操作系统的工具

list

列出所有的符号事件类型,其中性能事件的包括:Hardware event、Software event、Hardware cache event、tracepoint:Tracepoint event
Hardware Event 是由 PMU 硬件产生的事件,比如 cache 命中,当您需要了解程序对硬件特性的使用情况时,便需要对这些事件进行采样;
Software Event 是内核软件产生的事件,比如进程切换,tick 数等 ;
Tracepoint event 是内核中的静态 tracepoint 所触发的事件,这些 tracepoint 用来判断程序运行期间内核的行为细节,比如 slab 分配器的分配次数,系统调用,TCP事件,文件系统IO事件,块设备事件等。

lock

分析锁事件

probe

定义新的动态跟踪点

record

运行一个命令,收集采样信息,并把剖析信息记录在perf.data中

report

读取perf.data(由perf record创建)并显示剖析信息

sched

跟踪/测量调度器属性(延时)的工具

script

读取perf.data(由perf record创建)并显示跟踪输出

stat

运行一个命令并收集性能计数器统计信息,用于分析指定程序的性能概况。

task-clock:任务真正占用的处理器时间,单位为ms。
context-switches:上下文的切换次数。
CPU-migrations:处理器迁移次数。Linux为了维持多个处理器的负载均衡,在特定条件下会将某个任务从一个CPU迁移到另一个CPU。
page-faults:缺页异常的次数。当应用程序请求的页面尚未建立、请求的页面不在内存中,或者请求的页面虽然在内存中,但物理地址和虚拟地址的映射关系尚未建立时,都会触发一次缺页异常。
cycles:消耗的处理器周期数。
instructions:执行了多少条指令。IPC为平均每个cpu cycle执行了多少条指令。
branches:遇到的分支指令数。branch-misses是预测错误的分支指令数。

timechart

可视化某一个负载期间系统总体性能的工具

top

系统剖析工具。对于一个指定的性能事件(默认是CPU周期),显示消耗最多的函数或指令。perf top类似linux的top命令,可以排列展示当机的函数和指令消耗情况。perf top主要用于实时分析各个函数在某个性能事件上的热度,能够快速的定位热点函数,包括应用程序函数、模块函数与内核函数,甚至能够定位到热点指令。默认的性能事件为cpu cycles。
结果展示:
第一列:符号引发的性能事件的比例,默认指占用的cpu周期比例。
第二列:符号所在的DSO(Dynamic Shared Object),可以是应用程序、内核、动态链接库、模块。
第三列:DSO的类型。[.]表示此符号属于用户态的ELF文件,包括可执行文件与动态链接库)。[k]表述此符号属于内核或模块。
第四列:符号名。有些符号不能解析为函数名,只能用地址表示。

perf使用

系统剖析

perf可以用来剖析cpu调用路径,对cpu时间如何消耗在内核和用户空间进行概括总结。这项工作由record命令完成,该命令以一定间隔进行取样,并导出到一个perf.data文件,然后使用report命令查看文件。

在下面的例子里,所有的cpu(-a)以997Hz的频率(-F 997)对调用栈(-g)取样10s(sleep 10)。选项--stdio用来打印所有的输出,而非采用默认的交互模式操作。

perf实用指南

完整的的输出长达多页,按照取样计数逆序排列。这些取样计数以百分数输出,展示了cpu时间的运算。这个例子中,72.98%的时间花在空闲线程,9.43%的时间花在dd进程。而在这9.43%时间中,87.5%的时间花在上面所示的栈中,函数为ext4_file_write()。

这些内核和进程符号只在它们的调试信息文件存在的情况下可用,否则只显示十六进制地址。

perf通过给cpu周期计数器设置一个溢出中断实现。由于现在处理器上的周期频率不断变化,因此使用了一个“按比例缩放的”常数计数器。

进程剖析

除了剖析系统里的所有cpu,我们也可以对单个进程进程剖析。下面的命令执行了command并创建文件perf.data:

# perf record -g command

和之前一样,perf需要调试信息文件,这样在查看报告时可以进行符号转译。

调度器延时

sched命令记录并报告调度器统计信息。例如:

perf实用指南

上面显示了跟踪时期平均和最大的调度器延时。

调度器事件较为频繁,因此此类跟踪会导致cpu和存储的开销。本例中的perf.data文件即为跟踪10s的产物,大小达到了1.7GB。输出中的INFO行表示有些事件被丢弃了。这凸显了DTrace在内核中过滤和聚合模型的优势:它可以在跟踪时汇总数据并只把汇总结果传递给用户空间,把开销最小化。

stat

stat命令基于cpc为cpu周期行为提供了一个概要总结。下面的例子里它启动了gzip命令:

perf实用指南统计信息包括了周期的指令计数,以及IPC(CPI的倒数)。和前面描述的一样,这是一个对判断周期类型以及其中有多少停滞周期非常有用的概要指标。

下面列出了其他可以检查的计数器:

perf实用指南

注意其中的”Hardware event“和”Hardware cache event“。这些是否可用取决于处理器的架构,并在处理器手册中有记录(例如,Intel软件开发者手册)。

这些事件可以使用选项-e指定。例如(来自Intel Xeon):

perf实用指南

除了指令和周期之外,这个例子还测量了以下几个方面:

  • L1-dcache-load-misses:一级数据缓存负载未命中。这大概可以看出应用程序施加的内存负载,其中有一部分负载从一级缓存返回。可以与其他L1事件计数器进行对比以确定缓存命中率。

  • LLC-load-misses:末级缓存负载未命中。在末级缓存之后,就会直接存取主存,因此这实际测量了主存负载。从它与L1-dcache-load-missed之间的区别,可以大概看出(还需要其他计数器以确保完整性),除一级CPU缓存之外其他缓存的有效性。

  • dTLB-load-misses:数据转译后备缓冲器未命中。它展示了MMU为负载缓存页面映射的有效性,可以用来测量内存负载的大小(工作集)。

还有许多其他计数器可待查验。perf支持描述名(与这个例子里使用的一样)和十六进制值。后者可以在查看处理器手册中发现神秘计数器时派上用场,此类计数器一般没有描述名。

软件跟踪

perf record -e可以与各种软件性能测量点配合,用来跟踪内核调度器的活动。这些测量点包括了软件事件和跟踪点事件(静态探测器),由perf list列出。例如:

perf实用指南下面的例子使用上下文切换软件事件,以在应用程序离开cpu时进行跟踪,并收集了10s的调用栈:

perf实用指南这份截取的输出显示了两个应用程序,perl和tar,以及它们上下文切换时的调用栈。看看这个栈就能发现tar程序在文件系统(ext4)读的时候睡眠。而perl程序由于执行密集计算,进行了非自愿性上下文切换,尽管仅从这份输出并不能得出此结论。

使用sched跟踪点事件可以发现更多的信息。还可以使用动态跟踪点(动态跟踪)直接跟踪内核调度器函数,与静态探测器结合使用可以提供与前面DTrace类似的数据,虽然这可能需要更多的事后处理工作以得出预期结果。

第9章包含了另一个使用perf进行静态跟踪的例子。第10章中有一个使用perf动态跟踪tcp_sendmsg()内核函数的例子。

perf 静态跟踪

Linux上的工具perf提供了块跟踪点,可以用这些跟踪点来跟踪一些基本信息。这些跟踪点如下:

# perf list | grep block:
 block:block_bio_backmerge                          [Tracepoint event]
 block:block_bio_bounce                             [Tracepoint event]
 block:block_bio_complete                           [Tracepoint event]
 block:block_bio_frontmerge                         [Tracepoint event]
 block:block_bio_queue                              [Tracepoint event]
 block:block_getrq                                  [Tracepoint event]
 block:block_plug                                   [Tracepoint event]
 block:block_remap                                  [Tracepoint event]
 block:block_rq_abort                               [Tracepoint event]
 block:block_rq_complete                            [Tracepoint event]
 block:block_rq_insert                              [Tracepoint event]
 block:block_rq_issue                               [Tracepoint event]
 block:block_rq_remap                               [Tracepoint event]
 block:block_rq_requeue                             [Tracepoint event]
 block:block_sleeprq                                [Tracepoint event]
 block:block_split                                  [Tracepoint event]
 block:block_unplug_io                              [Tracepoint event]
 block:block_unplug_timer                           [Tracepoint event]

举个例子,为检查调用栈,用调用图来跟踪块设备问题。命令sleep 10用来作为跟踪的持续时间。

perf实用指南perf实用指南输出长达数页,展示了产生块设备I/O的不同代码路径。这里给出的部分是ext4的目录读取。

perf 动态跟踪

使用perf创建内核tcp_sendmsg()函数的动态跟踪点,然后跟踪它五秒并显示调用图(栈跟踪):

# perf probe --add='tcp_sendmsg'
Added new event:
 probe:tcp_sendmsg    (on tcp_sendmsg)

You can now use it in all perf tools, such as:

perf record -e probe:tcp_sendmsg -aR sleep 1

# perf record -e probe:tcp_sendmsg -aR sleep 30
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.429 MB perf.data (89 samples) ]

# perf report --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
# Samples: 89  of event 'probe:tcp_sendmsg'
# Event count (approx.): 89
#
# Overhead  Command    Shared Object      Symbol
# ........  .........  .................  ...............
#
   97.75%  nginx      [kernel.kallsyms]  [k] tcp_sendmsg
    1.12%  AliYunDun  [kernel.kallsyms]  [k] tcp_sendmsg
    1.12%  sshd       [kernel.kallsyms]  [k] tcp_sendmsg


#
# (For a higher level overview, try: perf report --sort comm,dso)
#

输出显示nginx的栈跟踪,它导致内核调用tcp_sendmsg()并由TCP连接发送数据。还有一些预定义的网络跟踪点事件,如下所示:

# perf list
[...]
skb:consume_skb                                    [Tracepoint event]
skb:kfree_skb                                      [Tracepoint event]
skb:skb_copy_datagram_iovec                        [Tracepoint event]
net:net_dev_queue                                  [Tracepoint event]
net:net_dev_xmit                                   [Tracepoint event]
net:netif_receive_skb                              [Tracepoint event]
net:netif_rx                                       [Tracepoint event]

skb跟踪点用于套接字缓存事件,而net用于网络设备。这些也有助于网络调查。

perf火焰图

perf的数据可以进一步被加工为火焰图,这需要其他工具的支持,flameGap这个开源项目(https://github.com/brendangregg/FlameGraph.git)很不错,里面有很多的perl脚本。使用perf report -tui或者-stdio输出的文本不够直观的话,使用火焰图可以很直观的表现出哪些代码是瓶颈所在。

压测
$pgbench -M prepared -n -r -P 1 -c 32 -j 32 -T 100

收集统计信息
#perf record -a -g -v sleep 30

生成火焰图

# git clone https://github.com/brendangregg/FlameGraph      # or download it from github
# mv perf.data FlameGraph/
# cd FlameGraph
# perf script | ./stackcollapse-perf.pl > out.perf-folded
# cat out.perf-folded | ./flamegraph.pl > perf-kernel.svg

或者通过如下命令:

perf record -g ls

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

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

./stackcollapse-perf.pl perf.unfold >perf.svg

就可以得到截图中的perf.svg矢量图片了。

绘制perf热力图

压测
$pgbench -M prepared -n -r -P 1 -c 32 -j 32 -T 100

收集统计信息
#perf record -a -g -v sleep 30

生成热力图

# git clone https://github.com/brendangregg/HeatMap      # or download it from github
# mv perf.data HeatMap/
# cd HeatMap
# perf script | awk '{ gsub(/:/, "") } $5 ~ /issue/ { ts[$6, $10] = $4 }
   $5 ~ /complete/ { if (l = ts[$6, $9]) { printf "%.f %.f\n", $4 * 1000000,
   ($4 - l) * 1000000; ts[$6, $10] = 0 } }' > out.lat_us
# ./trace2heatmap.pl --unitstime=us --unitslat=us --maxlat=50000 out.lat_us > out.svg

perf常用命令

# 输出当前内核perf支持的预置events
perf list

# 跟踪进程内部函数级cpu使用情况
perf top -p pid -e cpu-clock
perf top -agv/-p
perf top -g -p pid
perf record -ag sleep 30;perf report


# 查看系统IO的请求,查找是什么原因导致的IO异常
perf record -e block:block_rq_issue -ag
perf report

# 解读前面收集到的perf.data
perf report -p pid
perf record -agv
perf record -e xxx -p pid
perf report -i perf.data

# 解读前面收集到的perf.data,辅以汇编指令显示。
perf annotate

# 生成火焰图
perf-script -Read perf.data

perf list | awk -F: '/Tracepoint event/ { lib[$1]++ } END {for (l in lib) { printf "  %-16s %d\n", l, lib[l] } }' | sort | column



参考:

anzhihe 安志合个人博客,版权所有 丨 如未注明,均为原创 丨 转载请注明转自:https://chegva.com/3464.html | ☆★★每天进步一点点,加油!★★☆ | 

您可能还感兴趣的文章!

1 评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注