4. ftrace 核心概念:tracer、trace event、filter、trigger、instance
ftrace 是 Linux 内核内置的跟踪框架,其设计围绕五个核心概念展开:tracer(跟踪器)、trace event(跟踪事件)、filter(过滤)、trigger(触发)和 instance(实例)。理解这五个概念是掌握 ftrace 调试能力的基础。
4.1 Tracer(跟踪器)
Tracer 是 ftrace 中最上层的抽象,它定义了一种特定的数据采集模式。每个 tracer 对应一个内核子系统或一种跟踪策略,通过 /sys/kernel/tracing/current_tracer 文件选择激活。
| Tracer 名称 | 功能描述 | 典型场景 |
|---|---|---|
| function | 跟踪所有内核函数的调用入口和返回 | 函数调用路径分析、性能热点定位 |
| function_graph | 以调用图形式显示函数嵌套关系,包含执行时间 | 函数耗时分析、调用链可视化 |
| nop | 空跟踪器,不采集任何数据 | 关闭跟踪、释放资源 |
| irqsoff | 跟踪中断被关闭的最大时长 | 实时性分析、中断延迟排查 |
| preemptoff | 跟踪抢占被关闭的最大时长 | 实时性分析、调度延迟排查 |
| wakeup | 跟踪高优先级任务从唤醒到获得 CPU 的延迟 | 调度延迟测量、RT 任务性能 |
trace 文件,可通过 cat /sys/kernel/tracing/trace 读取。
function_graph 是日常调试中使用频率最高的 tracer,它同时提供函数调用关系和执行时间,适合快速定位性能瓶颈。
4.2 Trace Event(跟踪事件)
Trace event 是 ftrace 中最细粒度的数据采集单元。与 tracer 不同,trace event 由内核代码中的 tracepoint 静态定义,每个事件对应一个特定的内核行为(如系统调用、调度切换、中断触发)。
事件通过 /sys/kernel/tracing/events/ 目录组织,按子系统分组:
# 查看所有可用事件子系统
ls /sys/kernel/tracing/events/
# 启用特定事件(以 syscalls 子系统为例)
echo 1 > /sys/kernel/tracing/events/syscalls/sys_enter_openat/enable
# 启用整个子系统
echo 1 > /sys/kernel/tracing/events/syscalls/enable
| 子系统 | 事件示例 | 用途 |
|---|---|---|
| syscalls | sys_enter_openat, sys_exit_read | 系统调用跟踪 |
| sched | sched_switch, sched_wakeup | 调度行为分析 |
| irq | irq_handler_entry, irq_handler_exit | 中断处理跟踪 |
| block | block_rq_complete, block_rq_insert | 块设备 I/O 分析 |
| kmem | kmalloc, kfree | 内存分配跟踪 |
4.3 Filter(过滤)
Filter 机制允许用户对 trace event 设置条件表达式,只有满足条件的事件才会被记录。这在大规模跟踪时能有效减少数据量,聚焦目标行为。
Filter 通过事件目录下的 filter 文件配置,支持对事件字段进行逻辑运算:
# 只记录 PID 为 1234 的进程的系统调用
echo "common_pid == 1234" > /sys/kernel/tracing/events/syscalls/sys_enter_openat/filter
# 复合条件:PID 为 1234 且返回值大于 0
echo "common_pid == 1234 && ret > 0" > /sys/kernel/tracing/events/syscalls/sys_exit_openat/filter
# 清除 filter
echo 0 > /sys/kernel/tracing/events/syscalls/sys_enter_openat/filter
| 操作符 | 说明 | 示例 |
|---|---|---|
| == | 等于 | common_pid == 100 |
| != | 不等于 | common_pid != 0 |
| > / < | 大于 / 小于 | latency > 1000 |
| && / || | 逻辑与 / 或 | pid == 100 && cpu == 0 |
| ~ | 正则匹配(字符串字段) | comm ~ "sshd" |
common_pid(进程 PID)、common_comm(进程名)、cpu(CPU 编号)。
4.4 Trigger(触发)
Trigger 是 ftrace 的事件驱动机制,允许在事件触发时执行预定义的动作。Trigger 通过事件目录下的 trigger 文件配置,支持多种动作类型。
| Trigger 类型 | 动作 | 典型用法 |
|---|---|---|
| traceon | 事件触发时开启跟踪 | 条件触发后开始记录 |
| traceoff | 事件触发时关闭跟踪 | 捕获特定事件后停止 |
| snapshot | 事件触发时保存当前跟踪缓冲区快照 | 保留异常时刻的上下文 |
| enable_event | 事件触发时启用另一个事件 | 级联跟踪 |
| disable_event | 事件触发时禁用另一个事件 | 动态控制事件开关 |
| stacktrace | 事件触发时记录内核栈回溯 | 定位调用路径 |
# 当 sched_switch 事件触发时,记录内核栈
echo 'stacktrace' > /sys/kernel/tracing/events/sched/sched_switch/trigger
# 当 sys_enter_openat 触发时,启用 sys_exit_openat 事件
echo 'enable_event:syscalls:sys_exit_openat' > /sys/kernel/tracing/events/syscalls/sys_enter_openat/trigger
# 清除所有 trigger
echo '!stacktrace' > /sys/kernel/tracing/events/sched/sched_switch/trigger
stacktrace 和 snapshot。在生产环境中使用时需评估性能影响。
4.5 Instance(实例)
Instance 是 ftrace 的隔离机制,允许创建多个独立的跟踪上下文。每个 instance 拥有独立的缓冲区、tracer 和事件配置,互不干扰。这在同时调试多个子系统或多个进程时极为有用。
Instance 通过 /sys/kernel/tracing/instances/ 目录管理:
# 创建新实例
mkdir /sys/kernel/tracing/instances/my_instance
# 在实例中配置 tracer
echo function_graph > /sys/kernel/tracing/instances/my_instance/current_tracer
# 在实例中启用事件
echo 1 > /sys/kernel/tracing/instances/my_instance/events/sched/sched_switch/enable
# 读取实例的跟踪数据
cat /sys/kernel/tracing/instances/my_instance/trace
# 删除实例
rmdir /sys/kernel/tracing/instances/my_instance
| 特性 | 默认实例(top-level) | 自定义实例 |
|---|---|---|
| 缓冲区 | 全局共享 | 独立分配 |
| 配置隔离 | 全局生效 | 实例内独立 |
| 性能影响 | 所有事件共享开销 | 仅影响实例内事件 |
| 适用场景 | 单一目标调试 | 多目标并行调试 |
trace 文件独立,可以同时运行多个 cat 命令读取不同实例的数据,实现并行监控。
4.6 五者协同工作流
在实际调试中,这五个概念通常协同使用,形成完整的数据采集链路:
- 选择 tracer:通过
current_tracer确定数据采集模式(如 function_graph)。 - 启用事件:在
events/下选择需要跟踪的具体事件。 - 设置 filter:对事件字段添加条件,只记录目标数据。
- 配置 trigger:定义事件触发时的附加动作(如 stacktrace)。
- 使用 instance:为不同调试目标创建隔离的跟踪上下文。
# 创建两个实例
mkdir /sys/kernel/tracing/instances/proc_a
mkdir /sys/kernel/tracing/instances/proc_b
# 实例 A:跟踪进程 100 的系统调用
echo 1 > /sys/kernel/tracing/instances/proc_a/events/syscalls/enable
echo "common_pid == 100" > /sys/kernel/tracing/instances/proc_a/events/syscalls/filter
# 实例 B:跟踪进程 200 的调度事件
echo 1 > /sys/kernel/tracing/instances/proc_b/events/sched/enable
echo "common_pid == 200" > /sys/kernel/tracing/instances/proc_b/events/sched/filter
# 分别读取数据
cat /sys/kernel/tracing/instances/proc_a/trace
cat /sys/kernel/tracing/instances/proc_b/trace
通过这种组合方式,ftrace 能够以极低的性能开销实现高度定制化的内核行为跟踪,满足从性能分析到故障定位的多种调试需求。