3. Ftrace tracer类型

Ftrace 提供了多种内置 tracer,每种 tracer 针对不同的内核追踪需求设计。理解这些 tracer 的原理与适用场景,是进行中断上下文驱动调试和调度时延分析的基础。本章将逐一剖析核心 tracer 的工作机制与典型用途。

3.1 tracer 分类总览

Ftrace tracer 可按追踪粒度与目标分为以下四大类:

类别 tracer 名称 核心用途 典型场景
函数追踪 function 记录内核函数调用序列 代码路径分析、函数调用频率统计
函数调用图 function_graph 显示函数调用层级与耗时 函数级性能瓶颈定位、中断处理流程可视化
调度时延 wakeup / wakeup_rt 测量任务从唤醒到获得 CPU 的时延 实时系统调度延迟分析、优先级反转排查
中断/抢占关闭 irqsoff / preemptirqsoff 追踪中断或抢占被关闭的最长区间 系统实时性评估、非预期关中断/关抢占点定位
选择建议: 调试中断上下文时,优先使用 function_graph 观察中断处理函数内部调用链,配合 irqsoff 定位关中断导致的时延尖峰。

3.2 function tracer:轻量级函数调用追踪

function tracer 是 Ftrace 最基础的 tracer,它利用编译器为每个内核函数入口插入的 mcount(或 fentry)桩点,在函数被调用时记录其地址与进程上下文。

  • 原理: 内核启动时,Ftrace 将所有 mcount 调用替换为 nop 指令。启用 function tracer 后,动态地将目标函数的 nop 替换为对 Ftrace 回调函数的调用,从而捕获函数调用事件。
  • 输出: 每行包含时间戳、进程 PID、CPU 编号、函数名称。
  • 适用场景: 快速确认某个代码路径是否被执行、统计函数调用次数、过滤特定子系统的函数调用。
# 启用 function tracer
echo function > /sys/kernel/tracing/current_tracer
echo 1 > /sys/kernel/tracing/tracing_on
# 等待一段时间后查看
cat /sys/kernel/tracing/trace | head -20
注意: function tracer 会产生大量事件,在高频调用路径上可能导致显著的性能开销。建议配合 set_ftrace_filter 缩小追踪范围。

3.3 function_graph tracer:带层级的函数调用图

function_graph tracer 在 function tracer 的基础上增加了函数调用深度追踪和函数执行耗时统计,输出格式类似 C 语言函数调用缩进图。

  • 原理: 在函数入口和出口分别插入桩点。入口时记录时间戳并增加缩进层级;出口时计算函数执行时间,并输出对应的缩进结束标记。
  • 输出特点: 使用 } 表示函数返回,并在行尾显示执行耗时(微秒级)。
  • 适用场景: 中断处理函数内部调用链分析、驱动初始化流程调试、函数级性能热点定位。
# 启用 function_graph tracer
echo function_graph > /sys/kernel/tracing/current_tracer
echo 1 > /sys/kernel/tracing/tracing_on
# 查看中断上下文调用图
cat /sys/kernel/tracing/trace | grep -E "irq|interrupt" | head -30
function_graph tracer 输出示例(中断上下文) 0) irq_handler_entry | do_IRQ() { 0) handle_irq_event_percpu() { 0) my_interrupt_handler() { 0) readl() = 0x1234; /* 耗时 2.5 us */ 说明:缩进表示函数调用深度,行尾数字为函数执行耗时(微秒)。

3.4 wakeup 与 wakeup_rt tracer:调度时延测量

这两类 tracer 专门用于测量任务从被唤醒到实际获得 CPU 执行之间的时间差,是评估系统实时性能的关键工具。

  • wakeup tracer: 追踪所有非实时任务(SCHED_OTHER)的唤醒时延。记录从 try_to_wake_up() 被调用到任务开始执行的时间。
  • wakeup_rt tracer: 专注于实时任务(SCHED_FIFO / SCHED_RR)的唤醒时延。实时任务对调度延迟更敏感,此 tracer 能更精确地反映实时性能。
  • 原理: 在调度器唤醒路径上插入钩子,记录唤醒时间戳;在上下文切换时记录任务开始执行的时间戳,两者差值即为唤醒时延。
  • 适用场景: 实时系统验证、中断下半部导致调度延迟排查、优先级反转问题定位。
# 启用 wakeup_rt tracer(需内核支持 CONFIG_PREEMPT_RT 或相关配置)
echo wakeup_rt > /sys/kernel/tracing/current_tracer
echo 1 > /sys/kernel/tracing/tracing_on
# 触发实时任务唤醒后查看最大时延
cat /sys/kernel/tracing/tracing_max_latency
关键指标: 实时系统通常要求最大唤醒时延在几十微秒到几百微秒之间。如果 tracing_max_latency 显示毫秒级数值,说明系统中存在严重的关抢占或关中断区间。

3.5 irqsoff 与 preemptirqsoff tracer:关中断/关抢占区间追踪

这两类 tracer 用于定位系统中中断被关闭或抢占被禁止的最长区间,是分析系统实时性瓶颈的核心工具。

tracer 名称 追踪目标 记录内容 典型问题
irqsoff 本地中断被关闭的区间 调用 local_irq_disable() 到 local_irq_enable() 之间的代码路径 驱动中长时间关中断、自旋锁持有时间过长
preemptirqsoff 抢占被禁止的区间(含中断关闭) 调用 preempt_disable() 到 preempt_enable() 之间的代码路径 RCU 读锁持有时间过长、调度器锁竞争
  • 原理: 在 local_irq_disable / local_irq_enable 或 preempt_disable / preempt_enable 的桩点处记录时间戳。当关闭/开启操作发生时,计算区间长度,若超过当前记录的最大值,则保存完整的调用栈。
  • 输出: 最大延迟时间、触发时的 CPU、完整的函数调用栈回溯。
  • 适用场景: 系统实时性评估、非预期关中断点定位、PREEMPT_RT 内核调试。
# 启用 irqsoff tracer
echo irqsoff > /sys/kernel/tracing/current_tracer
echo 0 > /sys/kernel/tracing/tracing_max_latency
echo 1 > /sys/kernel/tracing/tracing_on
# 运行负载后查看最大关中断区间
cat /sys/kernel/tracing/trace
irqsoff tracer 工作流程 local_irq_disable() 记录 T1 时间戳 执行临界区代码(中断被屏蔽) local_irq_enable() 计算 ΔT = T2 - T1 若 ΔT > max_latency,保存调用栈 说明:irqsoff 通过比较关中断前后的时间戳,找出系统中关中断时间最长的代码路径。

3.6 tracer 选择决策矩阵

在实际调试中,应根据具体问题选择合适的 tracer。以下决策矩阵可帮助快速定位:

调试目标 推荐 tracer 辅助配置 预期输出
确认中断处理函数是否被执行 function set_ftrace_filter 指定函数名 函数调用记录行
分析中断处理函数内部调用链 function_graph set_graph_function 指定入口函数 带缩进和耗时的调用图
测量实时任务调度延迟 wakeup_rt 设置 tracing_max_latency 阈值 最大唤醒时延及对应调用栈
定位关中断导致的时延尖峰 irqsoff 配合 tracing_cpumask 指定 CPU 最长关中断区间及调用栈
排查抢占被禁止导致的调度问题 preemptirqsoff 内核需开启 CONFIG_PREEMPTIRQSOFF_TRACER 最长关抢占区间及调用栈
实践建议: 在嵌入式系统调试中,建议先使用 function_graph 获取中断处理函数的整体调用视图,再根据发现的耗时点,使用 irqsoff 或 wakeup_rt 进行精确的时延定位。这种“先宏观后微观”的策略能显著提升调试效率。