perf的原理是什么?

perf, perf_event都是什么? perf有那些功能?

perf是linux官方的性能分析器 位于linux内核源码的tools/perf下面. 是内核 ==perf_events 可观测性子系统==的前端

perf拥有的能力有那些?

  • 采样技术: 比如每隔一定时间(例如每秒1000次)中断 CPU,记录当前正在运行的函数。通过统计,可以找出哪些函数在 CPU 上运行的时间最长,从而定位性能瓶颈。
  • 追踪技术: 记录系统中的特定事件,比如进程调度、系统调用、函数调用等,以了解事件发生的精确顺序和时间

相关概念

前后端分离

perf工具相当于前端, 而perf_events相当于后端

perf_events: Linux 内核里一个专门负责收集信息的子系统, 实时地捕捉各种“事件”,比如 CPU 缓存命中、进程调度、系统调用等

tracepoints: 内核静态追踪 kprobes: 内核动态追踪

USDT:用户静态追踪 uprobes:用户动态追踪

perf支持的子命令

perf 常用子命令速查表

常用程度命令描述
★★★★★record运行一个命令,并将其性能剖析数据记录到 perf.data 文件中。这是离线分析的第一步。
★★★★★report读取 record 生成的 perf.data 文件,并显示性能剖析报告。这是离线分析的第二步。
★★★★★stat运行一个命令并收集性能计数器统计信息。用于快速获取高层次的性能概览,如总CPU周期、缓存命中率等。
★★★★☆list列出 perf 支持的所有事件类型,包括硬件、软件和追踪点事件。这是学习和探索 perf 功能的起点。
★★★★☆top实时、交互式的系统性能剖析工具,类似于 top 命令,但能显示函数级别的性能瓶颈。非常适合快速诊断。
★★★☆☆annotate读取 perf.data,并将性能数据直接注解到源码或反汇编代码旁。用于进行深入的源码级优化。
★★★☆☆probe定义新的动态追踪点。用于在不修改内核源码的情况下,追踪特定内核函数。
★★☆☆☆diff对比两个 perf.data 文件,显示性能数据的差异。用于在优化前后进行性能对比。
★★☆☆☆script读取 perf.data,并将原始事件数据以文本形式输出,方便脚本化处理。适合高级用户进行自定义分析。
★☆☆☆☆trace实时追踪系统调用。功能类似于 strace,但基于 perf_events 框架。
★☆☆☆☆lock专门用于分析事件,帮助排查并发和同步问题。
★☆☆☆☆mem专门用于剖析内存访问,帮助排查缓存和内存瓶颈。
graph TD
    subgraph Kernel["内核 (Kernel)"]
        Events["Events<br/>事件"]
        Counters["Counters<br/>计数器"]
        RingBuffers["Ring Buffers<br/>环形缓冲区"]
    end
    
    Events --> Counters
    Events --> RingBuffers
    
    Events --> PerfList["perf list<br/>列出事件"]
    Counters --> PerfStat["perf stat<br/>统计性能"]
    RingBuffers --> PerfTrace["perf trace<br/>跟踪调用"]
    RingBuffers --> PerfRecord["perf record<br/>记录数据"]
    
    PerfList --> EventList["event list (text)<br/>事件列表"]
    PerfStat --> Counts["counts (text)<br/>计数结果"]
    PerfTrace --> Samples1["samples (text)<br/>样本数据"]
    PerfRecord --> PerfData["perf.data<br/>性能数据文件"]
    
    PerfData --> PerfReport["perf report<br/>生成报告"]
    PerfData --> PerfScript["perf script<br/>脚本输出"]
    
    PerfReport --> Summary["summary (text)<br/>汇总报告"]
    PerfScript --> Samples2["samples (text)<br/>样本文本"]
    
    PerfScript --> StackCollapse["stackcollapse-perf.pl<br/>堆栈折叠脚本"]
    StackCollapse --> FlameGraphScript["flamegraph.pl<br/>火焰图脚本"]
    FlameGraphScript --> FlameGraph["flame graph (SVG)<br/>火焰图"]
    
    PerfScript -.->|"Linux 5.8+<br/>Linux 5.8及以上版本"| FlameGraph
    
    classDef kernelClass fill:#e6f3ff,stroke:#333,stroke-width:2px
    classDef commandClass fill:#fff2cc,stroke:#333,stroke-width:1.5px
    classDef outputClass fill:#d5e8d4,stroke:#333,stroke-width:1.5px
    classDef dataClass fill:#ffe6cc,stroke:#333,stroke-width:1.5px
    classDef scriptClass fill:#f8cecc,stroke:#333,stroke-width:1.5px
    
    class Events,Counters,RingBuffers kernelClass
    class PerfList,PerfStat,PerfTrace,PerfRecord,PerfReport,PerfScript commandClass
    class EventList,Counts,Samples1,Samples2,Summary,FlameGraph outputClass
    class PerfData dataClass
    class StackCollapse,FlameGraphScript scriptClass

perf 子命令具体用法

perf list

  • 作用:列出所有当前已知的事件类型。

  • 解析:这是最基础的用法。当你不知道能用 perf 追踪什么事件时,就运行这个命令。它会返回一个很长的列表,包括硬件事件(CPU-cycles)、软件事件(context-switches)、内核追踪点(syscallssched)等。这个列表取决于你的内核版本和系统架构。

例子: 事件巨多

List of pre-defined events (to be used in -e):
 
  branch-instructions OR branches                    [Hardware event]
  branch-misses                                      [Hardware event]
  bus-cycles                                         [Hardware event]
  cache-misses                                       [Hardware event]
  cache-references                                   [Hardware event]
  cpu-cycles OR cycles                               [Hardware event]
  instructions                                       [Hardware event]
  ref-cycles                                         [Hardware event]
 
  alignment-faults                                   [Software event]
  bpf-output                                         [Software event]
  context-switches OR cs                             [Software event]
  cpu-clock                                          [Software event]
  cpu-migrations OR migrations                       [Software event]
  dummy                                              [Software event]
  emulation-faults                                   [Software event]
  major-faults                                       [Software event]
  minor-faults                                       [Software event]
  page-faults OR faults                              [Software event]
  task-clock                                         [Software event]
 
  duration_time                                      [Tool event]
 
  branch-instructions OR cpu/branch-instructions/    [Kernel PMU event]
  branch-misses OR cpu/branch-misses/                [Kernel PMU event]
  bus-cycles OR cpu/bus-cycles/                      [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]
  intel_bts//                                        [Kernel PMU event]
  intel_pt//                                         [Kernel PMU event]
  msr/aperf/                                         [Kernel PMU event]
  msr/cpu_thermal_margin/                            [Kernel PMU event]
  msr/mperf/                                         [Kernel PMU event]
  msr/tsc/                                           [Kernel PMU event]
  ref-cycles OR cpu/ref-cycles/                      [Kernel PMU event]
 
  rNNN                                               [Raw hardware event descriptor]
  cpu/t1=v1[,t2=v2,t3 ...]/modifier                  [Raw hardware event descriptor]
   (see 'man perf-list' on how to encode it)
 
  mem:<addr>[/len][:access]                          [Hardware breakpoint]
 
  alarmtimer:alarmtimer_cancel                       [Tracepoint event]
  alarmtimer:alarmtimer_fired                        [Tracepoint event]
  alarmtimer:alarmtimer_start                        [Tracepoint event]
  alarmtimer:alarmtimer_suspend                      [Tracepoint event]
  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_bio_remap                              [Tracepoint event]
  block:block_dirty_buffer                           [Tracepoint event]
  block:block_getrq                                  [Tracepoint event]
  block:block_plug                                   [Tracepoint event]
  block:block_rq_complete                            [Tracepoint event]
  block:block_rq_insert                              [Tracepoint event]
  ...
  ...

perf list xxxx 筛选特定事件

root@song-com:/home/song/src/learning/perf# perf list 'sched:*'
 
List of pre-defined events (to be used in -e):
 
  sched:sched_kthread_stop                           [Tracepoint event]
  sched:sched_kthread_stop_ret                       [Tracepoint event]
  sched:sched_kthread_work_execute_end               [Tracepoint event]
  sched:sched_kthread_work_execute_start             [Tracepoint event]
  sched:sched_kthread_work_queue_work                [Tracepoint event]
  sched:sched_migrate_task                           [Tracepoint event]
  sched:sched_move_numa                              [Tracepoint event]
  sched:sched_pi_setprio                             [Tracepoint event]
  sched:sched_process_exec                           [Tracepoint event]
  sched:sched_process_exit                           [Tracepoint event]
  sched:sched_process_fork                           [Tracepoint event]
  sched:sched_process_free                           [Tracepoint event]
  sched:sched_process_hang                           [Tracepoint event]
  sched:sched_process_wait                           [Tracepoint event]
  sched:sched_stat_blocked                           [Tracepoint event]
  sched:sched_stat_iowait                            [Tracepoint event]
  sched:sched_stat_runtime                           [Tracepoint event]
  sched:sched_stat_sleep                             [Tracepoint event]
  sched:sched_stat_wait                              [Tracepoint event]
  sched:sched_stick_numa                             [Tracepoint event]
  sched:sched_swap_numa                              [Tracepoint event]
  sched:sched_switch                                 [Tracepoint event]
  sched:sched_wait_task                              [Tracepoint event]
  sched:sched_wake_idle_without_ipi                  [Tracepoint event]
  sched:sched_wakeup                                 [Tracepoint event]
  sched:sched_wakeup_new                             [Tracepoint event]
  sched:sched_waking                                 [Tracepoint event]

常用事件清单

事件名所属类别事件作用
cpu-cycles硬件事件 (Hardware event)统计 CPU 运行的时钟周期总数。这是衡量 CPU 总工作量最基本的指标。
instructions硬件事件 (Hardware event)统计 CPU 执行的指令总数。用于计算 IPC (每周期指令数),即 instructions / cpu-cycles,它是衡量 CPU 效率的关键指标。
cache-references硬件缓存事件 (Hardware cache event)统计程序访问缓存的总次数。
cache-misses硬件缓存事件 (Hardware cache event)统计程序访问缓存失败的次数。通过它和 cache-references 可以计算缓存未命中率,是诊断内存瓶颈的关键。
L1-dcache-load-misses硬件缓存事件 (Hardware cache event)统计 L1 数据缓存加载未命中的次数。这是最快的一级缓存,未命中通常意味着性能会受到较大影响。
LLC-load-misses硬件缓存事件 (Hardware cache event)统计末级缓存(Last-Level Cache, LLC)加载未命中的次数。如果这个值很高,通常意味着数据不在任何一级缓存中,必须从主内存加载,是严重的性能问题。
bus-cycles硬件事件 (Hardware event)统计 CPU 与主内存总线交互的时钟周期数。可以用来衡量内存访问的繁忙程度。
branch-instructions硬件事件 (Hardware event)统计分支指令(如 if, for, while)执行的总数。
branch-misses硬件事件 (Hardware event)统计分支预测失败的次数。用于计算分支预测失败率,如果这个值很高,说明程序的控制流难以预测,会造成流水线停顿。
context-switches软件事件 (Software event)统计进程或线程上下文切换的次数。过高的上下文切换次数通常意味着调度开销大,可能存在锁竞争或 I/O 等待。
cpu-migrations软件事件 (Software event)统计进程在不同 CPU 核心间迁移的次数。频繁的迁移可能会导致缓存失效。
page-faults软件事件 (Software event)统计缺页错误的次数。当程序访问的内存页不在物理内存中时触发,通常会导致从磁盘加载,性能开销大。
task-clock软件事件 (Software event)统计进程在 CPU 上运行的总时间(不包括等待)。
cpu-clock软件事件 (Software event)类似于 task-clock,但它可以用于多线程和系统级分析。
raw_syscalls:sys_enter跟踪点事件 (Tracepoint event)统计所有系统调用的总数。
sched:sched_switch跟踪点事件 (Tracepoint event)每次发生进程/线程切换时都会触发。用于分析调度器行为。

perf stat 事件计数

事件计数相比于前面的record来说, 消耗性能少很多 因为只需要计数即可 所以快速、高层次的性能评估对比 的时候, 使用stat 如果需要深入, 细致的分析性能瓶颈的时候, 使用record

perf常用选项

选定对象: -a表示全体 -p pid表示指定的进程 选定瞬时还是一段事件: sleep 5 表示一段事件的统计结果 选定事件: -e 用于选定事件

perf stat command 统计指定命令

perf stat -p PID 统计指定进程

例子

root@song-com:/home/song/src/learning/perf/01-cpu-performance# perf stat ./inefficient 100000
 
 Performance counter stats for './inefficient 100000':
 
            833.89 msec task-clock                #    0.999 CPUs utilized          
                 2      context-switches          #    0.002 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                58      page-faults               #    0.070 K/sec                  
     2,792,550,415      cycles                    #    3.349 GHz                    
     3,644,079,265      instructions              #    1.30  insn per cycle         
       911,020,664      branches                  # 1092.498 M/sec                  
            57,078      branch-misses             #    0.01% of all branches        
 
       0.834484514 seconds time elapsed
 
       0.834445000 seconds user
       0.000000000 seconds sys
如何去看输出的状态信息
时间信息统计

下面这几个是执行情况

833.89 msec task-clock # 0.999 CPUs utilized
在CPU上真正运行的时间: 833ms, 占比99% 执行期间平均cpu占用率99%(单核), 如果执行期间跑在了多核上, 则可能会大于1

0.834484514 seconds time elapsed 程序运行的总时间 前面的utilized就是 (task-clock)/(time elapsed)

0.834445000 seconds user 用户空间耗时 0.000000000 seconds sys 内核空间耗时

性能事件统计

context-switches 表示上下文切换次数 page-faults 表示缺页中断发生次数

cycles 表示 程序执行期间 CPU 时钟周期的总数 instructions 表示程序执行的指令总数insn per cycle IPC 表示每周期的指令数量 衡量 CPU 效率的一个非常重要的指标 等于(cycles)/(instructions) 这里表示每个时钟周期执行1.3条指令

branches 表示分支指令数量 branch-misses 表示分支预测失败数量 0.01% of all branches 表示分支预测失败占比 这里可以看出是比较低的

perf stat -a sleep 5 统计整个系统5s内的性能

perf stat -e LLC-loads,LLC-load-misses 统计指定的事件

-e 选项可以指定事件 比如可以去分析特定的缓存命中率, 或者分支预测命中率

root@song-com:/home/song/src/learning/perf/01-cpu-performance# perf stat -e cache-references,cache-misses ./inefficient 100000
 
Performance counter stats for './inefficient 100000':
 
            39,220      cache-references                                            
            18,062      cache-misses              #   46.053 % of all cache refs    
 
       0.835907007 seconds time elapsed
 
       0.831906000 seconds user
       0.003999000 seconds sys
  • cache-references (缓存引用次数):
    • 含义: 你的程序在运行期间,总共向 CPU 的缓存发起了多少次访问请求。
    • 比喻: 就像你去一个巨大的图书馆找书,cache-references 就是你总共打开书架寻找的次数。
  • cache-misses (缓存未命中次数):
    • 含义: 在所有的缓存访问中,有多少次没有找到数据,导致 CPU 必须去更慢的内存(主存)中读取。
    • 比喻: 就像你打开书架找书,cache-misses 就是你没找到,必须去仓库(内存)取书的次数。
  • 46.053 % of all cache refs (缓存未命中率):
    • 含义: 缓存未命中的比例,计算公式是 cache-misses 除以 cache-references
    • 解读: 这个比例是核心。你的程序有 46.053% 的缓存访问都失败了,这是一个非常高的未命中率。

perf stat -e raw_syscalls:sys_enter -I 1000 -a

作用:以每秒一次的间隔,统计每秒钟发生的系统调用数量。 这个用法对于观察系统负载随时间的变化非常有用。

root@song-com:/home/song/src/learning/perf/01-cpu-performance# perf stat -e raw_syscalls:sys_enter -I 1000 ./inefficient 1000000
=== CPU性能问题示例:低效的素数计算 ===
计算范围: 1 1000000
算法: 试除法(低效版本)
预期问题: CPU密集型计算,大量除法运算
 
开始计算1到1000000之间的素数个数(低效算法)...
进度: 10%
#           time             counts unit events
     1.000100655                 37      raw_syscalls:sys_enter        //统计系统调用的次数                              
     2.000218212                  0      raw_syscalls:sys_enter                                      
     3.000348340                  0      raw_syscalls:sys_enter                                      
进度: 20%
     4.000475828                  1      raw_syscalls:sys_enter                                      
     5.000607028                  0      raw_syscalls:sys_enter                                      
     6.000800470                  0      raw_syscalls:sys_enter                                      
进度: 30%
     7.000927805                  1      raw_syscalls:sys_enter                                      
     8.001059564                  0      raw_syscalls:sys_enter                                      
     9.001189882                  0      raw_syscalls:sys_enter                                      
    10.001318139                  0      raw_syscalls:sys_enter                                      
    11.001439993                  0      raw_syscalls:sys_enter                                      
进度: 40%
    12.001570352                  1      raw_syscalls:sys_enter                                      
    13.001703651                  0      raw_syscalls:sys_enter                                      
    14.001832607                  0      raw_syscalls:sys_enter                                      
    15.001959974                  0      raw_syscalls:sys_enter                                      
    16.002091611                  0      raw_syscalls:sys_enter                                      
    17.002186653                  0      raw_syscalls:sys_enter                                      
进度: 50%
    18.002476384                  1      raw_syscalls:sys_enter                                      
    19.002605261                  0      raw_syscalls:sys_enter                                      
    20.002733729                  0      raw_syscalls:sys_enter                                      
    21.002865469                  0      raw_syscalls:sys_enter                                      
    22.002994694                  0      raw_syscalls:sys_enter                                      
    23.003121380                  0      raw_syscalls:sys_enter                                      
    24.003252970                  0      raw_syscalls:sys_enter                                      
    25.003382511                  0      raw_syscalls:sys_enter                                      
进度: 60%
#           time             counts unit events
    26.003517065                  1      raw_syscalls:sys_enter                                      
    27.003648214                  0      raw_syscalls:sys_enter                                      
    28.003781060                  0      raw_syscalls:sys_enter                                      
    29.003917977                  0      raw_syscalls:sys_enter                                      
    30.004054028                  0      raw_syscalls:sys_enter                                      
    31.004155380                  0      raw_syscalls:sys_enter                                      
    32.004258782                  0      raw_syscalls:sys_enter                                      
    33.004388444                  0      raw_syscalls:sys_enter                                      
    34.004517867                  0      raw_syscalls:sys_enter                                      
进度: 70%
    35.004646235                  1      raw_syscalls:sys_enter                                      
    36.004774699                  0      raw_syscalls:sys_enter                                      
    37.004906442                  0      raw_syscalls:sys_enter                                      
    38.005042104                  0      raw_syscalls:sys_enter                                      
    39.005170320                  0      raw_syscalls:sys_enter                                      
    40.005301182                  0      raw_syscalls:sys_enter                                      
    41.005432358                  0      raw_syscalls:sys_enter                                      
    42.005561244                  0      raw_syscalls:sys_enter                                      
    43.005697245                  0      raw_syscalls:sys_enter                                      
    44.005801655                  0      raw_syscalls:sys_enter                                      
进度: 80%
    45.005942608                  1      raw_syscalls:sys_enter                                      
    46.006073358                  0      raw_syscalls:sys_enter                                      
    47.006202197                  0      raw_syscalls:sys_enter                                      
    48.006324966                  0      raw_syscalls:sys_enter                                      
    49.006452896                  0      raw_syscalls:sys_enter                                      
    50.006585439                  0      raw_syscalls:sys_enter                                      
#           time             counts unit events
    51.006710339                  0      raw_syscalls:sys_enter                                      
    52.006836730                  0      raw_syscalls:sys_enter                                      
    53.006944163                  0      raw_syscalls:sys_enter                                      
    54.007076620                  0      raw_syscalls:sys_enter                                      
    55.007209707                  0      raw_syscalls:sys_enter                                      
进度: 90%
    56.007341995                  1      raw_syscalls:sys_enter                                      
    57.007476317                  0      raw_syscalls:sys_enter                                      
    58.007610004                  0      raw_syscalls:sys_enter                                      
    59.007742613                  0      raw_syscalls:sys_enter                                      
    60.007876270                  0      raw_syscalls:sys_enter                                      
    61.007972027                  0      raw_syscalls:sys_enter                                      
    62.008073469                  0      raw_syscalls:sys_enter                                      
    63.008209612                  0      raw_syscalls:sys_enter                                      
    64.008307877                  0      raw_syscalls:sys_enter                                      
    65.008441726                  0      raw_syscalls:sys_enter                                      
    66.008573931                  0      raw_syscalls:sys_enter                                      
    67.008682259                  0      raw_syscalls:sys_enter                                      
    68.008834122                  0      raw_syscalls:sys_enter                                      
进度: 100%

perf stat -e ‘syscalls:sys_enter_*’ -p PID

按照事件类型, 统计pid进程的情况

root@song-com:/home/song/src/learning/perf# perf stat -e 'syscalls:sys_enter_*' -p 73916
 
 Performance counter stats for process id '73916':
 
                 0      syscalls:sys_enter_socket                                   
                 0      syscalls:sys_enter_socketpair                                   
                 0      syscalls:sys_enter_bind                                     
                 0      syscalls:sys_enter_listen                                   
                 0      syscalls:sys_enter_accept4                                   
                 0      syscalls:sys_enter_accept                                   
                 0      syscalls:sys_enter_connect                                   
                 0      syscalls:sys_enter_getsockname                                   
                 0      syscalls:sys_enter_getpeername                                   
                 0      syscalls:sys_enter_sendto                                   
                 0      syscalls:sys_enter_recvfrom                                   
                 0      syscalls:sys_enter_setsockopt                                   
                 0      syscalls:sys_enter_getsockopt                                   
                 0      syscalls:sys_enter_shutdown                                   
                 0      syscalls:sys_enter_sendmsg                                   
                 0      syscalls:sys_enter_sendmmsg                                   
                 0      syscalls:sys_enter_recvmsg                                   
                 0      syscalls:sys_enter_recvmmsg                                   
                 0      syscalls:sys_enter_getrandom                                   
                 0      syscalls:sys_enter_ioprio_set                                   
                 0      syscalls:sys_enter_ioprio_get                                   
                 0      syscalls:sys_enter_add_key                                   
                 0      syscalls:sys_enter_request_key                                   
                 0      syscalls:sys_enter_keyctl                                   
                 0      syscalls:sys_enter_mq_open                                   
                 0      syscalls:sys_enter_mq_unlink                                                    
                 0      syscalls:sys_enter_fsconfig                                   
                 0      syscalls:sys_enter_statfs                                   
                 0      syscalls:sys_enter_fstatfs                                   
                 0      syscalls:sys_enter_ustat                                    
                 0      syscalls:sys_enter_getcwd                                   
                 0      syscalls:sys_enter_utimensat                                   
                 0      syscalls:sys_enter_futimesat                                   
                 0      syscalls:sys_enter_utimes                                   
                 0      syscalls:sys_enter_utime                                    
                 0      syscalls:sys_enter_sync                                     
                 0      syscalls:sys_enter_syncfs                                   
                 0      syscalls:sys_enter_fsync                                    
                 0      syscalls:sys_enter_fdatasync                                   
                 0      syscalls:sys_enter_sync_file_range                                   
                 0      syscalls:sys_enter_vmsplice                                   
                 0      syscalls:sys_enter_splice                                   
                 0      syscalls:sys_enter_tee                                      
                 0      syscalls:sys_enter_setxattr                                   
                 0      syscalls:sys_enter_lsetxattr                                   
                 0      syscalls:sys_enter_fsetxattr                                   
                 0      syscalls:sys_enter_getxattr                                   
                 0      syscalls:sys_enter_lgetxattr                                   
                 0      syscalls:sys_enter_fgetxattr                                   
                 0      syscalls:sys_enter_listxattr                                   
                 0      syscalls:sys_enter_llistxattr                                   
                 0      syscalls:sys_enter_flistxattr                                   
                 0      syscalls:sys_enter_removexattr                                   
                 0      syscalls:sys_enter_lremovexattr                                   
                 0      syscalls:sys_enter_fremovexattr                                   
                 0      syscalls:sys_enter_umount                                   
                 0      syscalls:sys_enter_open_tree                                   
                 0      syscalls:sys_enter_mount                                    
                 0      syscalls:sys_enter_fsmount                                   
                 0      syscalls:sys_enter_move_mount                                   
                 0      syscalls:sys_enter_pivot_root                                   
                 0      syscalls:sys_enter_sysfs                                    
                 0      syscalls:sys_enter_dup3                                     
                 0      syscalls:sys_enter_dup2                                     
                 0      syscalls:sys_enter_dup                                      
                 0      syscalls:sys_enter_select                                   
                 0      syscalls:sys_enter_pselect6                                   
                 0      syscalls:sys_enter_poll                                     
                 0      syscalls:sys_enter_ppoll                                    
                 0      syscalls:sys_enter_getdents                                   
                 0      syscalls:sys_enter_getdents64                                   
                 0      syscalls:sys_enter_symlink                                   
                 0      syscalls:sys_enter_linkat                                   
                 0      syscalls:sys_enter_link                                     
                 0      syscalls:sys_enter_renameat2                                   
                 0      syscalls:sys_enter_renameat                                   
                 0      syscalls:sys_enter_rename                                   
                 0      syscalls:sys_enter_pipe2                                    
                 0      syscalls:sys_enter_pipe                                     
                 0      syscalls:sys_enter_execve                                   
                 0      syscalls:sys_enter_execveat                                   
                 0      syscalls:sys_enter_newstat                                   
                 0      syscalls:sys_enter_newlstat                                   
                 0      syscalls:sys_enter_newfstatat                                   
                 0      syscalls:sys_enter_newfstat                                   
                 0      syscalls:sys_enter_readlinkat                                   
                 0      syscalls:sys_enter_readlink                                   
                 0      syscalls:sys_enter_statx                                    
                 0      syscalls:sys_enter_lseek                                    
                 0      syscalls:sys_enter_read                                     
[...]
 
      14.011315605 seconds time elapsed

perf stat -e ‘block:*’ -a sleep 10

统计一段事件内的 所有指定事件的情况

perf record

perf record -F 99 command

作用: 以 99Hz 的频率对指定命令进行 CPU 采样 perf 会在每秒内随机的 99 个时间点中断 CPU,记录下当前正在执行的指令,并最终生成一个报告

关于perf的采样

  • -F频率采样。你告诉 perf 每秒钟要采集多少个样本。

  • -c周期采样或溢出采样(overflow sampling)。你告诉 perf 每隔多少个事件(比如每隔1000个周期),就采集一次。 这两种方法都可以控制采样粒度,区别在于前者基于时间,后者基于事件数。

perf record -F 99 -a -g sleep 10

作用: 对整个系统进行 10 秒钟的 CPU 栈踪迹采样

-g 工作原理:当函数调用另一个函数时,它会把当前函数的“地址”(也就是帧指针)保存在栈上,作为返回的“路标”。被调用函数结束时,它会根据这个帧指针找到返回的“路标”,回到调用者那里。-g 就是利用这些栈上的帧指针

  • 优点
    • 通用性强:几乎所有平台和编译器都支持这种方法。
    • 开销低:不需要额外的调试信息,回溯速度快。
  • 缺点
    • 不准确:许多编译器(尤其是 GCC)默认会开启 -fomit-frame-pointer 优化,目的是为了节省一个寄存器,从而提高性能。一旦这个优化被开启,帧指针就不会被保存在栈上,-g 就无法正确地回溯完整的调用栈,导致栈信息不完整或错误。
Samples: 3K of event 'cycles', Event count (approx.): 45824810257
  Children      Self  Command          Shared Object                                  Symbol
-   16.01%    15.97%  CPU-Worker-0\n   libm-2.31.so                                   [.] sincosf32x                                      
   + 6.17% 0x6b726f572d555043                                                                                                              
     0.57% sincosf32x                                                                                                                      
+   15.69%    15.48%  MEM-Worker-1\n   multithreaded_workload                         [.] memory_intensive_computation                     
-   15.36%    15.02%  CPU-Worker-0\n   multithreaded_workload                         [.] worker_thread                                    
     15.15% worker_thread                                                                                                                 
+    9.82%     9.78%  MEM-Worker-1\n   libm-2.31.so                                   [.] sincosf32x                                       
+    6.17%     0.00%  CPU-Worker-0\n   [unknown]                                      [.] 0x6b726f572d555043                                                  ▒
+    4.81%     4.67%  CPU-Worker-0\n   libm-2.31.so                                   [.] __ieee754_log_fma                                                   ▒
+    4.47%     4.47%  CPU-Worker-0\n   libm-2.31.so                                   [.] __ieee754_exp_fma                                                   ▒
+    3.95%     3.93%  BRANCH-Worker-2  multithreaded_workload                         [.] branch_intensive_task                                               ▒
+    3.82%     3.75%  MEM-Worker-1\n   libm-2.31.so                                   [.] __ieee754_log_fma                                                   ▒
+    3.80%     0.00%  node             libc-2.31.so                                   [.] __libc_start_main                                                   ▒
+    3.28%     3.21%  MEM-Worker-1\n   libm-2.31.so                                   [.] __ieee754_exp_fma                                                   ▒
+    3.09%     2.96%  CPU-Worker-0\n   libm-2.31.so                                   [.] exp@@GLIBC_2.29                                                     ▒
+    3.08%     0.00%  MEM-Worker-1\n   [unknown]                                      [.] 0x000055a6dc23f710                                                  ▒
+    2.55%     2.45%  MEM-Worker-1\n   libm-2.31.so                                   [.] exp@@GLIBC_2.29                                                     ▒
+    1.93%     0.00%  node             node                                           [.] node::Start                                                         ▒
+    1.87%     0.00%  node             node                                           [.] node::Start                                                         ▒
+    1.87%     0.00%  node             node                                           [.] node::NodeMainInstance::Run                      
+    1.87%     0.00%  node             node                                           [.] node::NodeMainInstance::Run                   
+    1.87%     0.00%  node             node                                           [.] node::SpinEventLoopInternal                   
+    1.87%     0.03%  node             node                                           [.] uv_run   

可以看到消耗cpu的情况, 具体到了每个函数的消耗情况

perf record -F 99 -p Pid —call-graph dwarf sleep 10

 perf record -F 99 -p $(pgrep multithreaded) --call-graph dwarf sleep 10

作用 对pid 使用 DWARF 调试信息来获取更准确的栈踪迹

小技巧: -p pid 可以替换成 -p $(pgrep multithreaded) 这样就可以找到特定的线程了. 不过得知道pgrep命令

  • 工作原理DWARF 是一种标准的调试信息格式,它包含了程序中所有函数、变量、以及函数调用关系的详细元数据。--call-graph dwarf 不依赖于栈上的帧指针,而是直接读取这些调试信息来重建调用栈。它就像是有一个详细的“地图”,可以准确地找到每一个函数在哪里被调用。

  • 优点

    • 非常准确:不管编译器是否开启了帧指针优化,它都能精确地回溯完整的调用栈。
    • 信息丰富:可以获取到更详细的调试信息,比如函数参数、变量值等。
  • 缺点

    • 性能开销大:因为需要加载和解析大量的调试信息,所以分析速度比 -g 慢,且会占用更多的内存。
    • 需要调试信息:你的程序必须在编译时包含了 -g 选项,并且你需要在系统上安装与内核和程序版本匹配的调试符号包(debug symbols)。如果缺少这些信息,--call-graph dwarf 就会失败。
root@song-com:/home/song/src/learning/perf# perf record -F 99 -g -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.675 MB perf.data (3487 samples) ]
root@song-com:/home/song/src/learning/perf# perf report
root@song-com:/home/song/src/learning/perf# perf record -F 99 -p $(pgrep multithreaded) --call-graph dwarf sleep 10
[ perf record: Woken up 41 times to write data ]
[ perf record: Captured and wrote 10.467 MB perf.data (1297 samples) ]

产生的信息也比-g多很多, 下面的结果中, 可以看到更加详细的函数调用

# perf report --sort comm
Samples: 512  of event 'cycles', Event count (approx.): 19548839079  Children      Self  Command
-   47.36%    47.36%  CPU-Worker-0\n
     46.63% __GI___clone (inlined)                                                                      ▒
        start_thread
        worker_thread
      - compute_task (inlined)                                                                          ▒
         - 46.34% heavy_math_computation (inlined)                                                      ▒
              16.37% __sincos (inlined)                                                                 ▒
            - 6.18% __GI___exp (inlined)                                                                ▒
                 3.76% __ieee754_exp_fma
              3.06% 0x55a97e99d3a4
              2.96% __ieee754_log_fma
-   37.51%    37.51%  MEM-Worker-1\n
     36.84% __GI___clone (inlined)                                                                      ▒
        start_thread
        worker_thread
      - compute_task (inlined)                                                                          ▒
         - 36.41% memory_intensive_computation
            + heavy_math_computation (inlined)                                                          ▒
+   13.28%    13.28%  BRANCH-Worker-2
+    1.85%     1.85%  SYNC-Worker-3\n  

perf record -e LLC-load-misses -ag sleep 5

 perf record -e cache-misses -p $(pgrep multithreaded) --call-graph dwarf sleep 5

注意:这里触发的事件不是99的时钟周期了. 而是事件event

还可以添加 -c 100 选项 作用: 每当发生 100 次末级缓存加载未命中时,就进行一次采样。 -c表示事件的采样间隔 event的count 这里100就是表示事件发生了100次, 才去采样一次

perf top命令

perf top -F 49 -ns comm,dso

可以看到热点函数动态占比

Samples: 94K of event 'cycles', 4000 Hz, Event count (approx.): 39693365768 lost: 0/0 drop: 0/0
  Children      Self  Shared Object                                  Symbol
+   22.40%    22.27%  libm-2.31.so                                   [.] sincosf32x
+   14.07%    13.87%  multithreaded_workload                         [.] worker_thread
+   12.35%    12.15%  multithreaded_workload                         [.] memory_intensive_computation
+    8.13%     7.94%  libm-2.31.so                                   [.] __ieee754_exp_fma
+    7.72%     7.58%  libm-2.31.so                                   [.] __ieee754_log_fma
+    6.91%     0.03%  perf                                           [.] __ordered_events__flush.part.0
+    6.87%     0.04%  perf                                           [.] deliver_event
+    5.60%     5.25%  libm-2.31.so                                   [.] exp@@GLIBC_2.29
+    5.10%     0.02%  perf                                           [.] hist_entry_iter__add