perf是linux内核自带的性能分析工具,由于其和对应的内核版本同步发布,不需要单独安装,同时功能又很强大,因此成为了笔者的主要性能分析工具。本文主要从笔者的实际使用情况出发,介绍一下perf工具的常用命令和使用场景。
perf常用参数
-C 指定统计的CPU核心编号,不指定时统计全部核心(等价于-a)
-e 指定统计事件
-p 只统计特定pid指定的进程中产生的事件
-t 只统计特定tid指定的线程中产生的事件
-K 隐藏内核中的函数符号
-U 隐藏用户态的函数符号
-g perf record工具专用的参数,记录函数的调用栈信息
其他参数可以通过man perf-top等命令查看perf工具集的手册了解。
perf list
perf list命令可以列出perf支持的内置事件列表。输出的列表如下所示:
List of pre-defined events (to be used in -e):
cpu-cycles OR cycles [Hardware event]
instructions [Hardware event]
…
cpu-clock [Software event]
task-clock [Software event]
context-switches OR cs [Software event]
…
ext4:ext4_allocate_inode [Tracepoint event]
kmem:kmalloc [Tracepoint event]
module:module_load [Tracepoint event]
workqueue:workqueue_execution [Tracepoint event]
sched:sched_{wakeup,switch} [Tracepoint event]
syscalls:sys_{enter,exit}_epoll_wait [Tracepoint event]
…
可以看到事件分为三类:Hardware event硬件事件、Software event软件事件和Tracepoint event追踪点事件。后两种事件都是由内核定义的软件事件,而硬件事件则是由CPU的PMU硬件产生的事件。由于不同的CPU支持的硬件事件各不相同,事件种类很多,因此perf不可能内置所有CPU的所有事件,只能包含主流CPU型号的常用事件。但是perf可以通过参数-e r$Umask$Event来直接指定硬件事件编号,从而统计CPU支持的任何硬件事件。在Intel的开发者手册《Intel 64 and IA-32 Architectures Software Developer’s Manual》Volume 3的19.1和19.4章节,可以查到PMU支持的所有事业参数。在手册中可以看到一些事件除了Umask和Event之外,还有cmask,inv,any等参数,这些参数直接写在umask和event前面即可。例如cmask=1,inv=1,any=1的010E事件写成-e r01A0010E即可。在开发者手册第三卷的18.2.1.1节Architectural Performance Monitoring Version1 Facilities中可以看到事件选择参数寄存器的格式定义。
perf stat
perf stat可以用于统计分析系统或者特定软件的整体执行情况。
$perf stat ./t1
Performance counter stats for './t1':
262.738415 task-clock-msecs # 0.991 CPUs
2 context-switches # 0.000 M/sec
1 CPU-migrations # 0.000 M/sec
81 page-faults # 0.000 M/sec
9478851 cycles # 36.077 M/sec (scaled from 98.24%)
6771 instructions # 0.001 IPC (scaled from 98.99%)
111114049 branches # 422.908 M/sec (scaled from 99.37%)
8495 branch-misses # 0.008 % (scaled from 95.91%)
12152161 cache-references # 46.252 M/sec (scaled from 96.16%)
7245338 cache-misses # 27.576 M/sec (scaled from 95.49%)
0.265238069 seconds time elapsed
如上图所示,在默认情况下,perf stat会统计cycles、instructions、cache-misses、context-switches等对系统或软件性能影响最大的几个硬件和软件事件。通过这些统计情况,基本上就能了解软件的运行效率是受CPU影响较大还是IO影响较大,是受运算指令数影响较大还是内存访问影响较大。通过指令数、缓存访问数等统计还能大致判断软件性能是否符合对应的功能设计,是否有代码级优化的可能。
perf top
perf top可以用于观察系统和软件内性能开销最大的函数列表。通过观察不同事件的函数列表可以分析出不同函数的性能开销情况和特点,判断其优化方向。例如如果某个函数在perf top -e instructions中排名靠后,却在perf top -e cache-misses和perf top -e cycles中排名靠前,说明函数中存在大量cache-miss造成CPU资源占用较多,就可以考虑优化该函数中的内存访问次数和策略,来减少内存访问和cache-miss次数,从而降低CPU开销。
在较新的内核版本中,perf top还可以深入到函数对应的汇编指令中,明确指出是哪些指令占用了计算资源,可以非常明确的指明软件性能热点。
perf record和perf report
perf record一般和perf report搭配使用。perf record可以记录系统或软件一段时间内的事件统计情况,再通过perf report进行文本界面的展示。使用perf record可以将时间段内的情况记录下来,进行整个时段的分析,或者复制到其他设备上做后续分析,这是其他命令不支持的。perf record还有一个特别的参数-g,可以支持记录函数的调用关系。使用这个参数,就不止能够看到性能开销高的函数列表,还能看到这些函数是如何被调用和使用的。在很多情况下,性能开销高的函数都是memcpy之类的系统基础函数,其本身是没有什么优化空间的,能够优化的是调用memcpy的方式和次数。通过perf record -g就能够分析出这些函数的调用关系,从而找到真正需要优化的代码位置。