2、环境准备:内核配置要求、编译内核、挂载tracefs文件系统

好,咱们正式开始动手之前,得先把“战场”打扫干净。说白了,ftrace 虽然强大,但它不是个开箱即用的玩具。你得让内核认识它、支持它,然后才能指挥它。

我记得刚入行那会儿,有次在客户现场排查一个调度延迟问题,兴致勃勃地敲了 echo function > current_tracer,结果系统冷冷地回了一句 bash: echo: write error: Function not available。当时那个尴尬啊……后来才发现,内核压根没编译 ftrace 进去。所以,这一节咱们就把这些坑提前填上。

2.1 内核配置要求

ftrace 的核心功能,依赖于内核的几个关键配置项。你想想看,内核编译时如果没打开这些开关,那 ftrace 就是“巧妇难为无米之炊”。

我个人习惯,在配置内核时,直接用 make menuconfig 或者 make nconfig,然后搜索这几个关键符号:

配置项 说明 我的建议
CONFIG_FTRACE ftrace 的总开关,必须打开 设为 y
CONFIG_DYNAMIC_FTRACE 动态插桩,允许运行时选择跟踪哪些函数 设为 y,这是核心中的核心
CONFIG_FUNCTION_TRACER 函数跟踪器,支持 functionfunction_graph 跟踪器 设为 y
CONFIG_STACK_TRACER 内核栈回溯跟踪,排查栈溢出时很有用 建议设为 y
CONFIG_FTRACE_SYSCALLS 跟踪系统调用入口和退出 设为 y,调试用户态程序时很香
CONFIG_FUNCTION_GRAPH_TRACER 函数调用图跟踪器,能看到谁调了谁 设为 y

重点提醒: CONFIG_DYNAMIC_FTRACE 一定要打开。没有它,ftrace 就只能跟踪所有函数,性能开销巨大,而且你没法精确控制跟踪范围。我曾经在一个嵌入式项目里忘了开这个,结果系统跑起来直接卡死……嗯,教训深刻。

除了上面这些,还有一些辅助配置也值得关注:

  • CONFIG_TRACING:跟踪框架的基础,一般会被自动选中。
  • CONFIG_EVENT_TRACING:事件跟踪,比如跟踪 sched_switchirq_handler_entry 等内核事件。
  • CONFIG_KPROBESCONFIG_UPROBES:动态探针,可以和 ftrace 配合使用,后面章节会讲到。

怎么确认当前内核有没有打开这些配置?很简单:

# 查看当前内核的配置
zcat /proc/config.gz | grep CONFIG_FTRACE
# 或者
cat /boot/config-$(uname -r) | grep CONFIG_FTRACE

如果输出是 y 或者 m,那就没问题。如果是 is not set,那你就得重新编译内核了。

2.2 编译内核

好,假设你发现内核没开这些选项,那就得自己动手编译了。别怕,这事儿我干过上百次,其实没那么玄乎。

我建议你准备一台虚拟机或者单独的测试机器,别在生产环境上搞。万一编译出问题,系统起不来,那就麻烦了。

步骤大致如下:

  1. 下载内核源码:去 kernel.org 下载你想要的版本。我个人习惯用长期支持版(LTS),比如 5.10.x 或 6.1.x,稳定且文档齐全。
  2. 解压并配置
    tar xf linux-6.1.xx.tar.xz
    cd linux-6.1.xx
    make menuconfig
    在菜单里找到 Kernel hacking -> Tracers,把上面表格里的选项都勾上。
  3. 编译
    make -j$(nproc)   # 用所有CPU核心并行编译,快很多
    第一次编译大概要十几分钟到半小时,取决于你的机器性能。
  4. 安装模块和内核
    sudo make modules_install
    sudo make install
  5. 更新引导配置并重启
    sudo update-grub   # 对于 Ubuntu/Debian
    sudo reboot

小技巧: 如果你不想编译整个内核,也可以只编译内核模块。但 ftrace 是内核核心功能,必须编译进内核(y),不能作为模块(m)。这一点要注意。

重启后,用 uname -r 确认新内核已经启动。然后再次检查配置:

cat /proc/config.gz | grep CONFIG_DYNAMIC_FTRACE
# 应该输出:CONFIG_DYNAMIC_FTRACE=y

看到 y 了?好,那咱们就成功了一半。

2.3 挂载 tracefs 文件系统

ftrace 的用户接口,是通过一个叫 tracefs 的虚拟文件系统暴露出来的。说白了,你往 /sys/kernel/tracing/ 目录下的文件里写东西,就能控制 ftrace 的行为。

但有个前提——你得先把这个文件系统挂载上。

大多数现代 Linux 发行版(比如 Ubuntu 20.04+、CentOS 8+)在启动时已经自动挂载了。你可以检查一下:

mount | grep tracefs
# 或者
ls /sys/kernel/tracing/

如果能看到一堆文件(比如 available_tracerscurrent_tracer 等),那就说明已经挂载好了。

如果没有,那就手动挂载:

sudo mount -t tracefs tracefs /sys/kernel/tracing/

为了永久生效,可以把它加到 /etc/fstab 里:

echo "tracefs /sys/kernel/tracing tracefs defaults 0 0" | sudo tee -a /etc/fstab

注意: 有些老系统用的是 debugfs,挂载点在 /sys/kernel/debug/tracing/。虽然也能用,但 tracefs 是更现代、更推荐的方式。我建议你优先用 tracefs

挂载成功后,咱们来看看核心目录里都有些什么:

ls /sys/kernel/tracing/
# 你会看到类似这样的输出:
# available_tracers  current_tracer  trace  trace_pipe  ...
# set_ftrace_filter  set_ftrace_pid  ...

这些文件就是 ftrace 的控制面板。比如 available_tracers 列出了当前内核支持的所有跟踪器,current_tracer 用来设置当前使用的跟踪器。

咱们验证一下:

cat /sys/kernel/tracing/available_tracers
# 输出类似:function function_graph nop

看到 functionfunction_graph 了?这说明 ftrace 已经就绪,可以开始干活了。

2.4 环境验证小脚本

为了确保万无一失,我写了个小脚本,你可以跑一下,快速验证环境是否准备到位:

#!/bin/bash
# 快速验证 ftrace 环境

echo "=== 1. 检查内核配置 ==="
zgrep -E "CONFIG_(FTRACE|DYNAMIC_FTRACE|FUNCTION_TRACER)" /proc/config.gz 2>/dev/null || echo "未找到 /proc/config.gz,请确认内核配置"

echo ""
echo "=== 2. 检查 tracefs 挂载 ==="
mount | grep tracefs && echo "tracefs 已挂载" || echo "tracefs 未挂载,请执行: sudo mount -t tracefs tracefs /sys/kernel/tracing/"

echo ""
echo "=== 3. 检查可用跟踪器 ==="
cat /sys/kernel/tracing/available_tracers 2>/dev/null || echo "无法访问 /sys/kernel/tracing/,请检查权限或挂载"

echo ""
echo "=== 4. 测试设置跟踪器 ==="
echo nop > /sys/kernel/tracing/current_tracer 2>/dev/null && echo "设置 nop 跟踪器成功" || echo "设置失败,请以 root 身份运行"

把这个脚本保存为 check_ftrace_env.sh,然后 sudo bash check_ftrace_env.sh。如果所有检查都通过,那恭喜你,环境准备完毕,可以进入下一章了。

嗯,我记得有一次帮一个团队排查问题,他们折腾了半天 ftrace 没反应,结果就是 tracefs 没挂载。所以这一步虽然简单,但千万别跳过。

好,环境准备好了,下一章咱们就开始真正使用 ftrace 了。到时候我会带你从最简单的 function 跟踪器开始,一步步深入。