文章目录
一、简介
Ftrace 是 Linux 官方提供的跟踪工具,在 Linux 2.6.27 版本中引入。Ftrace 可在不引入任何前端工具的情况下使用,让其可以适合在任何系统环境中使用。
Ftrace 可用来快速排查以下相关问题:
- 特定内核函数调用的频次 (function)
- 内核函数在被调用的过程中流程(调用栈) (function + stack)
- 内核函数调用的子函数流程(子调用栈)(function graph)
- 由于抢占导致的高延时路径等
Ftrace 跟踪工具由性能分析器(profiler)和跟踪器(tracer)两部分组成:
- 性能分析器 ,用来提供统计和直方图数据(需要 CONFIG_ FUNCTION_PROFILER=y)
- 函数性能分析
- 直方图
- 跟踪器 ,提供跟踪事件的详情:
- 函数跟踪(function)
- 跟踪点(tracepoint)
- kprobe
- uprobe
- 函数调用关系(function_graph)
- hwlat 等
除了操作原始的文件接口外,也有一些基于 Ftrace 的前端工具,比如 perf-tools 和 trace-cmd (界面 KernelShark)等。整体跟踪及前端工具架构图如下:
Ftrace 的使用的接口为 tracefs 文件系统,需要保证该文件系统进行加载:
$ sysctl -q kernel.ftrace_enabled=1
$ mount -t tracefs tracefs /sys/kernel/tracing
$ mount -t debugfs,tracefs
tracefs on /sys/kernel/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)
tracefs on /sys/kernel/debug/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
$ ls -F /sys/kernel/debug/tracing # 完整目录如下图
tracing 目录下核心文件介绍如下表格,当前可仅关注黑体加粗的项,其他项可在需要的时候再进行回顾:
文件 | 描述 |
---|---|
available_tracers | 可用跟踪器,hwlat blk function_graph wakeup_dl wakeup_rt wakeup function nop,nop 表示不使用跟踪器 |
current_tracer | 当前使用的跟踪器 |
function_profile_enabled | 启用函数性能分析器 |
available_filter_functions | 可跟踪的完整函数列表 |
set_ftrace_filter | 选择跟踪函数的列表,支持批量设置,例如 tcp、tcp 和 tcp 等 |
set_ftrace_notrace | 设置不跟踪的函数列表 |
set_event_pid | 设置跟踪的 PID,表示仅跟踪 PID 程序的函数或者其他跟踪 |
tracing_on | 是否启用跟踪,1 启用跟踪 0 关闭跟踪 |
trace_options | 设置跟踪的选项 |
trace_stat(目录) | 函数性能分析的输出目录 |
kprobe_events | 启用 kprobe 的配置 |
uprobe_events | 启用 uprobe 的配置 |
events ( 目录 ) | 事件(Event)跟踪器的控制文件: tracepoint、kprobe、uprobe |
trace | 跟踪的输出 (Ring Buffer) |
trace_pipe | 跟踪的输出;提供持续不断的数据流,适用于程序进行读取 |
perf_tools 包含了一个复位所有 ftrace 选型的工具脚本,在跟踪不符合预期的情况下,建议先使用 reset-ftrace 进行复位,然后再进行测试。
二、内核函数调用跟踪
基于 Ftrace 的内核函数调用跟踪整体架构如下所示:
这里我们尝试对于内核中的系统调用函数 __arm64_sys_openat
进行跟踪(前面两个下划线),需要注意的是 __arm64_sys_openat
是在 arm64 结构体系下 sys_openat
系统调用的包装,如果在 x86_64 架构下则为 __x64_sys_openat()
,由于我们本地的电脑是 M1 芯片,所以演示的样例以 arm64 为主。
在不同的体系结构下,可以在 /proc/kallsym 文件中搜索确认。
后续的目录,如无特殊说明,都默认位于 /sys/kernel/debug/tracing/ 根目录。
# 使用 function 跟踪器,并将其设置到 current_tracer
$ sudo echo function > current_tracer
# 将跟踪函数 __arm64_sys_openat 设置到 set_ftrace_filter 文件中
$ sudo echo __arm64_sys_openat > set_ftrace_filter
# 开启全局的跟踪使能
$ sudo echo 1 > tracing_on
# 运行 ls 命令触发 sys_openat 系统调用,新的内核版本中直接调用 sys_openat
$ ls -hl
# 关闭
$ sudo echo 0 > tracing_on
$ sudo echo nop > current_tracer
# 需要主要这里的 echo 后面有一个空格,即 "echo+ 空格>"
$ sudo echo > set_ftrace_filter
# 通过 cat trace 文件进行查看
$ sudo cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 224/224 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
sudo-15099 [002] .... 29469.444400: __arm64_sys_openat <-invoke_syscall
sudo-15099 [002] .... 29469.444594: __arm64_sys_openat <-invoke_syscall
我们可以看到上述的结果表明了函数调用的任务名称、PID、CPU、标记位、时间戳及函数名字。
在 perf_tools 工具集中的前端封装工具为 functrace ,需要注意的是该工具默认不会设置 tracing_on 为 1, 需要在启动前进行设置,即 "echo 1 > tracing_on"。
perf_tools 工具集中 kprobe 也可以实现类似的效果,底层基于 kprobe 机制实现,ftrace 机制中的 kprobe 在后续章节会详细介绍。