测试环境:VMware 15.5.6 + Debian 10
ftrace是用来跟踪Linux kernel函数调用情况的一个工具,想要使用它,首先要开启该功能:
sysctl kernel.ftrace_enabled=1
随后进入/sys/kernel/debug/tracing,使用ftrace需要用到的工具都在该目录下:
root@drdestiny:~# cd /sys/kernel/debug/tracing
root@drdestiny:/sys/kernel/debug/tracing# ls
available_events per_cpu stack_trace
available_filter_functions printk_formats stack_trace_filter
available_tracers README timestamp_mode
buffer_size_kb saved_cmdlines trace
buffer_total_size_kb saved_cmdlines_size trace_clock
current_tracer saved_tgids trace_marker
dyn_ftrace_total_info set_event trace_marker_raw
enabled_functions set_event_pid trace_options
events set_ftrace_filter trace_pipe
free_buffer set_ftrace_notrace tracing_cpumask
instances set_ftrace_pid tracing_max_latency
kprobe_events set_graph_function tracing_on
kprobe_profile set_graph_notrace tracing_thresh
max_graph_depth snapshot uprobe_events
options stack_max_size uprobe_profile
目录下除了events
、instances
、options
、per_cpu
为目录外,其余均为文件。目前我们能用到的只有:
-
available_filter_functions
-
available_tracers
-
available_tracers
-
trace
-
current_tracer
-
set_ftrace_filter
-
set_ftrace_notrace
-
set_graph_function
-
tracing_on
-
set_graph_notrace
首先明确一点,我们使用ftrace的基本方式就是读写文件,但是这些文件并不是简单的静态文件,ftrace会根据我们写入的内容配置,根据读的文件输出相应内容。
首先通过tracing_on
开启ftrace(开启ftrace,上面的systemctl和这里的tracing_on
缺一不可):
root@drdestiny:/sys/kernel/debug/tracing# echo 1 > tracing_on
将1写入tracing_on
,ftrace就可以使用了(0表示禁用),此时我们读这个文件试试:
root@drdestiny:/sys/kernel/debug/tracing# cat tracing_on
1
在设置tracer之前,我们可以看看当前系统支持哪些tracer:
root@drdestiny:/sys/kernel/debug/tracing# cat available_tracers
blk mmiotrace function_graph function nop
不同的tracer功能也不同,这里只介绍后三个:
function_graph
:function
:nop
:
先设置当前tracer为function
:
echo function > current_tracer
不用担心写入错误内容,如果写入的内容不在available_tracers
中,会报错:
root@drdestiny:/sys/kernel/debug/tracing# echo 1 > current_tracer
-bash: echo: write error: Invalid argument
在追踪我们想追踪的函数之前,我们可以查看该函数是否可追踪,比如,我们想追踪printk:
root@drdestiny:/sys/kernel/debug/tracing# cat available_filter_functions | grep printk
umip_printk
mmiotrace_printk
__printk_ratelimit
printk_timed_ratelimit
vprintk
printk_percpu_data_ready
vprintk_store
vprintk_emit
vprintk_default
early_printk
vprintk_deferred
printk_safe_log_store
__printk_safe_flush
printk_safe_flush
printk_safe_flush_on_panic
printk_nmi_direct_enter
printk_nmi_direct_exit
__printk_safe_enter
__printk_safe_exit
vprintk_func
aa_label_xprintk
aa_label_printk
acpi_handle_printk
xen_raw_printk
dev_vprintk_emit
dev_printk_emit
__dev_printk
dev_printk
__netdev_printk
netdev_printk
__warn_printk
printk
printk_emit
printk_deferred
_ldm_printk
sdev_prefix_printk [scsi_mod]
scmd_printk [scsi_mod]
ata_port_printk [libata]
ata_link_printk [libata]
ata_dev_printk [libata]
lprintk.part.35 [uhci_hcd]
drm_dev_printk [drm]
可以发现printk在列表中。如果想查看所有可追踪的函数,直接读available_filter_functions
即可。
开始追踪:
测试脚本
#!/bin/sh
dir=/sys/kernel/debug/tracing
sysctl kernel.ftrace_enabled=1 # 开启ftrace
echo function > ${dir}/current_tracer
echo 1 > ${dir}/tracing_on
sleep 1
echo 0 > ${dir}/tracing_on
less ${dir}/trace
可以用的tracer:
function:追踪所有内核函数的函数调用
set_graph_function是function_graph的filter设置文件,set_ftrace_filter也可以影响function_graph,即强制使指定函数成为叶子节点
https://lwn.net/Articles/370423/
The function_graph tracer shows the time a function took in the duration field. In the previous articles, it was mentioned that only the leaf functions, the ones that do not call other functions, have an accurate duration, since the duration of parent functions also includes the overhead of the function_graph tracer calling the child functions. By using the
set_ftrace_filter
file, you can force any function into becoming a leaf function in the function_graph tracer, and this will allow you to see an accurate duration of that function.
https://www.kernel.org/doc/Documentation/trace/ftrace.txt
https://linux.cn/article-9838-1.html