系统级性能分析工具perf的介绍与使用

时间:2023-12-14 16:43:08

测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题)

Kernel:3.13.0-32

系统级性能优化通常包括两个阶段:性能剖析(performance profiling)和代码优化。性能剖析的目标是寻找性能瓶颈,查找引发性能问题的原因及热点代码。代码优化的目标是针对具体性能问题而优化代码或编译选项,以改善软件性能。

在性能剖析阶段,需要借助于现有的profiling工具,如perf等。在代码优化阶段往往需要借助开发者的经验,编写简洁高效的代码,甚至在汇编级别合理使用各种指令,合理安排各种指令的执行顺序。

perf是一款Linux性能分析工具。Linux性能计数器是一个新的基于内核的子系统,它提供一个性能分析框架,比如硬件(CPU、PMU(Performance Monitoring Unit))功能和软件(软件计数器、tracepoint)功能。
通过perf,应用程序可以利用PMU、tracepoint和内核中的计数器来进行性能统计。它不但可以分析制定应用程序的性能问题(per thread),也可以用来分析内核的性能问题,当然也可以同事分析应用程序和内核,从而全面理解应用程序中的性能瓶颈。

使用perf,可以分析程序运行期间发生的硬件事件,比如instructions retired、processor clock cycles等;也可以分析软件时间,比如page fault和进程切换。

背景知识

tracepoints

tracepoints是散落在内核源码中的一些hook,它们可以在特定的代码被执行到时触发,这一特定可以被各种trace/debug工具所使用。

perf将tracepoint产生的时间记录下来,生成报告,通过分析这些报告,条有人缘便可以了解程序运行期间内核的各种细节,对性能症状做出准确的诊断。

硬件特性之cache

内存读写是很快的,但是还是无法和处理器指令执行速度相比。为了从内存中读取指令和数据,处理器需要等待,用处理器时间来衡量,这种等待非常漫长。cache是一种SRAM,读写速度非常快,能和处理器相匹配。因此将常用的数据保存在cache中,处理器便无需等待,从而提高性能。cache的尺寸一般都很小,充分利用cache是软件调优非常重要部分。

主要关注点

基于性能分析,可以进行算法优化(空间复杂度和时间复杂度权衡)、代码优化(提高执行速度、减少内存占用)。

评估程序对硬件资源的使用情况,例如各级cache的访问次数、各级cache的丢失次数、流水线停顿周期、前端总线访问次数等。

评估程序对操作系统资源的使用情况,系统调用次数、上下文切换次数、任务迁移次数。

事件可以分为三种:

  1. Hardware Event由PMU部件产生,在特定的条件下探测性能事件是否发生以及发生的次数。比如cache命中。
  2. Software Event是内核产生的事件,分布在各个功能模块中,统计和操作系统相关性能事件。比如进程切换,tick数等。
  3. Tracepoint Event是内核中静态tracepoint所触发的事件,这些tracepoint用来判断程序运行期间内核的行为细节,比如slab分配器的分配次数等。

perf的使用

perf --help之后可以看到perf的二级命令。

序号 命令 作用
1 annotate 解析perf record生成的perf.data文件,显示被注释的代码。
2 archive 根据数据文件记录的build-id,将所有被采样到的elf文件打包。利用此压缩包,可以再任何机器上分析数据文件中记录的采样数据。
3 bench perf中内置的benchmark,目前包括两套针对调度器和内存管理子系统的benchmark。
4 buildid-cache 管理perf的buildid缓存,每个elf文件都有一个独一无二的buildid。buildid被perf用来关联性能数据与elf文件。
5 buildid-list 列出数据文件中记录的所有buildid。
6 diff 对比两个数据文件的差异。能够给出每个符号(函数)在热点分析上的具体差异。
7 evlist 列出数据文件perf.data中所有性能事件。
8 inject 该工具读取perf record工具记录的事件流,并将其定向到标准输出。在被分析代码中的任何一点,都可以向事件流中注入其它事件。
9 kmem 针对内核内存(slab)子系统进行追踪测量的工具
10 kvm 用来追踪测试运行在KVM虚拟机上的Guest OS。
11 list 列出当前系统支持的所有性能事件。包括硬件性能事件、软件性能事件以及检查点。
12 lock 分析内核中的锁信息,包括锁的争用情况,等待延迟等。
13 mem 内存存取情况
14 record 收集采样信息,并将其记录在数据文件中。随后可通过其它工具对数据文件进行分析。
15 report 读取perf record创建的数据文件,并给出热点分析结果。
16 sched 针对调度器子系统的分析工具。
17 script 执行perl或python写的功能扩展脚本、生成脚本框架、读取数据文件中的数据信息等。
18 stat 执行某个命令,收集特定进程的性能概况,包括CPI、Cache丢失率等。
19 test perf对当前软硬件平台进行健全性测试,可用此工具测试当前的软硬件平台是否能支持perf的所有功能。
20 timechart 针对测试期间系统行为进行可视化的工具
21 top 类似于linux的top命令,对系统性能进行实时分析。
22 trace 关于syscall的工具。
23 probe 用于定义动态检查点。

下面开始逐一分析。

perf list

perf list不能完全显示所有支持的事件类型,需要sudo perf list。

同时还可以显示特定模块支持的perf事件,hw/cache/pmu都是硬件相关的;tracepoint基于内核的ftrace;sw实际上是内核计数器。

hw/hardware显示支持的硬件事件相关,如:

al@ubuntu:~/common-use/example/perf-test$ perf list hardware
  cpu-cycles OR cycles                               [Hardware event]
  instructions                                       [Hardware event]
  cache-references                                   [Hardware event]
  cache-misses                                       [Hardware event]
  branch-instructions OR branches                    [Hardware event]
  branch-misses                                      [Hardware event]
  stalled-cycles-frontend OR idle-cycles-frontend    [Hardware event]
  stalled-cycles-backend OR idle-cycles-backend      [Hardware event]

sw/software显示支持的软件事件列表:

al@ubuntu:~/common-use/example/perf-test$ perf list sw
  cpu-clock                                          [Software event]
  task-clock                                         [Software event]
  page-faults OR faults                              [Software event]
  context-switches OR cs                             [Software event]
  cpu-migrations OR migrations                       [Software event]
  minor-faults                                       [Software event]
  major-faults                                       [Software event]
  alignment-faults                                   [Software event]
  emulation-faults                                   [Software event]
  dummy                                              [Software event]

cache/hwcache显示硬件cache相关事件列表:

al@ubuntu:~/common-use/example/perf-test$ perf list cache
  L1-dcache-loads                                    [Hardware cache event]
  L1-dcache-load-misses                              [Hardware cache event]
  L1-dcache-stores                                   [Hardware cache event]
  L1-dcache-prefetches                               [Hardware cache event]
  L1-dcache-prefetch-misses                          [Hardware cache event]
  L1-icache-loads                                    [Hardware cache event]
  L1-icache-load-misses                              [Hardware cache event]
  L1-icache-prefetches                               [Hardware cache event]
  LLC-loads                                          [Hardware cache event]
  LLC-load-misses                                    [Hardware cache event]
  LLC-stores                                         [Hardware cache event]
  dTLB-loads                                         [Hardware cache event]
  dTLB-load-misses                                   [Hardware cache event]
  iTLB-loads                                         [Hardware cache event]
  iTLB-load-misses                                   [Hardware cache event]
  branch-loads                                       [Hardware cache event]
  branch-load-misses                                 [Hardware cache event]
  node-loads                                         [Hardware cache event]
  node-load-misses                                   [Hardware cache event]

pmu显示支持的PMU事件列表:

al@ubuntu:~/common-use/example/perf-test$ perf list pmu
  branch-instructions OR cpu/branch-instructions/    [Kernel PMU event]
  branch-misses OR cpu/branch-misses/                [Kernel PMU event]
  cache-misses OR cpu/cache-misses/                  [Kernel PMU event]
  cache-references OR cpu/cache-references/          [Kernel PMU event]
  cpu-cycles OR cpu/cpu-cycles/                      [Kernel PMU event]
  instructions OR cpu/instructions/                  [Kernel PMU event]

tracepoint显示支持的所有tracepoint列表,这个列表就比较庞大:

drm:drm_vblank_event                               [Tracepoint event]
drm:drm_vblank_event_queued                        [Tracepoint event]
drm:drm_vblank_event_delivered                     [Tracepoint event]
skb:kfree_skb                                      [Tracepoint event]
skb:consume_skb                                    [Tracepoint event]
skb:skb_copy_datagram_iovec                        [Tracepoint event]
net:net_dev_xmit                                   [Tracepoint event]
net:net_dev_queue                                  [Tracepoint event]
net:netif_receive_skb                              [Tracepoint event]
net:netif_rx                                       [Tracepoint event]
napi:napi_poll                                     [Tracepoint event]

perf top

默认情况下perf top是无法显示信息的,需要sudo perf top或者echo -1 > /proc/sys/kernel/perf_event_paranoid(在Ubuntu16.04,还需要echo 0 > /proc/sys/kernel/kptr_restrict)。

即可以正常显示perf top如下:

第一列:符号引发的性能事件的比例,指占用的cpu周期比例。

第二列:符号所在的DSO(Dynamic Shared Object),可以是应用程序、内核、动态链接库、模块。

第三列:DSO的类型。[.]表示此符号属于用户态的ELF文件,包括可执行文件与动态链接库)。[k]表述此符号属于内核或模块。

第四列:符号名。有些符号不能解析为函数名,只能用地址表示。

系统级性能分析工具perf的介绍与使用

关于perf top界面常用命令如下:

h:显示帮助,即可显示详细的帮助信息。

UP/DOWN/PGUP/PGDN/SPACE:上下和翻页。

a:annotate current symbol,注解当前符号。能够给出汇编语言的注解,给出各条指令的采样率。

d:过滤掉所有不属于此DSO的符号。非常方便查看同一类别的符号。

P:将当前信息保存到perf.hist.N中。

perf top常用选项有:

-e <event>:指明要分析的性能事件。

-p <pid>:Profile events on existing Process ID (comma sperated list). 仅分析目标进程及其创建的线程。

-k <path>:Path to vmlinux. Required for annotation functionality. 带符号表的内核映像所在的路径。

-K:不显示属于内核或模块的符号。

-U:不显示属于用户态程序的符号。

-d <n>:界面的刷新周期,默认为2s,因为perf top默认每2s从mmap的内存区域读取一次性能数据。

-g:得到函数的调用关系图。

perf top -g [fractal],路径概率为相对值,加起来为100%,调用顺序为从下往上。

perf top -g graph,路径概率为绝对值,加起来为该函数的热度。

perf stat

perf stat用于运行指令,并分析其统计结果。虽然perf top也可以指定pid,但是必须先启动应用才能查看信息。

perf stat能完整统计应用整个生命周期的信息。

命令格式为:

perf stat [-e <EVENT> | --event=EVENT] [-a] <command>
perf stat [-e <EVENT> | --event=EVENT] [-a] — <command> [<options>]

下面简单看一下perf stat ls的输出:

 Performance counter stats for 'ls':

          1.051536      task-clock (msec)         #    0.670 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                93      page-faults               #    0.088 M/sec                  
         1,942,492      cycles                    #    1.847 GHz                    
           532,500      stalled-cycles-frontend   #   27.41% frontend cycles idle   
           724,600      stalled-cycles-backend    #   37.30% backend  cycles idle   
     <not counted>      instructions               (0.00%)
     <not counted>      branches                   (0.00%)
     <not counted>      branch-misses              (0.00%)

       0.001569326 seconds time elapsed

task-clock:任务真正占用的处理器时间,单位为ms。CPUs utilized = task-clock / time elapsed,CPU的占用率。

context-switches:程序在运行过程中上下文的切换次数。

CPU-migrations:程序在运行过程中发生的处理器迁移次数。Linux为了维持多个处理器的负载均衡,在特定条件下会将某个任务从一个CPU迁移到另一个CPU。

CPU迁移和上下文切换:发生上下文切换不一定会发生CPU迁移,而发生CPU迁移时肯定会发生上下文切换。发生上下文切换有可能只是把上下文从当前CPU中换出,下一次调度器还是将进程安排在这个CPU上执行。

page-faults:缺页异常的次数。当应用程序请求的页面尚未建立、请求的页面不在内存中,或者请求的页面虽然在内存中,但物理地址和虚拟地址的映射关系尚未建立时,都会触发一次缺页异常。另外TLB不命中,页面访问权限不匹配等情况也会触发缺页异常。

cycles:消耗的处理器周期数。如果把被ls使用的cpu cycles看成是一个处理器的,那么它的主频为2.486GHz。可以用cycles / task-clock算出。

stalled-cycles-frontend:指令读取或解码的质量步骤,未能按理想状态发挥并行左右,发生停滞的时钟周期。

stalled-cycles-backend:指令执行步骤,发生停滞的时钟周期。

instructions:执行了多少条指令。IPC为平均每个cpu cycle执行了多少条指令。

branches:遇到的分支指令数。branch-misses是预测错误的分支指令数。

其他常用参数

-a, --all-cpus        显示所有CPU上的统计信息
    -C, --cpu <cpu>       显示指定CPU的统计信息
    -c, --scale           scale/normalize counters
    -D, --delay <n>       ms to wait before starting measurement after program start
    -d, --detailed        detailed run - start a lot of events
    -e, --event <event>   event selector. use 'perf list' to list available events
    -G, --cgroup <name>   monitor event in cgroup name only
    -g, --group           put the counters into a counter group
    -I, --interval-print <n>
                          print counts at regular interval in ms (>= 10)
    -i, --no-inherit      child tasks do not inherit counters
    -n, --null            null run - dont start any counters
    -o, --output <file>   输出统计信息到文件
    -p, --pid <pid>       stat events on existing process id
    -r, --repeat <n>      repeat command and print average + stddev (max: 100, forever: 0)
    -S, --sync            call sync() before starting a run
    -t, --tid <tid>       stat events on existing thread id
    -T, --transaction     hardware transaction statistics
    -v, --verbose         be more verbose (show counter open errors, etc)
    -x, --field-separator <separator>
                          print counts with custom separator
        --append          append to the output file
        --filter <filter>
                          event filter
        --log-fd <n>      log output to fd, instead of stderr
        --per-core        aggregate counts per physical processor core
        --per-socket      aggregate counts per processor socket
        --per-thread      aggregate counts per thread
        --post <command>  执行待测程序前执行的程序
        --pre <command>   执行待测程序后执行的程序

示例

前面统计程序的示例,下面看一下统计CPU信息的示例:

执行sudo perf stat -C 0,统计CPU 0的信息。想要停止后,按下Ctrl+C终止。可以看到统计项一样,只是统计对象变了。

 Performance counter stats for 'CPU(s) 0':

      10164.997531      task-clock (msec)         #    1.000 CPUs utilized            (100.00%)
             1,147      context-switches          #    0.113 K/sec                    (100.00%)
                62      cpu-migrations            #    0.006 K/sec                    (100.00%)
                76      page-faults               #    0.007 K/sec                  
       353,147,998      cycles                    #    0.035 GHz                      (49.97%)
        55,541,309      stalled-cycles-frontend   #   15.73% frontend cycles idle     (50.00%)
     1,163,503,673      stalled-cycles-backend    #  329.47% backend  cycles idle     (50.04%)
        51,713,115      instructions              #    0.15  insns per cycle        
                                                  #   22.50  stalled cycles per insn  (50.04%)
        10,334,910      branches                  #    1.017 M/sec                    (50.00%)
         1,980,209      branch-misses             #   19.16% of all branches          (49.96%)

      10.163701471 seconds time elapsed

如果需要统计更多的项,需要使用-e,如:

perf stat -e task-clock,context-switches,cpu-migrations,page-faults,cycles,stalled-cycles-frontend,stalled-cycles-backend,instructions,branches,branch-misses,L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses,dTLB-loads,dTLB-load-misses ls

结果如下,关注的特殊项也纳入统计。

 Performance counter stats for 'ls':

          0.976790      task-clock (msec)         #    0.618 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                92      page-faults               #    0.094 M/sec                  
         1,801,371      cycles                    #    1.844 GHz                    
           458,450      stalled-cycles-frontend   #   25.45% frontend cycles idle   
           665,732      stalled-cycles-backend    #   36.96% backend  cycles idle   
     <not counted>      instructions               (0.00%)
     <not counted>      branches                   (0.00%)
     <not counted>      branch-misses              (0.00%)
     <not counted>      L1-dcache-loads            (0.00%)
     <not counted>      L1-dcache-load-misses      (0.00%)
     <not counted>      LLC-loads                  (0.00%)
     <not counted>      LLC-load-misses            (0.00%)
     <not counted>      dTLB-loads                 (0.00%)
     <not counted>      dTLB-load-misses           (0.00%)

       0.001580341 seconds time elapsed

perf record

perf report

perf timechart

perf script

perf lock

perf kmem

perf sched

perf probe

参考资料

系统级性能分析工具 — Perf:http://blog.csdn.net/zhangskd/article/details/37902159/

linux perf - 性能测试和优化工具:http://www.cnblogs.com/hushaojun/p/4848269.html

Linux下的内核测试工具——perf使用简介:http://www.blogjava.net/qileilove/archive/2013/09/04/403646.html

Perf -- Linux下的系统性能调优工具,第 1 部分:http://www.ibm.com/developerworks/cn/linux/l-cn-perf1/

Perf -- Linux下的系统性能调优工具,第 2 部分:https://www.ibm.com/developerworks/cn/linux/l-cn-perf2/

性能分析工具---Perf简介汇总整理:http://sanwen.net/a/nzsrvoo.html