1      ftrace 简介

ftrace 是 Linux 内核中提供的一种调试工具。使用 ftrace 可以对内核中发生的事情进行跟踪,可以调试 bug 或者分析内核,也可以帮助开发人员了解 Linux 内核的运行时行为,以便进行故障调试或性能分析。

最早 ftrace 是一个 function tracer,仅能够记录内核的函数调用流程。如今 ftrace 已经成为一个 framework,采用 plugin 的方式支持开发人员添加更多种类的 trace 功能。

Ftrace 由 RedHat 的 Steve Rostedt 负责维护。到 2.6.30 为止,已经支持的 tracer 包括:

Function tracerFunction graph tracer: 跟踪函数调用。

Schedule switch tracer: 跟踪进程调度情况。

Wakeup tracer:跟踪进程的调度延迟,即高优先级进程从进入 ready 状态到获得 CPU 的延迟时间。该 tracer 只针对实时进程。

Irqsoff tracer:当中断被禁止时,系统无法相应外部事件,比如键盘和鼠标,时钟也无法产生 tick 中断。这意味着系统响应延迟,irqsoff 这个 tracer 能够跟踪并记录内核中哪些函数禁止了中断,对于其中中断禁止时间最长的,irqsoff 将在 log 文件的第一行标示出来,从而使开发人员可以迅速定位造成响应延迟的罪魁祸首。

Preemptoff tracer:和前一个 tracer 类似,preemptoff tracer 跟踪并记录禁止内核抢占的函数,并清晰地显示出禁止抢占时间最长的内核函数。

Preemptirqsoff tracer: 同上,跟踪和记录禁止中断或者禁止抢占的内核函数,以及禁止时间最长的函数。

Branch tracer: 跟踪内核程序中的 likely/unlikely 分支预测命中率情况。 Branch tracer 能够记录这些分支语句有多少次预测成功。从而为优化程序提供线索。

Hardware branch tracer:利用处理器的分支跟踪能力,实现硬件级别的指令跳转记录。在 x86 上,主要利用了 BTS 这个特性。

Initcall tracer:记录系统在 boot 阶段所调用的 init call 。

Mmiotrace tracer:记录 memory map IO 的相关信息。

Power tracer:记录系统电源管理相关的信息。

Sysprof tracer:缺省情况下,sysprof tracer 每隔 1 msec 对内核进行一次采样,记录函数调用和堆栈信息。

Kernel memory tracer: 内存 tracer 主要用来跟踪 slab allocator 的分配情况。包括 kfree,kmem_cache_alloc 等 API 的调用情况,用户程序可以根据 tracer 收集到的信息分析内部碎片情况,找出内存分配最频繁的代码片断,等等。

Workqueue statistical tracer:这是一个 statistic tracer,统计系统中所有的 workqueue 的工作情况,比如有多少个 work 被插入 workqueue,多少个已经被执行等。开发人员可以以此来决定具体的 workqueue 实现,比如是使用 single threaded workqueue 还是 per cpu workqueue.

Event tracer: 跟踪系统事件,比如 timer,系统调用,中断等。

这里还没有列出所有的 tracer,ftrace 是目前非常活跃的开发领域,新的 tracer 将不断被加入内核。

2          搭建环境

2.1      内核配置与重新编译

如果想要支持ftrace,就必须将该特性编译进内核。内核源码目录下的 kernel/trace/Kconfig与kernel/trace/Makefile 文件给出了ftrace相关的编译选项。那么重新配置内核选项,并且重新编译内核。以下步骤:

1. 获取内核源码,(可以从www.kernel.org上下载)

2. 配置选项:

Kernel hacking选项 –> 选择Tracers选项,进入 Tracers 菜单下,可以看到内核支持的跟踪器列表。如下图所示,这里选中了所有的跟踪器,读者可以根据自己的需要选中特定的跟踪器。

要注意的是,如果是在 32 位 x86 机器上,编译时不要选中 General setup 菜单项(下图)下的 Optimize for size 选项,否则就无法看到上述的Kernel Function Graph Tracer 选项。这是因为在 Konfig 文件中,针对 32 位 x86 机器,表项 FUNCTION_GRAPH_TRACER 有一个特殊的依赖条件:“Optimize for size”

ftrace 通过 debugfs 向用户态提供了访问接口,所以还需要将 debugfs 编译进内核。激活对 debugfs 的支持,可以直接编辑内核配置文件 .config ,设置 CONFIG_DEBUG_FS=y ;或者在 make menuconfig 时到 Kernel hacking 菜单下选中对 debugfs 文件系统的支持,即选中选项“Debug Filesystem”。

配置完成后,编译安装新内核,然后启动到新内核。

注意,激活 ftrace 支持后,编译内核时会使用编译器的 -pg 选项,这是在 kernel/trace/Makefile 文件中定义的,如下图所示。

  12 # Do not instrument the tracer itself:3

 

4 ifdef CONFIG_FUNCTION_TRACER

5 ORIG_CFLAGS := $(KBUILD_CFLAGS)

6 KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))

7

8 # selftest needs instrumentation

使用 -pg 选项会在编译得到的内核映像中加入大量的调试信息。一般情况下,只是在开发测试阶段激活 ftrace 支持,以调试内核,修复 bug 。最终用于发行版的内核则会关闭 -pg 选项,也就无法使用 ftrace。

 

2.2      激活Ftrace

ftrace 通过debugfs向用户态提供访问接口。配置内核时激活 debugfs 后会创建目录/sys/kernel/debug(如果重启到没有挂载,可以重新挂载到一个新目录),debugfs 文件系统就是挂载到该目录。

# mount -t debugfs nodev /sys/kernel/debug

在/sys/kernel/debug/tracing目录下有如下文件:

root@RedHat linux-3.2-trace]# ls /sys/kernel/debug/tracing/available_events            kprobe_profile      trace_clockavailable_filter_functions  options             trace_marker

 

available_tracers           per_cpu             trace_options

buffer_size_kb              printk_formats      trace_pipe

buffer_total_size_kb        README              trace_stat

current_tracer              saved_cmdlines      tracing_cpumask

dyn_ftrace_total_info       set_event           tracing_enabled

enabled_functions           set_ftrace_filter   tracing_max_latency

events                      set_ftrace_notrace  tracing_on

free_buffer                 set_ftrace_pid      tracing_thresh

function_profile_enabled    set_graph_function

kprobe_events               trace

[root@RedHat linux-3.2-trace]#

如果想要在启动时变自动挂载,需要将如下内容添加到/etc/fstab 文件:

debugfs  /sys/kernel/debug  debugfs  defaults  0  0

很多开发者都喜欢简历一个像下面这样的目录:

# mkdir /mnt/debug

# mount -t debugfs nodev /mnt/debug

将会发现在/mnt/debug目录下已经创建了tracing目录。