4. perf 基础使用:perf stat、perf record/report、perf top、perf annotate 的基本用法与输出解读

perf 是 Linux 内核提供的性能剖析工具集,基于 perf_event_open 系统调用与硬件 PMU(Performance Monitoring Unit)交互。在低延迟驱动场景中,perf 用于定位中断处理耗时、临界区竞争、缓存未命中与分支预测错误。本章覆盖四个核心子命令:perf stat(计数)、perf record/report(采样与可视化)、perf top(实时热点)与 perf annotate(指令级分析)。

适用场景:驱动中断处理函数(ISR)、NAPI 轮询、DMA 完成回调、ioctl 路径、临界区自旋锁等待。perf 可在不修改内核代码的前提下采集精确性能数据。

4.1 perf stat:事件计数与程序级性能摘要

perf stat 以计数模式运行目标程序或附加到运行进程,输出周期数、指令数、缓存未命中、分支预测错误等硬件事件总数。驱动开发者常用它对比不同实现路径的 CPI(每指令周期数)与缓存行为。

4.1.1 基本用法

# 运行命令并统计
perf stat ./driver_test

# 附加到已运行的 PID(如中断处理线程)
perf stat -p $(pgrep ksoftirqd/0) sleep 5

# 指定自定义事件组
perf stat -e cycles,instructions,cache-misses,branch-misses ./driver_test

4.1.2 输出解读

输出字段 含义 驱动调优关注点
cycles CPU 周期总数 中断处理路径的绝对耗时
instructions 执行的指令数 代码路径长度,与 cycles 对比计算 CPI
cache-misses 最后一级缓存未命中次数 数据结构布局、DMA 缓冲区对齐
branch-misses 分支预测失败次数 条件判断密集的临界区
# task-clock 任务占用 CPU 时间(msec) CPU 利用率与调度延迟
CPI cycles / instructions 理想值 < 1.0,驱动路径应 < 2.0
驱动调优案例:某网卡驱动 NAPI 轮询路径 CPI 从 1.8 降至 1.2,通过将描述符数组从 kmalloc 改为 dma_alloc_coherent 并 cacheline 对齐,cache-misses 减少 37%。

4.1.3 事件计数流程

perf stat 事件计数流程 perf stat 启动 perf_event_open() PMU 配置 目标程序执行 硬件计数器递增 内核读取 / 缩放 输出摘要

4.2 perf record / report:采样剖析与热点定位

perf record 以固定频率(默认 4000 Hz)采样 CPU 程序计数器(PC),生成 perf.data 文件。perf report 将采样数据符号化,按热点函数排序。驱动开发者用它定位中断处理函数中哪一行代码消耗最多 CPU 时间。

4.2.1 基本用法

# 采样驱动测试程序,频率 1000 Hz
perf record -F 1000 -g -- ./driver_test

# 采样内核驱动模块(需 root)
perf record -F 1000 -a -g -- sleep 10

# 生成报告
perf report -i perf.data

-g 启用调用链(callchain)记录,显示热点函数的完整调用路径,对驱动中断上下文分析至关重要。

4.2.2 输出解读

列名 含义 驱动分析示例
Overhead 该函数占采样总数的百分比 80% 集中在 ixgbe_clean_rx_irq
Command 进程名 ksoftirqd/0 或 irq/46-ixgbe
Shared Object 所属模块或库 [kernel] 或 ixgbe.ko
Symbol 函数名 spin_lock、memcpy、napi_complete
采样偏差注意:perf 基于周期中断采样,短于采样周期的热点可能被低估。驱动 ISR 若执行时间 < 250 μs(4000 Hz 对应周期),应提高采样频率至 10000 Hz 或使用 perf stat 计数模式。

4.2.3 采样与报告流程

perf record / report 采样流程 perf record PMU 溢出中断 采样 PC + 调用链 写入 perf.data perf report 符号化 热点排序输出

4.3 perf top:实时热点监控

perf top 类似 top 命令,但按 CPU 采样事件排序显示当前最热的函数。驱动调试时,可实时观察中断处理函数、锁竞争、内存拷贝等热点变化。

4.3.1 基本用法

# 实时显示内核与用户态热点
perf top

# 仅显示内核态(驱动模块)
perf top -k vmlinux

# 指定事件:缓存未命中
perf top -e cache-misses

# 显示调用链
perf top -g

4.3.2 输出解读

列名 含义 典型驱动热点
Overhead 当前采样占比 若 > 10% 需重点优化
Shared 所属模块 ixgbe、mlx5_core
Object 符号类型 [k] 内核、[.] 用户态
Symbol 函数名 __do_softirq、native_queued_spin_lock_slowpath
实战技巧:在驱动加载后运行 perf top -k /proc/kallsyms,可实时观察驱动函数是否进入热点列表。若 spin_lock 出现在前 5,说明锁竞争严重,应检查临界区粒度或改用 RCU。

4.4 perf annotate:指令级热点分析

perf annotate 将热点函数反汇编,并标注每条指令的采样命中数(采样周期数)。驱动开发者可精确识别哪条指令导致缓存未命中、分支预测失败或高延迟内存访问。

4.4.1 基本用法

# 对 perf.data 中热点函数进行反汇编标注
perf annotate -i perf.data

# 指定具体函数
perf annotate -i perf.data --symbol ixgbe_clean_rx_irq

# 显示源码与汇编对照(需编译时加 -g)
perf annotate -i perf.data --source

4.4.2 输出解读

Percent |  Source code & Disassembly of ixgbe.ko
-----------------------------------------------
        │  while (rx_desc->wb.upper.status_error & IXGBE_RXD_STAT_DD) {
  0.12   │  mov    0x10(%rdi),%eax
 23.45   │  test   $0x1,%eax
        │  ↓ je     70
        │      skb = build_skb(rx_desc->data, ...)
  0.08   │  mov    %r12,%rdi
 15.32   │  call   build_skb
        │      napi_gro_receive(napi, skb)
  0.05   │  mov    %r13,%rdi
 10.87   │  call   napi_gro_receive
        │  }
列 含义 驱动调优指示
Percent 该指令占函数总采样数的百分比 高百分比指令是优化靶点
指令 汇编指令 test 高可能分支预测失败;call 高可能函数调用开销大
跳转标记 ↓ je 条件跳转 跳转目标可考虑 __builtin_expect 优化
指令级分析前提:驱动模块必须保留符号表(编译时不 strip),且内核需开启 CONFIG_KALLSYMS。对于内联函数,perf annotate 可能无法准确标注,建议使用 __attribute__((noinline)) 临时禁用内联以定位热点。

4.4.3 指令级热点分析流程

perf annotate 指令级分析流程 perf.data 采样数据 符号解析 + 反汇编 采样命中映射到指令 标注百分比输出 定位高延迟指令 优化代码 / 数据布局

4.5 驱动调优实战:perf 四步法

  1. perf stat 全局评估:测量驱动路径的 CPI、cache-misses、branch-misses,建立基线。
  2. perf record/report 热点定位:采样驱动中断或线程上下文,找出 overhead 最高的 3 个函数。
  3. perf top 实时验证:在施加网络流量或 I/O 压力时,确认热点是否与预期一致。
  4. perf annotate 指令级优化:对热点函数反汇编,识别高延迟指令(如 cache miss 的 load、分支预测失败的 test/je),针对性调整代码布局或数据结构。
低延迟驱动检查清单:
✓ 中断处理函数 CPI < 1.5
✓ cache-misses 占比 < 5%
✓ branch-misses 占比 < 3%
✓ 无自旋锁在热点前 5
✓ 热点函数内无频繁函数调用(如 printk、kmalloc)