3. Perf 基本命令:用法与参数详解
在 Android 底层驱动调优中,perf 是最核心的性能剖析工具。本章将系统讲解 perf 的五大基本命令——perf list、perf stat、perf record、perf report、perf top,涵盖其典型用法、关键参数及在驱动场景下的实践要点。掌握这些命令是后续进行中断分析、调度延迟、缓存命中率等专项调优的基础。
前置条件:确保目标 Android 设备内核已开启
CONFIG_PERF_EVENTS,且用户空间包含 perf 工具(通常位于 /system/bin/perf 或通过 adb shell 使用)。对于非 root 设备,部分硬件事件可能需要 perf_event_paranoid 调整为 1 或更低。
3.1 perf list:列出可监控的事件
perf list 用于查询当前内核与硬件支持的所有性能事件,是驱动开发者选择监控目标的起点。
3.1.1 基本用法
# 列出所有事件(硬件、软件、tracepoint、PMU)
adb shell perf list
# 按类别筛选
adb shell perf list hw # 仅硬件事件
adb shell perf list sw # 仅软件事件
adb shell perf list cache # 仅缓存事件
adb shell perf list tracepoint # 仅内核 tracepoint
3.1.2 驱动调优常用事件
| 事件类别 | 典型事件名 | 驱动调优场景 |
|---|---|---|
| 硬件 (PMU) | cpu-cycles, instructions, cache-misses |
评估中断处理函数指令效率、DMA 缓存一致性开销 |
| 软件 | context-switches, page-faults, cpu-migrations |
分析驱动线程调度延迟、内存映射开销 |
| Tracepoint | irq:irq_handler_entry, sched:sched_wakeup, power:cpu_idle |
追踪中断响应时间、唤醒延迟、电源状态切换 |
| 动态 PMU | exynos-llc, cci (取决于 SoC) |
监控片内互联/LLC 延迟,优化驱动缓存一致性协议 |
注意:不同 SoC(如 Qualcomm、MTK、Exynos)的 PMU 事件名可能不同。务必先在目标设备上执行
perf list 确认可用事件,避免在脚本中硬编码不存在的 PMU 名称。
3.2 perf stat:快速统计性能计数器
perf stat 用于在程序或一段命令执行期间,汇总关键性能计数器的总值与平均值,适合快速评估驱动模块的整体开销。
3.2.1 基本语法与驱动示例
# 统计一个驱动测试程序执行期间的硬件事件
adb shell perf stat -e cycles,instructions,cache-misses,branch-misses \
/data/local/tmp/driver_test
# 统计内核模块加载时的软件事件
adb shell perf stat -e context-switches,page-faults,cpu-migrations \
-- insmod /vendor/lib/modules/gpu_drv.ko
# 统计特定 PID 驱动线程 5 秒内的统计
adb shell perf stat -p 1234 -e irq:irq_handler_entry,irq:irq_handler_exit sleep 5
3.2.2 关键参数
| 参数 | 说明 | 驱动调优典型用法 |
|---|---|---|
-e |
指定事件列表,逗号分隔 | -e cycles,instructions,cache-misses |
-p |
监控指定 PID | -p $(pidof surfaceflinger) 分析显示驱动 |
-a |
全系统模式 | -a -e cache-misses 评估全局缓存压力 |
-r N |
重复运行 N 次,取平均值 | -r 5 ./dma_test 消除单次抖动 |
--per-core |
按 CPU 核分别输出统计 | 分析中断亲和性是否均衡 |
--interval-print N |
每 N 毫秒打印一次快照 | 观察驱动在不同负载阶段的计数器变化 |
驱动调优实战:使用
perf stat -e instructions,cycles -p <irq_thread_pid> --interval-print 1000 可以每秒观察中断线程的 IPC(Instructions Per Cycle)。若 IPC 持续低于 0.5,说明该中断处理函数存在严重的指令停顿(如 cache miss 或分支预测失败),需要进一步用 perf record 定位热点。
3.3 perf record & perf report:采样与热点分析
perf record 通过采样(sampling)记录事件发生时 CPU 的指令指针(IP)或调用栈,perf report 则对采样数据进行符号解析与排序,生成热点报告。这是驱动开发者定位性能瓶颈最强大的组合。
3.3.1 典型驱动采样场景
# 场景1:对驱动测试程序进行 CPU 周期采样,生成调用链
adb shell perf record -e cycles -g --call-graph dwarf \
-o /data/local/tmp/perf.data /data/local/tmp/driver_test
# 场景2:采样特定内核线程(如 IRQ 线程)10 秒
adb shell perf record -e cycles -p $(pidof irq/296-5b10000) \
-g -- sleep 10
# 场景3:全系统采样 cache-misses,关注驱动模块
adb shell perf record -e cache-misses -a -g -- sleep 5
3.3.2 关键参数对比
| 参数 | perf record | perf report |
|---|---|---|
-e |
指定采样事件(默认 cycles) | 过滤只显示某事件的数据 |
-g |
记录调用栈(call-graph) | 显示调用链占比 |
--call-graph |
设置栈展开方式:fp / dwarf / lbr | — |
-p |
附加到指定 PID | — |
-a |
全系统采样 | — |
-F |
采样频率(如 1000 Hz) | — |
-i |
— | 指定输入文件(默认 perf.data) |
--sort |
— | 排序方式:comm, dso, symbol, srcline |
--stdio |
— | 以文本形式输出,适合脚本处理 |
3.3.3 驱动热点分析示例
# 在设备上生成采样数据后,拉取到主机分析
adb pull /data/local/tmp/perf.data .
perf report -i perf.data --sort comm,dso,symbol --stdio | head -40
# 输出示例(驱动相关):
# # Overhead Command Shared Object Symbol
# # ........ ............... ..................... ......................
# 35.20% irq/296-5b10000 [kernel.kallsyms] [k] dma_alloc_from_pool
# 12.15% irq/296-5b10000 [kernel.kallsyms] [k] _raw_spin_lock_irqsave
# 8.70% irq/296-5b10000 [vendor_module.ko] [k] gpu_irq_handler
驱动调优要点:若热点集中在
dma_alloc_from_pool 或 _raw_spin_lock_irqsave,说明驱动在中断上下文中频繁进行内存分配或自旋锁竞争。优化方向包括:使用预分配 DMA 池、改用无锁数据结构、将耗时操作推迟到工作队列。
3.4 perf top:实时热点监控
perf top 类似于 Linux top 命令,但展示的是实时采样中最耗 CPU 的函数(符号)排名,适合在驱动运行过程中动态观察热点变化。
3.4.1 驱动实时监控命令
# 实时显示内核与用户空间热点(默认采样 cycles)
adb shell perf top
# 只显示内核态符号(驱动模块通常在内核态)
adb shell perf top -k vmlinux --kallsyms /proc/kallsyms
# 按特定事件排序(如 cache-misses)
adb shell perf top -e cache-misses -a
# 显示调用链(-g),帮助理解热点上下文
adb shell perf top -g -p $(pidof surfaceflinger)
3.4.2 常用参数
| 参数 | 说明 | 驱动场景 |
|---|---|---|
-e |
指定采样事件 | -e cache-misses 观察缓存未命中热点 |
-p |
只监控指定 PID | -p $(pidof irq/xxx) 聚焦中断线程 |
-K |
不显示用户空间符号 | 只关注内核驱动模块 |
-U |
不显示内核空间符号 | 分析用户态驱动 HAL 层 |
-n |
显示采样计数 | 评估热点函数的绝对采样频率 |
--sort |
排序方式(默认按 overhead) | --sort dso,symbol 按模块分组 |
性能开销注意:
perf top 默认以 1000 Hz 频率采样,在低端 Android 设备上可能引入 1-3% 的额外开销。对于生产环境或功耗敏感测试,建议降低采样频率(-F 100)或使用 perf record 离线分析。
3.5 命令选择矩阵
根据不同的驱动调优阶段,选择合适的 perf 命令可以事半功倍:
| 调优阶段 | 推荐命令 | 核心关注点 |
|---|---|---|
| 事件探索 | perf list |
确认目标 SoC 支持的 PMU 与 tracepoint |
| 快速评估 | perf stat |
IPC、cache-miss 率、上下文切换频率 |
| 热点定位 | perf record + report |
函数级热点、调用链、锁竞争 |
| 实时监控 | perf top |
动态观察热点变化,验证优化效果 |
驱动调优工作流建议:先
perf list 确认可用事件 → perf stat 快速评估整体指标 → 若发现异常(如 cache-miss 率 > 10%),使用 perf record -g 采样并生成报告 → 根据热点函数优化代码 → 用 perf top 实时验证优化效果。此闭环可高效迭代驱动性能。