Trace 对于软件的维护和性能分析至关重要,ftrace 是当前 Linux 内核中一种新的 trace 工具。
ftrace(函数跟踪)是内核跟踪的“瑞士军刀”。它是内建在Linux内核中的一种跟踪机制。它能深入内核去发现里面究竟发生了什么,并调试它。ftrace不只是一个函数跟踪工具,它的跟踪能力之强大,还能调试和分析诸如延迟、意外代码路径、性能问题等一大堆问题。它也是一种很好的学习工具。
ftrace是由Steven Rostedy和Ingo Molnar在内核2.6.27版本中引入的。它有自己存储跟踪数据的环形缓冲并使用GCC配置机制
Ftrace 安装
http://www.omappedia.org/wiki/Installing_and_Using_Ftrace
==================================================
ftrace 相关的配置选项比较多,针对不同的跟踪器有各自对应的配置选项。不同的选项有不同的依赖关系,内核源码目录下的 kernel/trace/Kconfig 文件描述了这些依赖关系。读者可以参考 Makefile 文件和 Konfig 文件,然后选中自己所需要的跟踪器。
通常在配置内核时,使用 make menuconfig 会更直观一些。要将 ftrace 编译进内核,选中如下选项:
Kernel Hacking -> Tracers -> FUNCTION_TRACER
Kernel Hacking -> Tracers -> FUNCTION_GRAPH_TRACER (if possible)
Kernel Hacking -> Tracers -> STACK_TRACER // Trace max stack
Kernel Hacking -> Tracers -> DYNAMIC_FTRACE // enable/disable ftrace tracepoints dynamically
ftrace 通过 debugfs 向用户态提供访问接口。配置内核时激活 debugfs 后会创建目录 /sys/kernel/debug ,debugfs 文件系统就是挂载到该目录。要挂载该目录,挂载方法:
# mount -t debugfs nodev /sys/kernel/debug
tracing目录(/sys/kernel/debug/tracing)中的文件控制着跟踪的能力。根据你在内核配置时的选项的不同,这里列的文件可能稍有差异。你可以在内核源代码目录下/Documentation/trace[1]目录中找到这些文件的信息。
root@debian:/sys/kernel/debug# ls tracing/
available_events kprobe_events set_graph_function
available_filter_functions kprobe_profile snapshot
available_tracers max_graph_depth trace
buffer_size_kb options trace_clock
buffer_total_size_kb per_cpu trace_marker
current_tracer printk_formats trace_options
dyn_ftrace_total_info README trace_pipe
enabled_functions saved_cmdlines trace_stat
events set_event tracing_cpumask
free_buffer set_ftrace_filter tracing_max_latency
function_profile_enabled set_ftrace_notrace tracing_on
instances set_ftrace_pid tracing_thresh
让我们看看里面几个重要的文件:
● available_tracers: 被编译里系统的跟踪器。
● current_tracer: 这表示当前启用的哪个跟踪器。可以通过echo向表输入一个新的跟踪器来改变相应值。
● tracing_enabled: 让你可以启用或者禁用当前跟踪功能
● trace: 实际地的跟踪输出。
● set_ftrace_pid: 设置跟踪所作用的进程的PID。
root@debian:/sys/kernel/debug/tracing# cat available_tracers
blk function_graph wakeup_rt wakeup irqsoff function nop
# cat current_tracer ##查看当前在用哪个跟踪器。
# echo function > current_tracer ##选择一个特定的跟踪器。
# cat current_tracer ##检查是否是你所设置的跟踪器。
# echo 1 > tracing_on ##初始化跟踪。
# cat trace > /tmp/trace.txt ##将跟踪文件保存到一个临时文件。
# echo 0 > tracing_on ##禁用跟踪功能
# cat /tmp/trace.txt ##查看trace文件的输出。
现在trace文件的输入在trace.txt文件中。通过上面操作所得到的函数跟踪的一个示例输出
root@debian:/sys/kernel/debug/tracing# cat /tmp/trace.txt | head -25
# tracer: function
#
# entries-in-buffer/entries-written: 88013/1669673 #P:2
#
# _-------=> irqs-off
# / _------=> need-resched
# |/ _-----=> need-resched_lazy
# ||/ _----=> hardirq/softirq
# |||/ _---=> preempt-depth
# ||||/ _--=> preempt-lazy-depth
# ||||| / _-=> migrate-disable
# |||||| / delay
# TASK-PID CPU# |||||| TIMESTAMP FUNCTION
# | | | |||||| | |
bash-19599 [001] .....11 180574.090770: rt_spin_lock <-lockref_put_or_lock
bash-19599 [001] .....11 180574.090770: rt_spin_unlock <-lockref_put_or_lock
bash-19599 [001] .....11 180574.090770: migrate_enable <-lockref_put_or_lock
bash-19599 [001] .....11 180574.090771: add_preempt_count <-migrate_enable
bash-19599 [001] ....11. 180574.090771: unpin_current_cpu <-migrate_enable
bash-19599 [001] ....11. 180574.090771: sub_preempt_count <-migrate_enable
bash-19599 [001] ....... 180574.090772: inode_permission <-link_path_walk
bash-19599 [001] ....... 180574.090772: __inode_permission <-inode_permission
bash-19599 [001] ....... 180574.090772: generic_permission <-__inode_permission
bash-19599 [001] ....... 180574.090773: security_inode_permission <-__inode_permission
bash-19599 [001] ....... 180574.090773: selinux_inode_permission <-security_inode_permission
root@debian:/sys/kernel/debug/tracing#
tracing的输入可以由一个叫trace_options的文件控制。可以通过更新/sys/kernel/debug/tracing/trace_options文件的选项来启用或者禁用各种域。trace_options的一个示例:
root@debian:/sys/kernel/debug/tracing# cat trace_options
print-parent
nosym-offset
nosym-addr
noverbose
noraw
nohex
nobin
noblock
nostacktrace
trace_printk
noftrace_preempt
nobranch
annotate
nouserstacktrace
nosym-userobj
noprintk-msg-only
context-info
nolatency-format
sleep-time
graph-time
record-cmd
overwrite
nodisable_on_free
irq-info
markers
function-trace
nofunc_stack_trace
当跟踪完成后,你需要清除set_ftrace_pid文件,用如下命令:> set_ftrace_pid
root@debian:/sys/kernel/debug/tracing# cat set_ftrace_pid
19599
root@debian:/sys/kernel/debug/tracing# > set_ftrace_pid
root@debian:/sys/kernel/debug/tracing# cat set_ftrace_pid
no pid
root@debian:~# echo function_graph > /sys/kernel/debug/tracing/current_tracer
root@debian:~# cat /sys/kernel/debug/tracing/current_tracer
function_graph
root@debian:/sys/kernel/debug/tracing# cat trace | head -10
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
root@debian:/sys/kernel/debug/tracing# cat available_filter_functions | grep vmalloc
vmalloc_sync_all
is_vmalloc_or_module_addr
is_vmalloc_or_module_addr
vmalloc_open
get_vmalloc_info
setup_vmalloc_vm
vmalloc_to_page
remap_vmalloc_range_partial
remap_vmalloc_range
vmalloc_to_pfn
__vmalloc_node_range
__vmalloc_node
vmalloc_32_user
vmalloc_32
vmalloc_exec
vmalloc_node
vmalloc_user
__vmalloc
vmalloc
ext4_kvmalloc
snd_pcm_lib_get_vmalloc_page
snd_pcm_lib_free_vmalloc_buffer
_snd_pcm_lib_alloc_vmalloc_buffer
vmalloc_fault
root@debian:/sys/kernel/debug/tracing#
root@debian:/sys/kernel/debug/tracing# cat available_events | head -10
irq_vectors:thermal_apic_exit
irq_vectors:thermal_apic_entry
irq_vectors:threshold_apic_exit
irq_vectors:threshold_apic_entry
irq_vectors:call_function_single_exit
irq_vectors:call_function_single_entry
irq_vectors:call_function_exit
irq_vectors:call_function_entry
irq_vectors:irq_work_exit
irq_vectors:irq_work_entry
root@debian:/sys/kernel/debug/tracing#
root@debian:/sys/kernel/debug/tracing# echo sys_enter_nice >> set_event
root@debian:/sys/kernel/debug/tracing# cat set_event
syscalls:sys_enter_nice
root@debian:/sys/kernel/debug/tracing# echo '!sys_enter_nice' >> set_event
root@debian:/sys/kernel/debug/tracing# cat set_event
root@debian:/sys/kernel/debug/tracing#