kernel/trace 内核追踪(ftrace/tracing)机制与原理详解
源码路径:
rk3588/kernel-6.1/kernel/trace/
内核版本:Linux 6.1(RK3588 平台)
平台:RK3588(4×Cortex-A76 + 4×Cortex-A55 big.LITTLE,ARM64)
该目录实现 Linux 内核 ftrace / tracing 子系统:函数追踪、tracepoint 事件、延迟分析、动态探针(kprobe/uprobe)、BPF 挂载、块 I/O 追踪、Runtime Verification 等。数据经 per-CPU ring buffer 缓冲,通过 tracefs(/sys/kernel/debug/tracing/)对用户空间暴露控制与读取接口。
定位:内核可观测性核心;tracepoint 定义分散于各子系统
include/trace/events/,架构 ftrace 入口在arch/arm64/kernel/ftrace.c、entry-common.S。
目录
- 一、追踪子系统概览
- 二、源码目录结构
- 三、Kconfig 与 RK3588 默认配置
- 四、整体架构
- 五、核心数据结构
- 六、Ring Buffer 环形缓冲区
- 七、ftrace 函数追踪引擎
- 八、Tracer 插件机制
- 九、Trace Event 事件系统
- 十、动态探针、fprobe 与 BPF
- 十一、Latency 延迟追踪器
- 十二、追踪时钟(trace_clock.c)
- 十三、Runtime Verification(rv/)
- 十四、tracefs 用户接口
- 十五、RK3588/ARM64 平台说明
- 十六、完整追踪时序
- 十七、总结
- 附录:源文件清单
一、追踪子系统概览
Linux tracing 解决「在不改内核源码的前提下,观测内核运行时行为」:
| 能力 | 机制 | 典型用途 |
|---|---|---|
| 函数追踪 | mcount/fentry + dynamic ftrace | 调用链、性能热点 |
| 静态事件 | TRACE_EVENT tracepoint | sched、irq、block、power |
| 动态探针 | kprobe/uprobe | 任意内核/用户函数探测 |
| 延迟分析 | irqsoff/wakeup/hwlat tracer | 实时性、中断延迟 |
| BPF | bpf_trace.c | 可编程追踪、perf 集成 |
| 聚合 | hist trigger + tracing_map | 直方图、延迟分布 |
设计原则:写路径 per-CPU 无锁;关闭 tracing 时 dynamic ftrace patch 为 NOP,接近零开销。
二、源码目录结构
2.1 Kconfig 依赖树
1 | TRACING_SUPPORT |
2.2 编译依赖(Makefile)
1 | obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o # ftrace.c |
注意:ccflags-remove-$(CONFIG_FUNCTION_TRACER) += $(CC_FLAGS_FTRACE) — trace 目录自身 不被 ftrace 插桩,避免递归。
2.3 源文件分类
| 分类 | 主要文件 | 说明 |
|---|---|---|
| 核心 | trace.c, trace.h |
tracefs、tracer 管理、读写迭代器 |
| 存储 | ring_buffer.c |
per-CPU 环形缓冲区 |
| ftrace | ftrace.c, fgraph.c |
dynamic patch、filter、function graph 辅助 |
| 输出 | trace_output.c, trace_seq.c |
entry → 文本格式化 |
| 事件 | trace_events.c, trace_events_*.c |
注册、filter、trigger、hist |
| Tracer | trace_functions*.c, trace_irqsoff.c, … |
各 tracer 插件 |
| 探针 | trace_kprobe.c, trace_uprobe.c, trace_probe.c |
动态 event |
| BPF | bpf_trace.c |
BPF 挂载 tracepoint/kprobe |
| 钩子 | fprobe.c, rethook.c |
基于 ftrace 的 entry/exit 探针 |
| RV | rv/rv.c, rv/monitors/ |
运行时形式化验证 |
| 辅助 | trace_clock.c, pid_list.c, trace_boot.c |
时钟、PID 过滤、启动 tracing |
三、Kconfig 与 RK3588 默认配置
3.1 关键配置项
| 配置项 | 默认 | 说明 |
|---|---|---|
CONFIG_FUNCTION_TRACER |
架构 select | 函数入口插桩 |
CONFIG_DYNAMIC_FTRACE |
y | 运行时 NOP ↔ call patch |
CONFIG_DYNAMIC_FTRACE_WITH_REGS |
ARM64 y | 回调可获 pt_regs |
CONFIG_FUNCTION_GRAPH_TRACER |
y | 函数调用图 + 耗时 |
CONFIG_EVENT_TRACING |
FUNCTION_TRACER 时 | tracepoint 框架 |
CONFIG_KPROBE_EVENTS |
y(KPROBES) | 动态 kprobe event |
CONFIG_UPROBE_EVENTS |
y(ARM64) | 用户态探针 |
CONFIG_BPF_EVENTS |
BPF+PERF | BPF 程序挂载 |
CONFIG_FPROBE |
n | 轻量 ftrace 探针 |
CONFIG_RV |
n | Runtime Verification |
3.2 RK3588 defconfig
arch/arm64/configs/rockchip_linux_defconfig:
1 | CONFIG_FUNCTION_TRACER=y |
ARM64 Kconfig 自动 select:
HAVE_FUNCTION_TRACER/HAVE_DYNAMIC_FTRACEHAVE_DYNAMIC_FTRACE_WITH_REGS(GCC/Clang)FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY— 使用__patchable_function_entries段HAVE_FTRACE_MCOUNT_RECORD
启用 FUNCTION_TRACER 后,通常连带启用 DYNAMIC_FTRACE、FUNCTION_GRAPH_TRACER、EVENT_TRACING、KPROBE_EVENTS 等(Kconfig default y)。
四、整体架构
1 | ┌─────────────────────────────────────────────────────────────┐ |
数据流:插桩点触发 → ring_buffer_lock_reserve() 预留空间 → 写入 trace_entry → ring_buffer_unlock_commit() → 用户读 trace/trace_pipe → print_line / event format 格式化。
五、核心数据结构
5.1 trace_entry — 事件通用头
1 | struct trace_entry { |
5.2 trace_type — 内置类型
| 类型 | 含义 |
|---|---|
TRACE_FN |
函数调用(function tracer) |
TRACE_GRAPH_ENT/RET |
函数图入口/返回 |
TRACE_CTX |
上下文切换 |
TRACE_WAKE |
唤醒 |
TRACE_PRINT |
trace_printk |
TRACE_BLK |
块 I/O |
TRACE_HWLAT / TRACE_OSNOISE / TRACE_TIMERLAT |
延迟/噪声 |
5.3 trace_array — 追踪实例
1 | struct trace_array { |
- 全局实例:
top_trace_array()/global_trace_array - 子实例:
/instances/<name>/独立 buffer 与 tracer
5.4 tracer — 插件虚函数表
1 | struct tracer { |
注册:register_tracer();用户选择:echo xxx > current_tracer。
六、Ring Buffer 环形缓冲区
ring_buffer.c(~6234 行)是 tracing 的统一存储引擎。
6.1 设计要点
- per-CPU buffer:写者只写本 CPU 页链表,无全局写锁
- Reader page:读者专用页,读完后与 ring 中页 swap
- 压缩时间戳:5-bit type_len + 27-bit delta;必要时
TIME_EXTEND/TIME_STAMP - 嵌套写入:中断/NMI 上下文可嵌套 reserve/commit
- Splice:已读页可零拷贝传给用户态
6.2 页面模型
1 | reader page ring pages (per-CPU) |
6.3 主要 API
| 函数 | 功能 |
|---|---|
ring_buffer_alloc() |
分配 per-CPU buffer |
ring_buffer_lock_reserve() |
预留 event 空间 |
ring_buffer_unlock_commit() |
提交写入 |
ring_buffer_read() |
读取下一 event |
ring_buffer_overwrite() |
覆盖模式(丢最旧) |
ring_buffer_resize() |
动态调整 buffer 大小 |
启动时 buffer 为最小尺寸(ring_buffer_expanded),首次启用 tracing 时扩展,避免空闲占内存。
七、ftrace 函数追踪引擎
7.1 编译期插桩(ARM64)
RK3588 使用 patchable function entries:
- 编译器
-mrecord-mcount或-mfentry在每个函数入口留下可 patch 点 __patchable_function_entries/mcount_loc段记录所有位置- 架构代码:
arch/arm64/kernel/ftrace.c、entry-ftrace.S
7.2 Dynamic Ftrace
ftrace.c(~8479 行)核心流程:
- Boot:所有插桩点 patch 为 AArch64 NOP(或 branch stub)
- Enable:NOP →
bl ftrace_caller(或等价指令) - Filter:
set_ftrace_filter/set_ftrace_notracehash 表 per-ops 过滤
1 | struct ftrace_ops *function_trace_op; |
ftrace_ops 字段:func 回调、flags(PID 过滤、SAVE_REGS、IPMODIFY 等)、func_hash filter。
7.3 Function Tracer 写入路径
1 | some_func() |
7.4 Function Graph
trace_functions_graph.c + fgraph.c:在 entry 压栈返回地址,return 时弹栈计算 duration,输出缩进调用图。
八、Tracer 插件机制
8.1 已注册 Tracer
| Tracer | 源文件 | 功能 |
|---|---|---|
nop |
trace_nop.c |
空 tracer,仅 tracepoint |
function |
trace_functions.c |
记录函数调用 |
function_graph |
trace_functions_graph.c |
调用图 + 耗时 |
irqsoff / preemptoff / preemptirqsoff |
trace_irqsoff.c |
中断/抢占关闭延迟 |
wakeup / wakeup_rt / wakeup_dl |
trace_sched_wakeup.c |
唤醒延迟 |
hwlat |
trace_hwlat.c |
硬件延迟(SMI 等) |
osnoise / timerlat |
trace_osnoise.c |
OS 噪声 / 定时器延迟 |
branch |
trace_branch.c |
likely/unlikely 分支 |
blk |
blktrace.c |
块 I/O |
mmio |
trace_mmiotrace.c |
MMIO 访问 |
8.2 生命周期
1 | register_tracer() [模块 init] |
8.3 Max Trace / Snapshot
支持 CONFIG_TRACER_MAX_TRACE 的 tracer(irqsoff、wakeup 等):
- 延迟超过
tracing_max_latency时 swap 到max_buffer snapshot文件手动触发快照trace读 live 数据;max buffer 保留 worst-case 记录
九、Trace Event 事件系统
9.1 事件定义
静态 tracepoint(各子系统 include/trace/events/*.h):
1 | TRACE_EVENT(sched_switch, |
内置 ftrace entry(trace_entries.h):
1 | FTRACE_ENTRY_REG(function, ftrace_entry, TRACE_FN, ...); |
9.2 注册与管理(trace_events.c)
1 | trace_event_reg() |
9.3 Filter(trace_events_filter.c)
1 | echo 'pid == 1234 && comm == "myapp"' > events/.../filter |
表达式编译为 predicate 字节码,写入前求值。
9.4 Trigger(trace_events_trigger.c)
| Trigger | 动作 |
|---|---|
snapshot |
触发 buffer 快照 |
stacktrace |
记录栈 |
traceon / traceoff |
开关 tracing |
enable_event / disable_event |
控制其他 event |
hist |
直方图聚合 |
9.5 Histogram(trace_events_hist.c + tracing_map.c)
- 按字段 hash 聚合(pid、comm、latency 桶)
onmatch/onmax跨 event 延迟追踪trace_events_synth.c合成新 event 类型
9.6 常见 Event 子系统
| 子系统 | 典型事件 |
|---|---|
sched |
sched_switch, sched_wakeup, sched_waking |
irq |
irq_handler_entry/exit |
power |
cpu_idle, cpu_frequency |
block |
block_rq_issue, block_rq_complete |
kmem |
kmalloc, kfree |
syscalls |
sys_enter/exit_*(trace_syscalls.c) |
十、动态探针、fprobe 与 BPF
10.1 动态 Event 框架(trace_dynevent.c)
1 | /sys/kernel/debug/tracing/dynamic_events |
| 类型 | 文件 | 说明 |
|---|---|---|
| kprobe / kretprobe | trace_kprobe.c |
内核函数/指令探针 |
| uprobe / uretprobe | trace_uprobe.c |
用户态探针 |
| eprobe | trace_eprobe.c |
eBPF-based probe |
| synthetic | trace_events_synth.c |
运行时合成 event |
公共解析:trace_probe.c(参数 fetch、format 生成)。
kprobe 示例:
1 | echo 'p:myprobe do_sys_openat2 dfd=%di filename=%si flags=%dx' >> kprobe_events |
10.2 rethook + fprobe
rethook.c(CONFIG_RETHOOK):通用函数返回 hook 基础设施,维护 per-task 返回 hook 链表,供 kretprobe/fprobe 复用。
fprobe.c(CONFIG_FPROBE):基于 ftrace_ops + rethook 的轻量探针:
- 支持 entry/exit handler
- 可一次 probe 多个函数
- 比 kprobe 开销更低,但仅限函数 entry/exit
1 | /* fprobe 回调链 */ |
10.3 BPF 集成(bpf_trace.c)
BPF 程序可挂载:
| 类型 | BPF_PROG_TYPE |
|---|---|
| tracepoint | TRACING |
| kprobe/uprobe | KPROBE |
| fentry/fexit | 基于 ftrace |
| raw tracepoint | RAW_TRACEPOINT |
Helper:bpf_get_stackid、bpf_probe_read、bpf_printk 等。与 perf 事件桥接:trace_event_perf.c。
十一、Latency 延迟追踪器
11.1 irqsoff / preemptoff(trace_irqsoff.c)
1 | local_irq_disable() → trace_hardirqs_off() /* 记录起始 */ |
11.2 wakeup latency(trace_sched_wakeup.c)
1 | try_to_wake_up() → trace_sched_waking() |
模式:wakeup(CFS)、wakeup_rt、wakeup_dl。
11.3 hwlat(trace_hwlat.c)
内核线程关中断 spin,检测 SMI/NMI 等 硬件引入的延迟空隙。
11.4 osnoise / timerlat(trace_osnoise.c)
- osnoise:统计 NMI/IRQ/SoftIRQ/线程/hw 各来源噪声
- timerlat:测量 hrtimer 唤醒延迟,用于 PREEMPT_RT 调优
十二、追踪时钟(trace_clock.c)
| 时钟 | API | 特点 |
|---|---|---|
local |
trace_clock_local() |
仅本 CPU,sched_clock(),最快 |
medium |
trace_clock() |
local_clock(),跨 CPU 有小 jitter |
global |
trace_clock_global() |
全局单调,有序列化开销 |
mono |
trace_clock_mono() |
单调 boot time |
jiffies |
trace_clock_jiffies() |
以 jiffy 为单位 |
用户设置:echo global > trace_clock
RK3588 跨 CPU 分析建议用 global 或 mono,避免 big.LITTLE 间 local 时钟不一致。
十三、Runtime Verification(rv/)
rv/ 子目录(~1731 行)实现在线 形式化规范验证:
1 | Tracing 插桩 → Monitor 实例 ← Reference Model(规范) |
1 | struct rv_monitor { |
用户接口:/sys/kernel/debug/tracing/rv/available_monitors
内置 monitor:
| Monitor | 文件 | 说明 |
|---|---|---|
| wip | rv/monitors/wip/wip.c |
Work In Progress 状态 |
| wwnr | rv/monitors/wwnr/wwnr.c |
Wait/Wakeup Not Running |
Reaction:reactor_panic.c、reactor_printk.c(rv_reactors.c)。
十四、tracefs 用户接口
挂载点:/sys/kernel/debug/tracing/(需 debugfs 挂载)。
14.1 常用控制文件
| 文件 | 功能 |
|---|---|
current_tracer |
设置当前 tracer |
available_tracers |
列出可用 tracer |
tracing_on |
全局开关 0/1 |
trace |
读追踪数据(读后清空) |
trace_pipe |
阻塞持续读 |
buffer_size_kb |
ring buffer 大小 |
trace_clock |
时钟源 |
tracing_cpumask |
限定 CPU |
set_ftrace_filter / set_ftrace_notrace |
函数 filter |
snapshot |
手动快照 |
tracing_max_latency |
最大延迟阈值 |
events/ |
event 树 |
instances/ |
独立实例 |
14.2 快速示例
1 | # 函数图追踪(含耗时) |
14.3 启动时 tracing(trace_boot.c)
CONFIG_BOOTTIME_TRACING:通过内核命令行 ftrace= / trace_event= 在 boot 早期启用 tracing,便于启动路径分析。
十五、RK3588/ARM64 平台说明
15.1 架构支持总结
| 能力 | ARM64/RK3588 |
|---|---|
| FUNCTION_TRACER | ✓(-mrecord-mcount / patchable entries) |
| DYNAMIC_FTRACE | ✓ |
| DYNAMIC_FTRACE_WITH_REGS | ✓(回调默认可获 pt_regs) |
| FUNCTION_GRAPH_TRACER | ✓(default y) |
| KPROBE / UPROBE | ✓ |
| HAVE_GENERIC_VDSO | ✓(与 trace 独立,用户态 gettimeofday) |
15.2 defconfig 与开销
Rockchip defconfig 显式启用 CONFIG_FUNCTION_TRACER=y;DYNAMIC_FTRACE 默认 y,未启用 tracing 时接近零开销(NOP patch)。
15.3 常用调试场景
| 场景 | 推荐配置 |
|---|---|
| 驱动 probe/初始化 | function_graph + set_ftrace_filter 限定驱动符号 |
| 调度延迟 | wakeup tracer 或 events/sched/sched_wakeup/enable |
| CPU 频率/idle | events/power/cpu_frequency/enable |
| 中断延迟 | irqsoff tracer |
| I/O 性能 | events/block/enable 或 blk tracer |
| 多媒体 pipeline | function_graph + tracepoint dma_fence |
| 实时性评估 | osnoise / timerlat |
15.4 big.LITTLE 注意点
tracing_cpumask限定 A76 或 A55 簇,减少交叉 CPU 噪声trace_clock用global/mono保证跨核时间戳可比- 8 核建议
buffer_size_kb ≥ 4096,避免 function tracer 溢出 - deep idle 时部分 little 核 clockevent 停,tracing 本身不依赖 periodic tick,但 hwlat/osnoise 测试需考虑 CPU 隔离
15.5 与 perf 的关系
- perf 可复用 tracepoint(
trace_event_perf.c) perf record -e sched:*与 ftrace events 共享底层 tracepoint- BPF 程序可通过
bpf_trace.c同时服务 tracing 与 perf
十六、完整追踪时序
十七、总结
| 要点 | 说明 |
|---|---|
| Ring Buffer | per-CPU 无锁存储,tracing 数据中枢 |
| Dynamic ftrace | 关闭时 NOP,启用时 patch,ARM64 patchable entries |
| Tracer 插件 | struct tracer 扩展,覆盖函数/延迟/I/O |
| Trace Event | tracepoint/kprobe/synthetic 统一框架 + filter/trigger/hist |
| fprobe/rethook | 轻量 entry/exit 探针基础设施 |
| tracefs | 标准用户态控制面 |
| RK3588 | FUNCTION_TRACER + dynamic ftrace + graph;8 核 big.LITTLE 需注意 clock/buffer |
kernel/trace 是内核开发、驱动调试、调度分析与实时性评估的核心工具链;与 perf、BPF、debugfs 深度集成。
附录:源文件清单
| 文件 | 行数 | 分类 |
|---|---|---|
trace.c |
10493 | 核心框架 |
ftrace.c |
8479 | ftrace 引擎 |
trace_events_hist.c |
6757 | 直方图 trigger |
ring_buffer.c |
6234 | 环形缓冲区 |
trace_events.c |
4112 | 事件框架 |
bpf_trace.c |
2838 | BPF 集成 |
trace_events_filter.c |
2475 | Event 过滤 |
trace_osnoise.c |
2444 | OS 噪声 / timerlat |
trace_events_synth.c |
2351 | 合成事件 |
trace_kprobe.c |
2133 | kprobe event |
trace_events_trigger.c |
1984 | Event trigger |
trace_events_user.c |
1922 | 用户 event |
blktrace.c |
1922 | 块 I/O tracer |
trace_uprobe.c |
1675 | uprobe event |
trace_output.c |
1583 | 输出格式化 |
trace_functions_graph.c |
1367 | 函数图 tracer |
trace_selftest.c |
1287 | 自测 |
trace_probe.c |
1234 | 探针公共代码 |
tracing_map.c |
1139 | 无锁 hash map |
trace_eprobe.c |
1095 | eprobe |
trace_functions.c |
974 | function tracer |
trace_hwlat.c |
893 | hwlat tracer |
trace_sched_wakeup.c |
820 | wakeup tracer |
trace_syscalls.c |
808 | syscall 事件 |
rv/rv.c |
801 | RV 框架 |
trace_irqsoff.c |
752 | irqsoff tracer |
trace_boot.c |
671 | 启动 tracing |
fgraph.c |
664 | function graph 辅助 |
trace_stack.c |
582 | 栈深度 tracer |
trace_event_perf.c |
529 | perf 桥接 |
trace_dynevent.c |
483 | 动态 event 控制 |
trace_branch.c |
455 | branch tracer |
trace_seq.c |
405 | 序列化输出 |
trace_printk.c |
400 | trace_printk |
trace_stat.c |
364 | 统计输出 |
trace_mmiotrace.c |
362 | MMIO tracer |
rethook.c |
346 | 返回 hook |
fprobe.c |
334 | fprobe 探针 |
trace_events_inject.c |
335 | event 注入 |
pid_list.c |
495 | PID 过滤 |
trace_clock.c |
158 | 追踪时钟 |
trace_nop.c |
100 | nop tracer |
rv/rv_reactors.c |
510 | RV reaction |
| 其他测试/辅助 | ~3000 | selftest、benchmark 等 |
| 合计(含 rv/) | 83027 | 81 个 .c/.h 文件 |
行数统计:Linux 6.1,find kernel/trace -name '*.c' -o -name '*.h' | xargs wc -l。
正在加载留言…