1 ftrace 简介
ftrace 是 Linux 内核中提供的一种调试工具。使用 ftrace 可以对内核中发生的事情进行跟踪,可以调试 bug 或者分析内核,也可以帮助开发人员了解 Linux 内核的运行时行为,以便进行故障调试或性能分析。
最早 ftrace 是一个 function tracer,仅能够记录内核的函数调用流程。如今 ftrace 已经成为一个 framework,采用 plugin 的方式支持开发人员添加更多种类的 trace 功能。
Ftrace 由 RedHat 的 Steve Rostedt 负责维护。到 2.6.30 为止,已经支持的 tracer 包括:
Function tracer 和 Function 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目录。