2. Ftrace基础
Ftrace(Function Tracer)是 Linux 内核内置的追踪框架,专为调试实时性、中断响应延迟和函数调用路径而设计。它通过静态插桩和动态改写指令,以极低开销记录内核函数的进入/退出、调度点与中断上下文切换。理解 Ftrace 的架构层次与用户态接口,是后续进行中断上下文驱动调试的基石。
2.1 Ftrace 架构概览
Ftrace 采用分层 + 插件化设计,从上到下分为三层:用户态接口层、核心框架层和底层插桩层。核心框架负责管理追踪器(tracer)的注册、环形缓冲区(ring buffer)的分配以及过滤规则的匹配;底层插桩则通过 mcount/fentry 或 kprobe 机制捕获函数执行流。
架构要点:所有追踪数据最终写入统一的 per-CPU 环形缓冲区,用户通过
trace 文件读取;不同 tracer 只是对原始数据的解析和呈现方式不同。
2.2 tracefs 文件系统挂载
Ftrace 的用户态接口通过 tracefs(Trace File System)暴露。在大多数现代发行版中,tracefs 会自动挂载到 /sys/kernel/tracing;若未自动挂载,可手动执行以下命令:
# 挂载 tracefs 到标准路径
mount -t tracefs tracefs /sys/kernel/tracing
# 验证挂载
ls /sys/kernel/tracing/
兼容性提示:旧版内核(< 3.10)将 Ftrace 接口放在
/sys/kernel/debug/tracing 下,需先挂载 debugfs。建议统一使用 /sys/kernel/tracing 路径。
挂载成功后,/sys/kernel/tracing/ 目录下会出现数十个控制文件和状态文件。下表列出最核心的三个文件:
| 文件名称 | 类型 | 功能描述 |
|---|---|---|
available_tracers |
只读 | 列出当前内核支持的所有 tracer 名称(如 function、irqsoff、preemptoff、wakeup、nop 等) |
current_tracer |
读写 | 写入 tracer 名称以激活对应追踪器;读取可查看当前激活的 tracer |
trace |
只读 | 输出当前环形缓冲区中的追踪结果(人类可读格式);写入 echo 0 > trace 可清空缓冲区 |
2.3 核心文件详解
2.3.1 available_tracers —— 查看可用追踪器
该文件列出内核编译时开启的所有 tracer 插件。不同内核配置输出的列表可能不同,典型输出如下:
# cat /sys/kernel/tracing/available_tracers
function function_graph irqsoff preemptoff preemptirqsoff wakeup wakeup_dl wakeup_rt nop
各 tracer 的用途简要说明:
- function —— 追踪所有内核函数的调用,输出函数名与 PID。
- function_graph —— 以 C 调用图风格显示函数嵌套关系,适合分析调用链深度。
- irqsoff —— 追踪中断被关闭的最大时长,用于检测关中断导致的调度延迟。
- preemptoff —— 追踪抢占被关闭的最大时长,用于分析内核态不可抢占路径。
- preemptirqsoff —— 同时追踪关中断和关抢占的叠加延迟。
- wakeup / wakeup_rt / wakeup_dl —— 追踪高优先级任务从唤醒到获得 CPU 的调度延迟。
- nop —— 空追踪器,不记录任何数据,用于关闭追踪。
注意:若
available_tracers 中缺少 irqsoff 或 preemptoff,说明内核未开启 CONFIG_IRQSOFF_TRACER 或 CONFIG_PREEMPT_TRACER,需要重新编译内核。
2.3.2 current_tracer —— 激活追踪器
通过向 current_tracer 写入 tracer 名称来启动追踪。写入 nop 则停止追踪。典型操作流程:
# 1. 查看当前激活的 tracer(默认 nop)
cat /sys/kernel/tracing/current_tracer
nop
# 2. 激活 function tracer
echo function > /sys/kernel/tracing/current_tracer
# 3. 验证激活状态
cat /sys/kernel/tracing/current_tracer
function
# 4. 停止追踪(恢复 nop)
echo nop > /sys/kernel/tracing/current_tracer
最佳实践:切换 tracer 前务必先写入
nop 清空状态,避免残留数据干扰新 tracer 的输出。
2.3.3 trace —— 读取追踪结果
trace 文件是 Ftrace 最主要的输出接口。激活 tracer 后,内核将追踪数据写入 per-CPU 环形缓冲区,用户读取 trace 即可获得格式化文本。以下是一个 function tracer 的示例输出:
# tracer: function
#
# entries-in-buffer/entries-written: 1423/1423 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
<idle>-0 [000] d..2. 1234.567890: _raw_spin_unlock_irqrestore
<idle>-0 [000] d..2. 1234.567891: __do_softirq
<idle>-0 [000] .ns2. 1234.567892: run_timer_softirq
kworker-123 [001] d..1. 1234.567900: mutex_lock
kworker-123 [001] d..1. 1234.567901: __mutex_lock_slowpath
输出字段含义:
| 字段 | 说明 |
|---|---|
| TASK-PID | 任务名称和进程 ID |
| CPU# | 运行在哪个 CPU 核心上 |
| irqs-off | d 表示关中断,. 表示开中断 |
| need-resched | N 表示需要重新调度,. 表示不需要 |
| hardirq/softirq | h 硬中断上下文,s 软中断上下文,. 进程上下文 |
| preempt-depth | 抢占锁嵌套深度(数值越大越不可抢占) |
| TIMESTAMP | 事件发生的时间戳(秒.微秒) |
| FUNCTION | 被追踪的内核函数名称 |
2.4 快速上手:第一个 Ftrace 实验
以下步骤演示如何挂载 tracefs、激活 function tracer 并读取追踪结果:
- 挂载 tracefs(如未自动挂载):
mount -t tracefs tracefs /sys/kernel/tracing - 查看可用 tracer:
cat /sys/kernel/tracing/available_tracers - 激活 function tracer:
echo function > /sys/kernel/tracing/current_tracer - 触发一些内核活动(例如执行
ls或ping):ls /tmp - 读取追踪结果:
cat /sys/kernel/tracing/trace | head -30 - 停止追踪:
echo nop > /sys/kernel/tracing/current_tracer
调试技巧:若
trace 输出为空,检查是否已写入 current_tracer 且内核配置开启了 CONFIG_FUNCTION_TRACER。也可先写入 echo 1 > tracing_on 确保追踪开关已打开。