3. ftrace 基础框架:tracefs 挂载与核心操作
ftrace 是 Linux 内核内置的跟踪器,用于分析内核行为、函数调用和调度延迟。在实时性测试中,ftrace 是测量调度延迟、抢占延迟和中断响应时间的关键工具。本章将系统讲解 ftrace 的基础框架,包括 tracefs 文件系统的挂载、跟踪器的查看与选择、跟踪数据的读取以及跟踪启停控制。
3.1 tracefs 文件系统挂载
ftrace 通过 tracefs 虚拟文件系统暴露控制接口和跟踪数据。在大多数现代 Linux 发行版中,tracefs 默认挂载在 /sys/kernel/tracing 目录下。如果未自动挂载,需要手动执行挂载操作。
# 挂载 tracefs 到标准路径
mount -t tracefs tracefs /sys/kernel/tracing
# 或使用 debugfs(旧方式,兼容性考虑)
mount -t debugfs debugfs /sys/kernel/debug
# 此时 ftrace 接口位于 /sys/kernel/debug/tracing
/sys/kernel/tracing 路径,这是内核主线推荐的标准化接口。在实时性测试脚本中,建议在脚本开头检查挂载状态并自动挂载。
挂载成功后,/sys/kernel/tracing 目录下会出现一系列控制文件和跟踪数据文件。下表列出了最核心的文件及其用途:
| 文件/目录 | 用途 | 读写属性 |
|---|---|---|
available_tracers |
列出当前内核支持的所有跟踪器 | 只读 |
current_tracer |
设置或查看当前激活的跟踪器 | 读写 |
tracing_on |
全局跟踪开关(1=开启,0=关闭) | 读写 |
trace |
读取跟踪数据(人类可读格式) | 只读 |
trace_pipe |
流式读取跟踪数据(持续输出) | 只读 |
buffer_size_kb |
每个 CPU 的跟踪缓冲区大小(KB) | 读写 |
tracing_cpumask |
限制跟踪只在指定 CPU 上运行 | 读写 |
set_ftrace_filter |
函数跟踪过滤器(白名单) | 读写 |
set_ftrace_notrace |
函数跟踪排除列表(黑名单) | 读写 |
buffer_size_kb 的默认值通常较小(约 1-4 MB)。对于长时间调度延迟跟踪,建议增大到 16-64 MB,避免跟踪数据被覆盖丢失。
3.2 available_tracers:查看可用跟踪器
available_tracers 文件列出了当前内核编译时启用的所有跟踪器。不同内核配置支持的跟踪器种类不同,实时性测试中常用的跟踪器包括:
- nop —— 空跟踪器,不记录任何数据,用于关闭跟踪。
- function —— 函数调用跟踪,记录内核函数的进入和退出。
- function_graph —— 函数调用图跟踪,显示函数调用层级和耗时。
- preemptirqsoff —— 跟踪抢占和中断关闭的最大时间(实时性关键指标)。
- preemptoff —— 仅跟踪抢占关闭时间。
- irqsoff —— 仅跟踪中断关闭时间。
- wakeup —— 跟踪最高优先级任务的调度唤醒延迟。
- wakeup_rt —— 跟踪实时(RT)任务的调度唤醒延迟。
- wakeup_dl —— 跟踪 deadline 调度类的任务唤醒延迟。
cat /sys/kernel/tracing/available_tracers
示例输出:
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
输出结果中,跟踪器名称之间用空格分隔。当前激活的跟踪器会用方括号 [] 标记。例如 [function] 表示当前正在使用 function 跟踪器。
3.3 current_tracer:设置当前跟踪器
current_tracer 文件用于激活指定的跟踪器。写入跟踪器名称即可切换,写入 nop 则关闭跟踪。
# 切换到 function_graph 跟踪器
echo function_graph > /sys/kernel/tracing/current_tracer
# 关闭跟踪(切换到 nop)
echo nop > /sys/kernel/tracing/current_tracer
# 查看当前跟踪器
cat /sys/kernel/tracing/current_tracer
wakeup_rt 或 wakeup_dl 跟踪器。它们专门记录高优先级任务从唤醒到开始执行的时间差,直接反映调度延迟。
切换跟踪器时,内核会自动重置跟踪缓冲区。因此,先设置跟踪器,再开启跟踪是标准操作流程。
3.4 tracing_on:跟踪启停控制
tracing_on 是全局跟踪开关,控制是否向缓冲区写入跟踪数据。写入 1 开启跟踪,写入 0 暂停跟踪。注意:暂停跟踪不会清空缓冲区,已记录的数据仍然可以读取。
# 开启跟踪
echo 1 > /sys/kernel/tracing/tracing_on
# 暂停跟踪
echo 0 > /sys/kernel/tracing/tracing_on
# 查看当前状态
cat /sys/kernel/tracing/tracing_on
tracing_on 设置为 0 只是暂停写入,不会清空缓冲区。如果需要清空历史数据,需要向 trace 文件写入空内容或重置跟踪器。标准清空操作为:echo > /sys/kernel/tracing/trace。
3.5 trace 文件读取与数据解析
trace 文件以人类可读的文本格式输出跟踪数据。每行记录包含时间戳、进程信息、CPU 编号和跟踪事件详情。
# 读取全部数据
cat /sys/kernel/tracing/trace
# 实时流式读取(类似 tail -f)
cat /sys/kernel/tracing/trace_pipe
以下是一个典型的 function_graph 跟踪输出示例:
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
0) 0.125 us | _raw_spin_lock();
0) 0.062 us | _raw_spin_unlock();
0) | try_to_wake_up() {
0) 0.250 us | _raw_spin_lock_irqsave();
0) 0.125 us | ttwu_queue();
0) 0.125 us | _raw_spin_unlock_irqrestore();
0) 1.000 us | }
0) 0.125 us | _raw_spin_lock();
0) 0.062 us | _raw_spin_unlock();
各字段含义:
- CPU —— 事件发生的 CPU 编号。
- DURATION —— 函数执行耗时(微秒),仅 function_graph 模式有此列。
- FUNCTION CALLS —— 函数调用层级和名称,缩进表示调用深度。
对于调度延迟分析,重点关注 wakeup_rt 跟踪器的输出,它直接给出从唤醒到调度的时间差:
# tracer: wakeup_rt
#
# Task: PID: 1234 (cyclictest)
# Duration: 45.125 us
# CPU: 2
#
# <idle>-0 [002] d..3 1234.567890: sched_wakeup: comm=cyclictest pid=1234 prio=95 target_cpu=002
# <idle>-0 [002] d..3 1234.567935: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 next_comm=cyclictest next_pid=1234 next_prio=95
其中 Duration: 45.125 us 就是调度延迟值,即从 sched_wakeup 事件到 sched_switch 事件的时间差。
3.6 ftrace 基础操作流程 SVG 图
下图展示了 ftrace 基础操作的标准流程,从挂载 tracefs 到读取调度延迟数据的完整步骤:
3.7 实时性测试中的典型操作序列
在实际的实时性测试中,ftrace 操作通常遵循以下标准序列。建议将以下命令封装为脚本,便于重复执行:
#!/bin/bash
TRACING=/sys/kernel/tracing
# 1. 确保 tracefs 已挂载
if ! mountpoint -q $TRACING; then
mount -t tracefs tracefs $TRACING
fi
# 2. 清空历史数据
echo nop > $TRACING/current_tracer
echo > $TRACING/trace
# 3. 设置跟踪器(以 wakeup_rt 为例)
echo wakeup_rt > $TRACING/current_tracer
# 4. 增大缓冲区(避免丢失数据)
echo 16384 > $TRACING/buffer_size_kb
# 5. 开启跟踪
echo 1 > $TRACING/tracing_on
# 6. 运行测试程序(示例)
cyclictest -p 95 -t 1 -i 1000 -l 10000
# 7. 暂停跟踪
echo 0 > $TRACING/tracing_on
# 8. 提取调度延迟数据
grep "Duration" $TRACING/trace
wakeup_rt 和 wakeup_dl 跟踪器的开销极小(仅记录特定调度事件),适合在生产环境或接近生产环境的测试中使用。
3.8 常见问题与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
cat trace 输出为空 |
跟踪未开启或缓冲区被清空 | 检查 tracing_on 是否为 1;确认 current_tracer 不是 nop |
available_tracers 列表很短 |
内核编译时未启用相关跟踪器 | 重新编译内核,开启 CONFIG_FUNCTION_TRACER、CONFIG_PREEMPTIRQ_TRACEPOINTS 等选项 |
| 跟踪数据丢失或截断 | 缓冲区太小,数据被覆盖 | 增大 buffer_size_kb,或使用 trace_pipe 实时读取 |
设置跟踪器时报错 Device or resource busy |
其他进程正在使用 ftrace | 检查是否有其他跟踪工具(如 perf、trace-cmd)占用,先关闭它们 |
| 调度延迟数据不准确 | ftrace 自身开销干扰了调度 | 使用 wakeup_rt 而非 function 跟踪器;减小缓冲区大小;限制跟踪 CPU 范围 |
3.9 本章小结
ftrace 的基础框架由 tracefs 文件系统提供,核心操作包括:
- 挂载 tracefs —— 确保
/sys/kernel/tracing可用。 - 查看 available_tracers —— 确认内核支持的跟踪器类型。
- 设置 current_tracer —— 选择适合实时性测试的跟踪器(如 wakeup_rt)。
- 控制 tracing_on —— 精确控制跟踪的启停时机。
- 读取 trace 文件 —— 解析调度延迟数据,提取 Duration 字段。