4. ftrace核心操作:设置跟踪器、过滤函数与跟踪事件
ftrace 是 Linux 内核内置的跟踪框架,能够以极低开销捕获内核函数调用、事件触发和性能计数器。本章聚焦 ftrace 的三大核心操作:选择跟踪器、过滤目标函数、启用跟踪事件。掌握这些操作是使用 ftrace 定位网络协议栈瓶颈的基础。
4.1 ftrace 文件系统接口
ftrace 通过 tracefs 伪文件系统暴露控制接口,默认挂载在 /sys/kernel/tracing(旧内核为 /sys/kernel/debug/tracing)。所有操作均通过读写该目录下的文件完成。
关键文件速查表
| 文件 | 用途 | 典型值 |
|---|---|---|
current_tracer |
设置/查看当前跟踪器 | function, function_graph, nop |
available_tracers |
列出内核支持的跟踪器 | 按编译配置动态生成 |
set_ftrace_filter |
白名单:只跟踪匹配的函数 | tcp_v4_do_rcv |
set_ftrace_notrace |
黑名单:排除匹配的函数 | schedule |
available_events |
列出所有可跟踪事件 | 数千个事件 |
events/ |
事件控制目录树 | events/net/ |
trace |
读取跟踪输出 | 文本格式 |
tracing_on |
全局开关(1=开,0=关) | 1 |
操作顺序: 设置跟踪器 → 配置过滤 → 开启跟踪 → 复现问题 → 关闭跟踪 → 读取
trace 文件。
4.2 设置跟踪器:function 与 function_graph
ftrace 提供多种跟踪器,网络性能分析最常用的是 function 和 function_graph。
- function 跟踪器:记录每个被调用函数的入口和退出时间戳,适合统计函数调用频次和延迟分布。
- function_graph 跟踪器:以缩进树形式展示函数调用链,清晰显示嵌套关系和子函数耗时,适合分析协议栈内部执行路径。
# 切换到 function_graph 跟踪器
echo function_graph > /sys/kernel/tracing/current_tracer
# 验证当前跟踪器
cat /sys/kernel/tracing/current_tracer
# 输出: function_graph
性能注意: function_graph 跟踪器开销高于 function 跟踪器,生产环境建议先使用 function 跟踪器做粗粒度定位,再在测试环境用 function_graph 做细粒度分析。
4.3 过滤函数:set_ftrace_filter 与 set_ftrace_notrace
默认情况下,function 跟踪器会跟踪所有内核函数,产生海量数据。通过过滤机制可以精确限定跟踪范围,降低噪声和开销。
4.3.1 白名单过滤
向 set_ftrace_filter 写入函数名或通配符,ftrace 只跟踪匹配的函数。
# 只跟踪 TCP 协议栈相关函数
echo 'tcp_*' > /sys/kernel/tracing/set_ftrace_filter
# 追加单个函数
echo 'ip_local_deliver' >> /sys/kernel/tracing/set_ftrace_filter
# 查看当前过滤列表
cat /sys/kernel/tracing/set_ftrace_filter | head -20
4.3.2 黑名单过滤
向 set_ftrace_notrace 写入函数名,排除高频干扰函数。
# 排除调度器和时钟中断函数
echo 'schedule' > /sys/kernel/tracing/set_ftrace_notrace
echo 'clock_*' >> /sys/kernel/tracing/set_ftrace_notrace
网络调试常用过滤模式:
tcp_* — 跟踪所有 TCP 函数ip_* — 跟踪 IP 层函数dev_* — 跟踪网络设备层函数sk_* — 跟踪 socket 层函数
4.4 跟踪事件:events 子系统
除了函数跟踪,ftrace 还支持预定义的跟踪事件(trace events)。事件由内核开发者静态插入,包含结构化字段(如 IP 地址、端口号、数据包长度),比函数跟踪更易解析。
4.4.1 启用事件
事件控制目录位于 /sys/kernel/tracing/events/,按子系统组织。
# 启用所有网络事件(谨慎,数据量极大)
echo 1 > /sys/kernel/tracing/events/net/enable
# 启用特定事件:TCP 接收事件
echo 1 > /sys/kernel/tracing/events/tcp/tcp_rcv_established/enable
# 启用多个事件(逐个写入)
echo 1 > /sys/kernel/tracing/events/tcp/tcp_v4_connect/enable
echo 1 > /sys/kernel/tracing/events/tcp/tcp_retransmit_skb/enable
4.4.2 事件格式与字段
每个事件都有预定义的格式,可通过 format 文件查看。
# 查看 tcp_rcv_established 事件的字段
cat /sys/kernel/tracing/events/tcp/tcp_rcv_established/format
# 输出示例(部分字段):
# name: tcp_rcv_established
# ID: 1234
# format:
# field:unsigned short common_type; offset:0; size:2;
# field:unsigned char common_flags; offset:2; size:1;
# field:__u32 saddr; offset:8; size:4; /* 源IP */
# field:__u32 daddr; offset:12; size:4; /* 目的IP */
# field:__u16 sport; offset:16; size:2; /* 源端口 */
# field:__u16 dport; offset:18; size:2; /* 目的端口 */
# field:__u32 length; offset:20; size:4; /* 数据长度 */
4.4.3 事件过滤
ftrace 支持对事件字段进行条件过滤,只记录满足条件的事件。
# 只记录目的端口为 80 的 TCP 接收事件
echo 'dport == 80' > /sys/kernel/tracing/events/tcp/tcp_rcv_established/filter
# 只记录长度大于 1000 字节的事件
echo 'length > 1000' > /sys/kernel/tracing/events/tcp/tcp_rcv_established/filter
# 组合条件(与逻辑)
echo 'dport == 80 && length > 500' > /sys/kernel/tracing/events/tcp/tcp_rcv_established/filter
过滤语法注意: 事件过滤使用 C 风格表达式,支持
==、!=、>、<、&&、||。字符串字段需用双引号,数值字段直接写。不支持函数调用。
4.5 实战案例:定位 TCP 重传原因
结合函数跟踪与事件跟踪,快速定位 TCP 重传是发生在发送端还是接收端。
# 步骤1:设置 function_graph 跟踪器,过滤 TCP 函数
echo function_graph > /sys/kernel/tracing/current_tracer
echo 'tcp_*' > /sys/kernel/tracing/set_ftrace_filter
# 步骤2:启用 TCP 重传事件
echo 1 > /sys/kernel/tracing/events/tcp/tcp_retransmit_skb/enable
# 步骤3:开启跟踪
echo 1 > /sys/kernel/tracing/tracing_on
# 步骤4:复现网络问题(如 curl 请求)
curl -o /dev/null http://10.0.0.1:8080/test
# 步骤5:关闭跟踪
echo 0 > /sys/kernel/tracing/tracing_on
# 步骤6:读取结果
cat /sys/kernel/tracing/trace | head -100
分析要点:
- 如果
- 结合
- 使用
- 如果
tcp_retransmit_skb 事件频繁出现,说明发送端触发重传。- 结合
tcp_rcv_established 事件查看接收端是否正常 ACK。- 使用
function_graph 跟踪 tcp_write_xmit 函数,观察发送队列状态。
4.6 常用操作速查表
| 操作 | 命令 | 说明 |
|---|---|---|
| 查看可用跟踪器 | cat available_tracers |
确认内核编译选项 |
| 设置跟踪器 | echo function > current_tracer |
切换跟踪器 |
| 添加函数过滤 | echo 'tcp_*' > set_ftrace_filter |
支持通配符 |
| 启用事件 | echo 1 > events/tcp/tcp_retransmit_skb/enable |
按需启用 |
| 设置事件过滤 | echo 'dport == 80' > events/tcp/tcp_rcv_established/filter |
减少数据量 |
| 清空缓冲区 | echo > trace |
重置跟踪输出 |
| 关闭跟踪 | echo 0 > tracing_on |
停止数据采集 |