2. ftrace简介:ftrace的架构、tracefs文件系统、主要跟踪器概览
ftrace(Function Tracer)是Linux内核内置的跟踪框架,用于帮助开发者和调试人员分析内核内部的行为。它能够记录函数调用、事件发生以及系统状态变化,且开销极低,非常适合在生产环境中进行性能分析和问题定位。本章将介绍ftrace的核心架构、用户接口以及三种最常用的跟踪器。
2.1 ftrace架构概览
ftrace的架构采用分层设计,从上到下依次为:用户空间接口层、核心框架层、跟踪器层以及数据采集层。这种分层结构使得ftrace既灵活又易于扩展。
tracefs文件系统向用户空间暴露控制接口,用户通过读写这些文件来启用/禁用跟踪器、设置过滤条件以及读取跟踪结果。
2.2 tracefs文件系统
ftrace通过tracefs文件系统与用户空间交互。在大多数现代Linux发行版中,tracefs被挂载在/sys/kernel/tracing/目录下。如果该目录不存在,可以手动挂载:
# 挂载 tracefs
mount -t tracefs tracefs /sys/kernel/tracing/
# 或者挂载 debugfs(旧接口,仍兼容)
mount -t debugfs debugfs /sys/kernel/debug/
# 此时 tracefs 位于 /sys/kernel/debug/tracing/
下表列出了/sys/kernel/tracing/目录下最常用的控制文件及其作用:
| 文件名称 | 作用描述 | 读写类型 |
|---|---|---|
available_tracers |
列出当前内核支持的所有跟踪器 | 只读 |
current_tracer |
设置或查看当前激活的跟踪器 | 读写 |
trace |
读取跟踪结果(人类可读格式) | 只读 |
trace_pipe |
以流式方式读取跟踪结果(阻塞读) | 只读 |
tracing_on |
全局跟踪开关(1=开启,0=关闭) | 读写 |
set_ftrace_filter |
设置函数过滤白名单(仅跟踪指定函数) | 读写 |
set_ftrace_notrace |
设置函数过滤黑名单(排除指定函数) | 读写 |
available_events |
列出所有可用的 tracepoint 事件 | 只读 |
events/ |
事件控制目录,可单独启用/禁用每个事件 | 目录 |
buffer_size_kb |
设置每个 CPU 的 ring buffer 大小(KB) | 读写 |
available_tracers 确认跟踪器支持情况,然后设置 current_tracer 为 function_graph,再通过 set_ftrace_filter 只过滤 V4L2 相关的函数,最后读取 trace 文件获取调用路径。
2.3 主要跟踪器概览
ftrace 提供了多种跟踪器,每种跟踪器适用于不同的调试场景。对于 V4L2 驱动调试,最常用的是 function、function_graph 和 events 三种。
2.3.1 function 跟踪器
function 跟踪器是最基础的跟踪器,它记录每个被调用内核函数的名称和调用顺序。当启用后,每个函数入口都会向 ring buffer 写入一条记录。
# 启用 function 跟踪器
echo function > /sys/kernel/tracing/current_tracer
echo 1 > /sys/kernel/tracing/tracing_on
# 执行需要跟踪的操作(如打开 V4L2 设备)
# ...
# 读取跟踪结果
cat /sys/kernel/tracing/trace | head -20
输出示例:
# 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
# | | | |||| | |
v4l2-test-1234 [000] .... 12345.678901: v4l2_open: v4l2_open+0x0/0x100
v4l2-test-1234 [000] .... 12345.678902: mutex_lock: mutex_lock+0x0/0x30
v4l2-test-1234 [000] .... 12345.678903: _raw_spin_lock: _raw_spin_lock+0x0/0x20
v4l2-test-1234 [000] .... 12345.678904: __mutex_lock_slowpath: __mutex_lock_slowpath+0x0/0x200
2.3.2 function_graph 跟踪器
function_graph 跟踪器在 function 的基础上增加了函数调用关系的层级缩进和函数执行耗时。它以图形化的方式展示函数的嵌套调用关系,非常适合分析 V4L2 ioctl 的完整调用路径。
# 启用 function_graph 跟踪器
echo function_graph > /sys/kernel/tracing/current_tracer
echo 1 > /sys/kernel/tracing/tracing_on
# 只跟踪 V4L2 相关函数(过滤)
echo 'v4l2_*' > /sys/kernel/tracing/set_ftrace_filter
# 执行 ioctl 操作
# ...
# 读取跟踪结果
cat /sys/kernel/tracing/trace
输出示例(展示层级关系):
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
0) | v4l2_ioctl() {
0) | mutex_lock() {
0) 0.500 us | _raw_spin_lock();
0) 1.200 us | }
0) | video_usercopy() {
0) | v4l2_querycap() {
0) 0.800 us | __check_object_size();
0) 2.100 us | }
0) | v4l2_s_fmt() {
0) | uvc_v4l2_set_format() {
0) 1.300 us | uvc_acquire_privileges();
0) 0.600 us | uvc_video_alloc_buffers();
0) 4.500 us | }
0) 5.200 us | }
0) 8.000 us | }
0) 10.500 us | }
2.3.3 events 跟踪器
events 跟踪器基于内核预定义的 tracepoint(跟踪点)工作。与 function 系列跟踪器不同,events 不跟踪所有函数,而是只记录开发者预先埋设的特定事件点。每个事件可以携带丰富的上下文数据(如参数值、返回值、设备状态等)。
对于 V4L2 驱动调试,events 跟踪器可以捕获 V4L2 核心层预埋的 tracepoint 事件:
# 列出所有可用的 V4L2 相关事件
ls /sys/kernel/tracing/events/v4l2/
# 启用所有 V4L2 事件
echo 1 > /sys/kernel/tracing/events/v4l2/enable
# 或者只启用特定事件(如 v4l2_ioctl)
echo 1 > /sys/kernel/tracing/events/v4l2/v4l2_ioctl/enable
# 开始跟踪
echo 1 > /sys/kernel/tracing/tracing_on
# 执行 ioctl 操作
# ...
# 读取结果
cat /sys/kernel/tracing/trace
events 输出示例:
# tracer: nop
#
# entries-in-buffer/entries-written: 45/45 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
v4l2-test-1234 [000] .... 12345.678901: v4l2_ioctl: dev=1, cmd=VIDIOC_QUERYCAP, ret=0
v4l2-test-1234 [000] .... 12345.678905: v4l2_ioctl: dev=1, cmd=VIDIOC_S_FMT, ret=0
v4l2-test-1234 [000] .... 12345.678910: v4l2_ioctl: dev=1, cmd=VIDIOC_REQBUFS, ret=0
2.4 三种跟踪器对比
下表总结了三种主要跟踪器的特点,帮助你在不同调试场景下做出选择:
| 跟踪器 | 跟踪粒度 | 数据量 | 性能开销 | 适用场景 |
|---|---|---|---|---|
| function | 函数级(所有函数) | 极大 | 中 | 快速定位函数调用序列,确认某个函数是否被调用 |
| function_graph | 函数级 + 调用层级 + 耗时 | 极大 | 中高 | 分析 ioctl 完整调用路径、定位耗时瓶颈、检查异常分支 |
| events | 预定义 tracepoint | 小 | 低 | 捕获特定事件(如 ioctl 命令码、错误码),适合长期监控 |
set_ftrace_filter 使用,只跟踪与 V4L2 相关的函数(如 v4l2_*、uvc_*、videobuf2_* 等)。