一、ftrace介绍
本文基于Rockpi 4A
单板Linux 4.4
内核介绍ftrace
的使用方法,其它内核版本的ftrace
使用方法类似。
ftrace(Function Tracer)
是直接内置在Linux
内核的跟踪程序,作为一个内部的tracer
提供给系统的开发者和设计者,帮他们弄清内核正在发生的行为,用于调试或分析用户空间之外的延迟和性能问题。
ftrace
是内核态的strace
,用于追踪内核态的调用记录,功能比strace
强大。ftrace
最开始是一个函数跟踪器,主要用于记录内核函数的运行轨迹。随着功能的增加,演变成一个跟踪框架,包括:用延迟跟踪来检查中断禁用和启用之间发生的情况、抢占和从任务被唤醒到任务实际调度的时间。
整个ftrace
框架可以分为几部分:ftrace
核心框架,RingBuffer
,debugfs
,Tracepoint
和各种Tracer
。见下图:
二、ftrace内核配置
1、内核配置
ftrace Linux
内核驱动配置方法如下:
使用make ARCH=arm64 menuconfig
命令,进入如下配置界面:
选择
Kernel hacking -> Tracers
,进入如下配置界面:在
Branch Profiling (Trace likely/unlikely profiler)
中,可以选择相关的Branch Profiling
,配置如下:ftrace
内核代码路径:kernel/trace/
,相关驱动文件如下:
root@ubuntu:/home/run/code/rockchip-bsp/kernel/kernel/trace# ls *.c
blktrace.c power-traces.c trace_benchmark.c trace_event_perf.c trace_export.c trace_kdb.c trace_output.c trace_sched_wakeup.c trace_stack.c
bpf_trace.c ring_buffer_benchmark.c trace_branch.c trace_events.c trace_functions.c trace_kprobe.c trace_printk.c trace_selftest.c trace_stat.c
ftrace.c ring_buffer.c trace.c trace_events_filter.c trace_functions_graph.c trace_mmiotrace.c trace_probe.c trace_selftest_dynamic.c trace_syscalls.c
gpu-traces.c rpm-traces.c trace_clock.c trace_events_trigger.c trace_irqsoff.c trace_nop.c trace_sched_switch.c trace_seq.c trace_uprobe.c
2、ftrace路径
单板系统启动后,ftrace
通过 debugfs
向用户态提供访问接口。相关接口如下:
root@xiaotianbsp:/sys/kernel/debug/tracing# ls
README options stack_max_size
available_events per_cpu stack_trace
available_filter_functions printk_formats stack_trace_filter
available_tracers saved_cmdlines trace
buffer_size_kb saved_cmdlines_size trace_clock
buffer_total_size_kb saved_tgids trace_marker
current_tracer set_event trace_options
dyn_ftrace_total_info set_event_pid trace_pipe
enabled_functions set_ftrace_filter trace_stat
events set_ftrace_notrace tracing_cpumask
free_buffer set_ftrace_pid tracing_max_latency
function_profile_enabled set_graph_function tracing_on
instances set_graph_notrace tracing_thresh
max_graph_depth snapshot
ftrace
部分节点含义如下:
1)available_filter_functions
可跟踪的所有函数列表,不在其中的函数无法跟踪。
2)available_tracers
可用跟踪器。
3)current_tracer
当前使用的跟踪器。
4)function_profile_enabled
函数性能分析器,打开后,trace_stat/
目录下会显示function
的统计信息。
5)max_graph_depth
显示函数最大调用深度,在后续实例中解释。
6)set_ftrace_filter
设置跟踪的函数列表,支持批量设置,如*ios
。
7)set_ftrace_notrace
设置不跟踪的函数列表。
8)set_ftrace_pid
设置跟踪进程的pid
,可查看用户空间接口使用内核的函数调用关系。
9)trace
跟踪的输出(Ring buffer
)。
10)trace_pipe
跟踪的输出,提供持续不断的数据流(实时输出)。
11)trace_stat/
函数性能分析的输出目录。
12)tracing_on
控制trace
打开和关闭。
上面节点介绍也可通过README
查看
root@linaro-alip:/sys/kernel/debug/tracing# cat README
tracing mini-HOWTO:
# echo 0 > tracing_on : quick way to disable tracing
# echo 1 > tracing_on : quick way to re-enable tracing
Important files:
trace - The static contents of the buffer
To clear the buffer write into this file: echo > trace
trace_pipe - A consuming read to see the contents of the buffer
current_tracer - function and latency tracers
available_tracers - list of configured tracers for current_tracer
buffer_size_kb - view and modify size of per cpu buffer
buffer_total_size_kb - view total size of all cpu buffers
trace_clock -change the clock used to order events
local: Per cpu clock but may not be synced across CPUs
global: Synced across CPUs but slows tracing down.
counter: Not a clock, but just an increment
uptime: Jiffy counter from time of boot
perf: Same clock that perf events use
...
README
对应驱动文件:kernel/trace/trace.c
static const char readme_msg[] =
"tracing mini-HOWTO:\n\n"
"# echo 0 > tracing_on : quick way to disable tracing\n"
"# echo 1 > tracing_on : quick way to re-enable tracing\n\n"
" Important files:\n"
" trace\t\t\t- The static contents of the buffer\n"
"\t\t\t To clear the buffer write into this file: echo > trace\n"
" trace_pipe\t\t- A consuming read to see the contents of the buffer\n"
" current_tracer\t- function and latency tracers\n"
" available_tracers\t- list of configured tracers for current_tracer\n"
" buffer_size_kb\t- view and modify size of per cpu buffer\n"
" buffer_total_size_kb - view total size of all cpu buffers\n\n"
" trace_clock\t\t-change the clock used to order events\n"
" local: Per cpu clock but may not be synced across CPUs\n"
" global: Synced across CPUs but slows tracing down.\n"
" counter: Not a clock, but just an increment\n"
" uptime: Jiffy counter from time of boot\n"
" perf: Same clock that perf events use\n"
....
三、ftrace种类
通过下面的命令可以查看目前系统可用的tracer
和目前使用的tracer
。
root@xiaotianbsp:/# cd /sys/kernel/debug/tracing/
root@xiaotianbsp:/sys/kernel/debug/tracing# cat available_tracers
blk branch function_graph wakeup_dl wakeup_rt wakeup irqsoff function nop
root@xiaotianbsp:/sys/kernel/debug/tracing# cat current_tracer
nop
tracer
有很多类型,主要包括几大类:
1、函数类
1)function
表示函数被调用的流程,类似Linux
内核的dump_stack()
函数功能,需要配置调用栈(options/func_stack_trace
)。
2)function_graph
表示本函数内部的调用实现。
2、延时类
1)irqsoff
当中断被禁止时,系统无法响应外部事件。此时,时钟也无法产生tick
中断,意味着系统响应延迟。irqsoff tracer
能够跟踪并记录内核中哪些函数禁止了中断,对于对于中断禁止事件最长的,irqsoff
将在tracer
文件的第一行标出,方便迅速定位造成响应延迟的罪魁祸首。
2)wakeup_rt
跟踪RT
类型的任务从获得调度到被唤醒的最长延迟时间。
3)wakeup
跟踪普通优先级进程的调度延迟,即高优先级进程从进入ready
状态到获得CPU
的延迟时间。该tracer
只针对实时进程。
4)preemptoff
跟踪并记录禁止内核抢占的函数,并清晰地显示出禁止抢占时间最长的内核函数。
5)preemptirqsoff
跟踪和记录禁止中断或禁止抢占的内核函数,以及禁止时间最长的函数。
3、其他类
1)blk
跟踪块设备函数。
2)branch
跟踪内核程序中的likely
和unlikely
分支预测命中率情况。branch tracer
能够记录这些分支语句有多少次预测成功,从而优化程序提供线索。
3)nop
不跟踪任务内核活动。将nop
写入current_tracer
文件可删除之前所用的跟踪器,并清空之前收集到的跟踪信息。
ftrace
可用来排查下面问题:
1)特定内核函数调用的频次(function
)。
2)内核函数在被调用的过程中路径(调用栈)(function+stack
)。
3)内核函数调用的子函数流程(function graph
)。
4)由于抢占导致的高延时路径等。
四、ftrace使用方法
ftrace
使用方法概括如下:
1)关闭并配置tracer
类型
2)配置tracer
参数
3)打开并查看tracer
内容
1、function
下面介绍如何配置跟踪function
功能。
root@xiaotianbsp:~#cd /sys/kernel/debug/tracing/
## 1、配置tracer类型
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 0 > tracing_on
root@xiaotianbsp:/sys/kernel/debug/tracing# cat available_tracers
blk branch function_graph wakeup_dl wakeup_rt wakeup irqsoff function nop
root@xiaotianbsp:/sys/kernel/debug/tracing# echo function > current_tracer
## 2、设置tracer参数
# 跟踪blk_start_request函数
root@xiaotianbsp:/sys/kernel/debug/tracing# echo blk_start_request > set_ftrace_filter
root@xiaotianbsp:/sys/kernel/debug/tracing# echo > trace ## 清ringbuffer
## 3、查看trace
root@xiaotianbsp:/sys/kernel/debug/tracing# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 0/0 #P:6
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 1 > tracing_on
root@xiaotianbsp:/sys/kernel/debug/tracing# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 0/0 #P:6
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
root@linaro-alip:/sys/kernel/debug/tracing# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 5/5 #P:6
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
mmcqd/0-157 [004] d... 406.503900: blk_start_request <-blk_fetch_request
mmcqd/0-157 [004] d... 406.504015: blk_start_request <-blk_fetch_request
mmcqd/0-157 [004] d... 406.515351: blk_start_request <-blk_fetch_request
mmcqd/0-157 [004] d... 406.549479: blk_start_request <-blk_fetch_request
mmcqd/0-157 [004] d... 406.599922: blk_start_request <-blk_fetch_request
如果想查看函数调用栈,可增加如下配置:
root@linaro-alip:/sys/kernel/debug/tracing# echo 0 > tracing_on
root@linaro-alip:/sys/kernel/debug/tracing# echo > trace
# 配置函数栈跟踪
root@linaro-alip:/sys/kernel/debug/tracing# echo 1 > options/func_stack_trace
root@linaro-alip:/sys/kernel/debug/tracing# echo 1 > tracing_on
root@linaro-alip:/sys/kernel/debug/tracing# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 4/4 #P:6
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
mmcqd/0-157 [004] d... 232.540969: blk_start_request <-blk_fetch_request
mmcqd/0-157 [004] d... 232.540978: <stack trace> ## 显示函数调用栈
=> ftrace_ops_no_ops
=> ftrace_graph_call
=> blk_start_request
=> blk_fetch_request
=> mmc_queue_thread
=> kthread
=> ret_from_fork
mmcqd/0-157 [004] d... 232.553196: blk_start_request <-blk_fetch_request
mmcqd/0-157 [004] d... 232.553202: <stack trace>
=> ftrace_ops_no_ops
=> ftrace_graph_call
=> blk_start_request
=> blk_fetch_request
=> mmc_queue_thread
=> kthread
=> ret_from_fork
2、function_graph
下面介绍如何配置跟踪function_graph
功能。
root@xiaotianbsp:~#cd /sys/kernel/debug/tracing/
## 1、配置tracer类型
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 0 > tracing_on
root@xiaotianbsp:/sys/kernel/debug/tracing# cat available_tracers
blk branch function_graph wakeup_dl wakeup_rt wakeup irqsoff function nop
root@xiaotianbsp:/sys/kernel/debug/tracing# echo function_graph > current_tracer
## 2、设置tracer参数
root@xiaotianbsp:/sys/kernel/debug/tracing# echo blk_start_request > set_graph_function
root@xiaotianbsp:/sys/kernel/debug/tracing# echo > trace ## 清ringbuffer
## 3、查看trace
root@xiaotianbsp:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 1 > tracing_on
root@xiaotianbsp:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
4) | blk_start_request() { ## 显示函数内部调用时间
4) 1.166 us | blk_dequeue_request();
4) 0.584 us | blk_add_timer();
4) + 12.250 us | }
4) | blk_start_request() {
4) 1.166 us | blk_dequeue_request();
4) 0.584 us | blk_add_timer();
4) + 12.250 us | }
3、trace pid
下面介绍如何配置跟踪进程pid
调用流程功能。
root@xiaotianbsp:~#cd /sys/kernel/debug/tracing/
## 1、配置tracer类型
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 0 > tracing_on
root@xiaotianbsp:/sys/kernel/debug/tracing# cat available_tracers
blk branch function_graph wakeup_dl wakeup_rt wakeup irqsoff function nop
root@xiaotianbsp:/sys/kernel/debug/tracing# echo function_graph > current_tracer
## 2、设置tracer参数
root@xiaotianbsp:/sys/kernel/debug/tracing# ps -A | grep mmc
155 ? 00:00:00 irq/27-mmc1
157 ? 00:00:02 mmcqd/0 ## 跟踪该pid
182 ? 00:00:00 jbd2/mmcblk0p5-
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 157 > set_ftrace_pid
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 8 > max_graph_depth
root@xiaotianbsp:/sys/kernel/debug/tracing# echo > trace ## 清ringbuffer
## 3、查看trace
root@xiaotianbsp:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
root@xiaotianbsp:/sys/kernel/debug/tracing# echo 1 > tracing_on
root@xiaotianbsp:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
...
4) | blk_fetch_request() { ## sd卡相关操作
4) | blk_peek_request() {
4) | deadline_dispatch_requests() {
4) | deadline_remove_request.isra.0() {
4) 0.584 us | elv_rb_del();
4) 5.542 us | }
4) | elv_dispatch_add_tail() {
4) 0.292 us | elv_rqhash_del.isra.0();
4) 5.542 us | }
4) + 20.708 us | }
4) | mmc_prep_request() {
4) 0.583 us | mmc_access_rpmb();
4) 5.834 us | }
4) + 37.333 us | }
4) | blk_start_request() {
4) 0.875 us | blk_dequeue_request();
4) 0.584 us | blk_add_timer();
4) + 11.083 us | }
4) + 57.750 us | }
...
其它类型后续介绍。
注:ftrace也可以用trace-cmd命令代替操作debugfs下的trace节点跟踪,配合kernelshark,可图形化分析数据。