
更多内容可以加入Linux系统知识库套餐(教程+视频+答疑)

沉淀、分享、成长,让自己和他人都能有所收获!😄
Ftrace 是一个自 Linux 内核 2.6 版本起就支持的内核调试工具。最初,Ftrace 主要用于函数级别的跟踪(function trace),但经过不断发展,Ftrace 现已成为一个通用的调试框架,能够实现多种跟踪目的。
Ftrace 通过 debugfs 虚拟文件系统向用户空间提供访问接口。通常,debugfs 会挂载在 /sys/kernel/debug 目录下,而 Ftrace 的控制和输出文件位于该目录下的 tracing 子目录中,完整路径为 /sys/kernel/debug/tracing。
以观测 do_sys_open 调用栈为例,ftrace 的使用如下:
# 设置跟踪器类型为 function_graph
sudo sh -c "echo function_graph > /sys/kernel/debug/tracing/current_tracer"
# 设置要观测调用栈的函数
sudo sh -c "echo do_sys_open > /sys/kernel/debug/tracing/set_graph_function"
# 设置观测选项:启用进程TASK/PID打印
sudo sh -c "echo funcgraph-proc > /sys/kernel/debug/tracing/trace_options"
# 开启跟踪
sudo sh -c "echo 1 > /sys/kernel/debug/tracing/tracing_on"
# 等待一段时间
# 关闭跟踪
sudo sh -c "echo 1 > /sys/kernel/debug/tracing/tracing_on"
# 查看 trace
sudo cat /sys/kernel/debug/tracing/trace
trace 的内容如下:
Ftrace支持多种追踪类型,包括函数调用、函数图、硬件延迟、中断关闭、抢占关闭等,我们可以通过 /sys/kernel/debug/ 相关的文件来查看 ftrace 支持的跟踪类型。
sudo cat /sys/kernel/debug/tracing/available_tracers
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
其中比较常用的是 function 和 function_graph。如要要设置跟踪器类型,需要把类型写入到 current_tracer 文件。比如设置类型为 function_graph 可以这样操作:
sudo sh -c "echo function_graph > /sys/kernel/debug/tracing/current_tracer"
set_ftrace_filter 表示要跟踪的函数,比如追踪 epoll_wait 可以这样操作:
sudo sh -c "echo SyS_epoll_wait > /sys/kernel/debug/tracing/set_ftrace_filter"
set_graph_function 用于设置 function_graph 跟踪器的触发函数。它不仅跟踪指定的函数,还跟踪该函数调用的所有子函数。
ftrace 的开关是通过 tracing_on 文件来控制的。
# 关闭 trace
sudo sh -c "echo 0 > /sys/kernel/debug/tracing/tracing_on"
# 开启 trace
sudo sh -c "echo 1>/sys/kernel/debug/tracing/tracing_on
sudo cat /sys/kernel/debug/tracing/trace
#tracer: function
#
#entries-in-buffer/entries-written:2972/2972 #P:12
#
# _-----=> irqs-off
# / _----=> need-resched
# |/ _---=> hardirq/softirq
# ||/ _--=> preempt-depth
# |||/ delay
#TASK-PID CPU# |||| TIMESTAMP FUNCTION
# |||||||||
redis-server-2831[007]....8269637.719334: SyS_epoll_wait <-do_syscall_64
redis-server-2830[010]....8269637.720688: SyS_epoll_wait <-do_syscall_64
通过这个 trace 我可以看到进程名、进程号、进程运行的 CPU、执行函数的时间戳等信息。
从上面的例子看出使用 ftrace 还是挺麻烦的,真正使用时实际上使用 trace-cmd 更多一点。trace-cmd 是一个用户空间的命令行工具,用于与 ftrace 进行交互。它提供了一个更方便的接口来配置和使用 ftrace,避免了直接操作 debugfs 文件系统的麻烦。
trace-cmd 的常见命令如下:
首先使用 record 记录 trace 数据:
trace-cmd record -p function_graph -g do_sys_open
注意 trace-cmd 默认开启了 funcgraph-proc 这个 trace-option,不需要手动指定。
使用 ctrl-c 退出这个 trace-cmd 时,会在当前目录生成 trace.dat 文件。接下来使用 report 读取 trace.dat 生成可读的文本:
当我们不知道可以跟踪哪些事件时,我们可以使用 trace-cmd list 列举当前系统上所有可用的事件:
trace-cmd list -e
它还可以带一个可选的参数,使用正则表达式进行过滤:
trace-cmd list -e '^sched.*' # 列出所有以 sched 开头的事件
如果只想跟踪特定进程的函数调用,可以使用 -P 选项指定进程的 PID。例如,要跟踪 PID 为 10885 的进程,可以使用以下命令:
trace-cmd record -p function_graph -P 2830

-g 选项用于 function_graph 插件,-g do_sys_open 表示只跟踪 do_sys_open 函数及其调用的所有子函数。
-l 选项指定要跟踪的函数。例如,要跟踪所有以 ext4_ 开头的函数,可以使用以下命令:
trace-cmd record -p function_graph -l "ext4_*"

-l 和 -g 的区别也比较显而易见:
默认情况下,trace-cmd 的 function_graph 会记录所有嵌套的函数调用。可以通过设置 --max-graph-depth 来限制跟踪深度。例如要将深度设置为 2,可以使用以下命令:
trace-cmd record -p function_graph --max-graph-depth 2-P 2830

可以结合事件追踪 -e 来获取更详细的信息,比如 -e sched:sched_switch 将指定追踪调度切换事件。还可以使用正则表达式过滤,比如追踪 nfs 相关的事件:
trace-cmd record -e "nfs:*"
