3. perf 基础:perf list、perf stat、perf record、perf report 的基本用法与输出解读

perf 这工具,说白了就是 Linux 系统自带的性能剖析神器。我刚开始接触它的时候,觉得命令行参数又多又杂,但用顺手之后,真香。今天咱们就把最核心的四个命令捋一遍:perf list、perf stat、perf record 和 perf report。

你想想看,排查性能问题就像医生看病。你得先知道有哪些检查项目(perf list),然后做个快速体检(perf stat),发现问题再拍个 CT 扫描(perf record),最后看诊断报告(perf report)。嗯,就是这么个流程。

perf 核心命令 perf list 列出可用事件 perf stat 快速统计概览 perf record 采样记录数据 perf report 分析报告展示 诊断流程:先查项目 → 快速体检 → 深度扫描 → 看报告

3.1 perf list:看看你能查什么

perf list 就是 perf 的「体检项目清单」。它会列出当前系统支持的所有性能事件。我个人习惯在开始任何性能分析之前,先跑一遍这个命令,心里有个底。

# 列出所有可用事件
perf list

# 只看硬件事件
perf list hw

# 只看软件事件
perf list sw

# 只看 cache 相关事件
perf list cache

输出大概长这样:

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]

  alignment-faults                                   [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]

  L1-dcache-load-misses                              [Hardware cache event]
  L1-dcache-loads                                    [Hardware cache event]
  L1-dcache-stores                                   [Hardware cache event]
  L1-icache-load-misses                              [Hardware cache event]
  LLC-load-misses                                    [Hardware cache event]
  LLC-loads                                          [Hardware cache event]
  ...
我的小技巧: 如果你在排查 CPU 密集型问题,重点关注 cycles 和 instructions。如果是内存问题,cache-misses 和 LLC-load-misses 是必看的。我曾经在调优一个数据库服务时,就是靠 LLC-load-misses 揪出了缓存行伪共享的问题。

3.2 perf stat:快速体检

perf stat 相当于给程序做个快速体检。它会在程序运行结束后,汇总关键的性能计数器数据。我经常用它来快速验证优化前后的效果。

# 统计 ls 命令的性能
perf stat ls

# 统计指定进程,持续 5 秒
perf stat -p PID sleep 5

# 只看特定事件
perf stat -e cycles,instructions,cache-misses ./myapp

输出示例:

 Performance counter stats for 'ls':

          1.234567      task-clock (msec)         #    0.987 CPUs utilized
                 3      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
               112      page-faults               #    0.091 M/sec
         3,456,789      cycles                    #    2.800 GHz
         2,100,000      instructions              #    0.61  insn per cycle
           456,789      branches                  #  370.123 M/sec
            12,345      branch-misses             #    2.70% of all branches

       0.001250678 seconds time elapsed
指标 含义 关注点
task-clock 任务占用的 CPU 时间 接近 elapsed time 说明是 CPU 密集
context-switches 上下文切换次数 过高说明锁竞争或 IO 等待严重
cycles CPU 周期数 越高说明 CPU 越忙
instructions 执行的指令数 结合 cycles 算 IPC
branch-misses 分支预测失败率 超过 5% 就要注意了
核心指标:IPC(Instructions Per Cycle)
IPC = instructions / cycles。IPC 越高,说明 CPU 利用率越好。一般 IPC 在 0.5-1.5 之间算正常。低于 0.5 说明有严重的停顿(比如 cache miss 或分支预测失败)。我见过最夸张的一次,一个未优化的 Python 脚本 IPC 只有 0.08,优化后到了 0.9。

3.3 perf record:深度扫描

光看统计数据不够,你得知道热点在哪。这时候 perf record 就派上用场了。它会以固定频率采样程序的运行状态,记录下每次采样时 CPU 正在执行的指令地址。

# 默认采样,按 CPU 周期
perf record ./myapp

# 按特定频率采样(每秒 1000 次)
perf record -F 1000 ./myapp

# 采样指定进程,持续 10 秒
perf record -p PID sleep 10

# 只采样用户态
perf record -u ./myapp

# 只采样内核态
perf record -k ./myapp
注意: 采样频率不要设太高。我曾经在线上环境设了 -F 9999,结果 perf 本身占用了大量 CPU,反而干扰了业务程序。一般 -F 1000 到 -F 4000 就够用了。

运行结束后,会在当前目录生成一个 perf.data 文件。这个文件就是你的「CT 扫描底片」。

3.4 perf report:看诊断报告

有了 perf.data,接下来就是看报告了。perf report 会解析采样数据,按热点排序展示。

# 查看报告
perf report

# 只看某个符号(函数)
perf report --symbols=my_function

# 输出到文件
perf report --stdio > report.txt

# 显示调用链
perf report -g

交互式界面大概长这样:

Samples: 1K of event 'cycles', 4000 Hz, Event count (approx.): 3456789
Overhead  Command  Shared Object      Symbol
  45.23%  myapp    myapp              [.] compute_hash
  22.11%  myapp    myapp              [.] parse_input
  10.56%  myapp    libc-2.31.so       [.] __memcpy_avx_unaligned
   5.34%  myapp    myapp              [.] validate_data
   3.21%  myapp    [kernel.kallsyms]  [k] do_syscall_64
   ...

解读要点:

  • Overhead:该函数占用的 CPU 时间比例。越高越需要关注。
  • Symbol:函数名。如果是 [.] 表示用户态,[k] 表示内核态。
  • 如果热点在 memcpy 这类库函数,说明你的程序在做大量内存拷贝。
  • 如果热点在内核函数(如 do_syscall_64),说明系统调用频繁。
我的经验: 看报告时别只盯着第一名。有时候第二名、第三名才是真正的瓶颈。比如 compute_hash 占了 45%,但它是必须的计算。而 __memcpy_avx_unaligned 占了 10%,如果能减少拷贝,收益可能更大。我曾经优化过一个网络服务,把热点从 memcpy 转移到业务逻辑上,吞吐量直接翻倍。

3.5 组合拳:一个完整的分析案例

咱们来走一遍完整的流程。假设有个程序 slowapp 跑得很慢。

# 第一步:快速体检
perf stat ./slowapp
# 发现 IPC 只有 0.3,cache-misses 很高

# 第二步:深度采样
perf record -F 1000 -g ./slowapp

# 第三步:看报告
perf report -g
# 发现热点在 data_process 函数,且 cache-misses 集中在某个循环
避坑指南: 我曾经在调试一个 Java 应用时,直接用 perf record 采样,结果报告里全是 JVM 的 C2 编译器热点,根本看不到业务代码。后来才想起来要加上 --call-graph dwarf 参数,并且配合 perf-map-agent 生成 JIT 符号表。嗯,这个坑我踩过,你们别踩了。

总结一下:perf list 是菜单,perf stat 是体检,perf record 是 CT 扫描,perf report 是诊断报告。这四个命令用熟了,大部分性能问题都能定位个七七八八。


可可精品资料库