Linux Perf 工具使用介绍

2023-08-01 language

Perf 全名是 Performance Event,在 Linux 2.6.31 以后内建的系统性能分析工具,由内核社区维护和发展,不仅可以用于应用程序的性能统计分析,也可以应用于内核代码的性能统计和分析。

这里简单介绍。

简介

Perf 是一款随 Linux 内核代码一同发布和维护的性能诊断工具,由内核社区维护和发展,不仅可以用于应用程序的性能统计分析,也可以应用于内核代码的性能统计和分析。

性能调优工具如 PerfOprofile 等的基本原理都是对被监测对象进行采样,最简单的情形是根据 tick 中断进行采样,即在 tick 中断内触发采样点,在采样点里判断程序当时的上下文。

假如一个程序 90% 的时间都花费在函数 foo() 上,只要采样足够多,那么通常来说 90% 的采样点都应该落在函数 foo() 的上下文中。

相对 OProfileGProf 来说,perf 的优势在于和内核紧密结合。

安装

首先确认内核是否支持。

$ cat "/boot/config-`uname -r`" | grep "PERF_EVENTS"
CONFIG_PERF_EVENTS_INTEL_UNCORE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_PERF_EVENTS=y
CONFIG_HAVE_PERF_EVENTS_NMI=y

可以通过发行版本的包管理工具进行安装。

----- CentOS
# yum install perf
----- Debain
# apt-get install linux-perf

或者在内核源码 tools/perf 目录下通过 make && make install 进行编译安装,安装时不需要 root,将安装在 home 目录下。

常用命令

相关的 perf 命令通过 perf <subcmd> 执行,大概有二十多个子命令,可通过 pref help [subcmd] 查看,其中最常用的有 liststattoprecordreport 等。

帮助文档也可以通过 man perf 或者 man perf-top 类似命令查看。

list

通过 list 子命令可以查看当前机器支持的事件,默认会打印所有支持事件,可以通过添加子集过滤所需要的事件,如 hwswcachetracepointpmuevent_glob 等,更多通过 perf list --help 命令查看。

所有的 perf 源可以统称为 perf_events,不同的系统支持的功能不同,大致可以分为如下三类:

  • Hardware Event 由 Performance Monitoring Unit, PMU 硬件产生的事件,比如 CacheMiss、BranchMiss 等,当需要了解程序对硬件特性的使用情况时,便需要对这些事件进行采样;
  • Software Event 是内核软件产生的事件,与硬件无关,比如 ContextSwitches、PageFaults 等;
  • Tracepoint Event 由内核中静态 Tracepoint 所触发的事件,基于 ftrace 用来判断程序运行期间内核的行为细节,比如 slab 分配器的分配次数等。

注意,很多情况下虚机上是无法支持的。

如下是常用命令。

----- 查看与调度相关的 Tracepoint 事件
# perf list sched
# perf list 'sched:*'
----- 也可以简单过滤
$ perf list | grep stalled
  stalled-cycles-frontend OR idle-cycles-frontend    [Hardware event]
  stalled-cycles-frontend OR cpu/stalled-cycles-frontend/ [Kernel PMU event]
----- 通过 debugfs 查看也可以
$ ls /sys/devices/cpu/events/
branch-instructions  bus-cycles    cache-references  instructions  mem-stores
branch-misses        cache-misses  cpu-cycles        mem-loads     stalled-cycles-frontend

$ cat /sys/bus/event_source/devices/cpu/events/stalled-cycles-frontend
event=0x0e,umask=0x01,inv,cmask=0x01

stat/record

可以简单查看某个程序执行的开销,或者先将采样数据保存下来再事后分析。

----- 某个进程的指标采集,可以通过-p <PID>指定正在运行的进程
# perf stat sleep 5
 Performance counter stats for 'sleep 5':

              0.36 msec task-clock                #    0.000 CPUs utilized          
                 1      context-switches          #    0.003 M/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                68      page-faults               #    0.188 M/sec                  
   <not supported>      cycles                                                      
   <not supported>      instructions                                                
   <not supported>      branches                                                    
   <not supported>      branch-misses                                               

       5.000664745 seconds time elapsed

       0.000630000 seconds user
       0.000000000 seconds sys

各个统计信息如下。

  • task-clock(msec) 占用时钟周期,该值高说明程序的多数时间花费在 CPU 计算上而非 IO 上。
  • context-switches 发生了多少次上下文切换,应该尽量避免频繁的进程切换。
  • cpu-migrations 发生了多少次 CPU 迁移。

或者通过 record 记录下采集事件,相关的参数有:

  • -F 每秒采集事件数
  • -g 记录程序的调用栈
  • -p/t 指定运行的进程或者线程ID
  • -e 只记录指定的事件列表
  • -a 采集所有 CPU 信息
  • -f 强制覆盖 perf.data 文件
  • -o 默认输出为 perf.data 文件,可以重新指定

例如。

----- 记录程序执行
perf record -F 99 -ag -- sleep 60
perf record -F 99 -ag -p PID

----- 记录指定的事件
perf record -e block:block_rq_issue -ag

然后可以通过 report 命令查看。

top

实时查看当前系统的统计信息。

----- 实时显示当前系统TopN进程、函数,通过-e指定关注的指标,默认是CPU
# perf top -e cache-misses
----- 显示消耗最多CPU周期的函数
# perf top -e cycles:k
----- 显示分配高速缓存最多的函数:
# perf top -e kmem:kmem_cache_alloc

常用参数有:

  • -e 指定性能事件。
  • -a/C 显示在所有或者指定 CPU 上的性能统计信息。
  • -p/-t 指定进程或者线程 ID 。
  • -K/U 隐藏内核或者用户空间的统计信息。

bench

包含一些基础的压册工具,可以通过 perf bench 查看所有支持的分类,如下是常用命令。

----- 内存压测
# perf bench mem memcpy
# perf bench mem memset

其它

----- 查看两个的性能对比
# perf diff new old

----- 整理的统计指标,可能会出现not supported
# perf stat program args
# perf stat dd if=/dev/zero of=test.iso bs=10M count=1
输出指标:
  task-clock       运行时占用CPU的时钟周期,可以判定CPU/IO Bound;
  context-switches 上下文切换次数,包括了进程间切换以及内核态和用户态的切换;
  cpu-migrations   运行期间发生CPU迁移次数,也即从一个CPU运行切换到另外的CPU;
  page-faults      程序发生了缺页异常的次数。

----- 通过record+report统计程序性能TOP指标
# perf record -e cpu-clock -ag program args
# perf stat dd if=/dev/zero of=test.iso bs=10M count=1
参数:
  -a           统计所有的CPU;
  -g           记录函数的调用关系,也即调用栈;
  -e cpu-clock 监控的指标为CPU调用周期;
# perf report -i perf.data

火焰图

通过火焰图可以有效观察资源消耗在那,不重要的会自然淡化甚至消失,而真正重要的代码路径则会突显,从而提供恰到好处的信息,不多也不少。

大部分的文章基本都是源自 Flame Graphs 中的介绍,可以从 Github FlameGraph 下载相关的脚本。

然后通过如下命令生成火焰图。

----- 记录Perf事件,其中-F指定频率,-p 指定进程ID
# perf record -F 99 -ag -p <PID>
----- 对采集数据进行解析,这样可以直接复制到本地机器处理
# perf script -i perf.data > perf.unfold
----- 将符号进行折叠
# FlameGraph/stackcollapse-perf.pl perf.unfold > perf.folded
----- 最后生成火焰图
# FlameGraph/flamegraph.pl perf.folded > perf.svg

如果出现 Unknown 问题,可以在 record 时增加 --call-graph dwarf 参数。

其它

源码解析

如上所述,源码在内核的 tools/perf 目录下,其中入口在 main()@perf.c,会根据子命令调用不同的函数,如 cmd_list()@builtin-list.ccmd_stat()@builtin-stat.c 等。

例如 perf list 对应 cmd_list() 函数,该函数依赖 debugfs,详见 tracing/events 目录下内容。

参考

  • Perf Wiki Linux 内核官方的文档。
  • Perf Examples 性能优化大神 Brendan Gregg’s 示例。
  • Perf Tools 同样是 Brendan Greeg’s 开发的一些常用 Perf 工具。