3. Linux 内核测量工具:perf、ftrace、trace-cmd 的基本使用与性能数据采集
在嵌入式 Linux 驱动性能优化中,测量是优化的前提。内核提供了三把利器:perf(性能计数器与采样)、ftrace(函数级跟踪)、trace-cmd(ftrace 的前端封装)。本章将系统讲解这三者的核心原理、基本用法以及如何采集驱动性能数据。
学习目标:掌握 perf 的 stat/record/report 命令、ftrace 的 tracefs 接口与 function_graph 跟踪器、trace-cmd 的 record/report 工作流,并能独立完成一次驱动中断延迟或函数耗时测量。
3.1 perf:性能计数器与采样分析
perf 基于 Performance Monitoring Unit (PMU) 硬件,能以极低开销统计 CPU 周期、缓存命中率、分支预测失败等硬件事件,也支持软件事件(如上下文切换、缺页中断)。
3.1.1 常用子命令与事件分类
| 子命令 | 功能 | 典型场景 |
|---|---|---|
perf stat |
运行命令并统计硬件/软件事件计数 | 对比优化前后的总周期数、指令数 |
perf record |
采样事件并写入 perf.data |
定位热点函数、调用链 |
perf report |
解析 perf.data 并展示采样结果 |
查看函数 CPU 占用百分比 |
perf top |
实时显示当前系统热点函数 | 快速定位驱动中断处理中的高耗时路径 |
perf list |
列出当前 CPU 支持的所有事件 | 确认硬件事件名称 |
3.1.2 驱动性能数据采集实战
场景:测量某 SPI 驱动在传输 1KB 数据时的 CPU 周期数与指令数。
# 1. 统计硬件事件
perf stat -e cycles,instructions,cache-misses \
dd if=/dev/spidev0.0 of=/dev/null bs=1024 count=1
# 2. 采样热点函数(频率 1000Hz,持续 5 秒)
perf record -F 1000 -g -p $(pidof spi_driver) -- sleep 5
# 3. 查看采样报告
perf report --stdio --sort symbol
关键指标解读:
- CPI (Cycles Per Instruction) = cycles / instructions。理想值接近 1.0,若 > 2.0 说明存在严重的流水线停顿或缓存未命中。
- cache-misses / cache-references 比率 > 5% 时,应考虑数据对齐或预取优化。
3.1.3 perf 驱动性能分析流程图
3.2 ftrace:函数级跟踪与延迟测量
ftrace 是内核内置的跟踪框架,通过 tracefs(挂载于 /sys/kernel/tracing)提供用户态接口。它支持多种跟踪器,其中 function_graph 能记录函数调用关系与执行时间,是驱动延迟分析的利器。
3.2.1 ftrace 核心文件与配置
| 文件路径 | 作用 | 常用值 |
|---|---|---|
current_tracer |
选择当前跟踪器 | function_graph, function, nop |
set_ftrace_filter |
只跟踪指定函数(支持通配符) | spi_*, my_driver_irq_handler |
set_ftrace_notrace |
排除不需要跟踪的函数 | schedule, __do_softirq |
tracing_on |
开关跟踪(1 开启,0 关闭) | 1, 0 |
trace |
读取跟踪结果 | cat 查看 |
trace_pipe |
流式读取跟踪结果(阻塞) | cat 持续输出 |
3.2.2 测量驱动中断处理函数耗时
# 1. 挂载 tracefs
mount -t tracefs tracefs /sys/kernel/tracing
cd /sys/kernel/tracing
# 2. 清空之前的跟踪
echo nop > current_tracer
echo > trace
# 3. 设置 function_graph 跟踪器,只跟踪中断处理函数
echo function_graph > current_tracer
echo my_irq_handler > set_ftrace_filter
# 4. 开启跟踪
echo 1 > tracing_on
# 5. 触发一次中断(例如发送 SPI 数据)
spi_send_data
# 6. 关闭跟踪并查看结果
echo 0 > tracing_on
cat trace
注意事项:
- 生产环境开启 ftrace 会增加函数调用开销(约 0.5~2 µs/次),建议只过滤关键函数。
- 使用
trace_pipe时注意缓冲区溢出,可配合buffer_size_kb调整大小。 - ARM64 平台需确保内核配置
CONFIG_FUNCTION_GRAPH_TRACER=y。
3.2.3 ftrace function_graph 输出示例
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
0) 3.125 us | my_irq_handler();
0) 1.002 us | readl();
0) 0.503 us | writel();
0) 0.750 us | my_clear_interrupt();
0) 4.380 us | } /* my_irq_handler */
从输出可见:中断处理函数总耗时 4.38 µs,其中 readl 占 1.0 µs,writel 占 0.5 µs。若总耗时超过 10 µs,应考虑将部分工作移至 tasklet 或 workqueue。
3.3 trace-cmd:ftrace 的前端封装
trace-cmd 是对 ftrace 的封装,提供更友好的命令行接口,支持 记录(record)、报告(report)、流式输出(stream)等操作。它自动处理 tracefs 的配置与清理,适合脚本化采集。
3.3.1 trace-cmd 基本工作流
| 步骤 | 命令 | 说明 |
|---|---|---|
| 1. 记录跟踪数据 | trace-cmd record -p function_graph -l my_irq_handler ./test_app |
运行 test_app 并记录其内核函数调用 |
| 2. 查看报告 | trace-cmd report |
解析 trace.dat 并输出可读结果 |
| 3. 流式监控 | trace-cmd stream -p function_graph -l my_irq_handler |
实时输出跟踪数据,类似 trace_pipe |
| 4. 提取特定事件 | trace-cmd report -F 'irq_handler_entry' |
只显示中断入口事件 |
3.3.2 采集驱动中断延迟数据
# 记录 10 秒内所有中断相关事件
trace-cmd record -e irq:irq_handler_entry -e irq:irq_handler_exit \
-T -F 'common_pid != 0' sleep 10
# 查看每个中断处理函数的耗时
trace-cmd report --cpu-time | grep "irq_handler"
trace-cmd 优势:
- 自动处理 tracefs 挂载与权限,无需手动 echo 配置。
- 支持 事件过滤(-F)和 函数过滤(-l),减少数据量。
- 输出格式统一,便于脚本解析(如
--ts2sec转换时间戳)。
3.4 三款工具对比与选型
| 维度 | perf | ftrace | trace-cmd |
|---|---|---|---|
| 主要用途 | 硬件事件计数、采样热点 | 函数调用跟踪、延迟分析 | ftrace 的易用封装 |
| 开销 | 极低(硬件 PMU) | 中等(函数级插桩) | 同 ftrace |
| 适用场景 | CPU 利用率、缓存优化 | 中断延迟、驱动函数耗时 | 自动化脚本、批量采集 |
| 输出格式 | 二进制 perf.data | 文本 trace | 二进制 trace.dat |
| 内核配置要求 | CONFIG_PERF_EVENTS=y |
CONFIG_FUNCTION_TRACER=y |
同 ftrace + CONFIG_TRACING=y |
3.5 综合数据采集策略
在实际驱动优化中,建议按以下流程组合使用三款工具:
- perf top 快速扫描,定位 CPU 占用最高的驱动函数。
- perf record/report 深入分析热点函数的调用链与 CPI。
- ftrace function_graph 测量关键函数的精确耗时,确认延迟瓶颈。
- trace-cmd record 在自动化测试中批量采集,对比优化前后的数据。
实战建议:在嵌入式板卡上,优先使用
perf stat 做快速评估,因为其开销最小。当需要定位具体函数时,再切换到 ftrace 或 trace-cmd,并务必使用 set_ftrace_filter 缩小跟踪范围,避免跟踪缓冲区溢出导致系统卡顿。