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