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 做细粒度分析。
function_graph 跟踪器输出示例(TCP 接收路径) 0) tcp_v4_rcv() /* 入口 */ 0.123 us 1) tcp_v4_do_rcv() 0.045 us 2) tcp_rcv_established() 0.032 us 3) tcp_data_queue() 0.018 us 3) tcp_data_queue() /* 返回 */ 0.018 us 缩进深度表示调用层级,右侧数值为子函数耗时(微秒),便于快速定位耗时热点。

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 层函数
ftrace 函数过滤流程 内核函数调用 在白名单? 在黑名单? 记录跟踪 跳过(不记录)

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 风格表达式,支持 ==、!=、>、<、&&、||。字符串字段需用双引号,数值字段直接写。不支持函数调用。
跟踪事件过滤架构 内核事件产生点 events/ 目录树 filter 文件 per-CPU 缓冲区 trace 文件 事件经过 filter 条件判断后,符合条件的记录写入 per-CPU 环形缓冲区,用户通过 trace 文件读取。 每个 CPU 独立缓冲区避免锁竞争,保证跟踪性能。

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 停止数据采集