一、ftrace介紹
本文基于Rockpi 4A單板Linux 4.4內(nèi)核介紹ftrace的使用方法,其它內(nèi)核版本的ftrace使用方法類似。
ftrace(Function Tracer)是直接內(nèi)置在Linux內(nèi)核的跟蹤程序,作為一個(gè)內(nèi)部的tracer提供給系統(tǒng)的開發(fā)者和設(shè)計(jì)者,幫他們弄清內(nèi)核正在發(fā)生的行為,用于調(diào)試或分析用戶空間之外的延遲和性能問題。
ftrace是內(nèi)核態(tài)的strace,用于追蹤內(nèi)核態(tài)的調(diào)用記錄,功能比strace強(qiáng)大。ftrace最開始是一個(gè)函數(shù)跟蹤器,主要用于記錄內(nèi)核函數(shù)的運(yùn)行軌跡。隨著功能的增加,演變成一個(gè)跟蹤框架,包括:用延遲跟蹤來檢查中斷禁用和啟用之間發(fā)生的情況、搶占和從任務(wù)被喚醒到任務(wù)實(shí)際調(diào)度的時(shí)間。
整個(gè)ftrace框架可以分為幾部分:ftrace核心框架,RingBuffer,debugfs,Tracepoint和各種Tracer。見下圖:

二、ftrace內(nèi)核配置
1、內(nèi)核配置
ftrace Linux內(nèi)核驅(qū)動(dòng)配置方法如下:
使用make ARCH=arm64 menuconfig命令,進(jìn)入如下配置界面:

選擇
Kernel hacking -> Tracers,進(jìn)入如下配置界面:
在
Branch Profiling (Trace likely/unlikely profiler)中,可以選擇相關(guān)的Branch Profiling,配置如下:
ftrace內(nèi)核代碼路徑:kernel/trace/,相關(guān)驅(qū)動(dòng)文件如下:
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路徑
單板系統(tǒng)啟動(dòng)后,ftrace 通過 debugfs向用戶態(tài)提供訪問接口。相關(guān)接口如下:
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部分節(jié)點(diǎn)含義如下:
1)available_filter_functions
可跟蹤的所有函數(shù)列表,不在其中的函數(shù)無法跟蹤。
2)available_tracers
可用跟蹤器。
3)current_tracer
當(dāng)前使用的跟蹤器。
4)function_profile_enabled
函數(shù)性能分析器,打開后,trace_stat/目錄下會(huì)顯示function的統(tǒng)計(jì)信息。
5)max_graph_depth
顯示函數(shù)最大調(diào)用深度,在后續(xù)實(shí)例中解釋。
6)set_ftrace_filter
設(shè)置跟蹤的函數(shù)列表,支持批量設(shè)置,如*ios。
7)set_ftrace_notrace
設(shè)置不跟蹤的函數(shù)列表。
8)set_ftrace_pid
設(shè)置跟蹤進(jìn)程的pid,可查看用戶空間接口使用內(nèi)核的函數(shù)調(diào)用關(guān)系。
9)trace
跟蹤的輸出(Ring buffer)。
10)trace_pipe
跟蹤的輸出,提供持續(xù)不斷的數(shù)據(jù)流(實(shí)時(shí)輸出)。
11)trace_stat/
函數(shù)性能分析的輸出目錄。
12)tracing_on
控制trace打開和關(guān)閉。
上面節(jié)點(diǎn)介紹也可通過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對應(yīng)驅(qū)動(dòng)文件: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種類
通過下面的命令可以查看目前系統(tǒng)可用的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、函數(shù)類
1)function
表示函數(shù)被調(diào)用的流程,類似Linux內(nèi)核的dump_stack()函數(shù)功能,需要配置調(diào)用棧(options/func_stack_trace)。
2)function_graph
表示本函數(shù)內(nèi)部的調(diào)用實(shí)現(xiàn)。
2、延時(shí)類
1)irqsoff
當(dāng)中斷被禁止時(shí),系統(tǒng)無法響應(yīng)外部事件。此時(shí),時(shí)鐘也無法產(chǎn)生tick中斷,意味著系統(tǒng)響應(yīng)延遲。irqsoff tracer能夠跟蹤并記錄內(nèi)核中哪些函數(shù)禁止了中斷,對于對于中斷禁止事件最長的,irqsoff將在tracer文件的第一行標(biāo)出,方便迅速定位造成響應(yīng)延遲的罪魁禍?zhǔn)住?/p>
2)wakeup_rt
跟蹤RT類型的任務(wù)從獲得調(diào)度到被喚醒的最長延遲時(shí)間。
3)wakeup
跟蹤普通優(yōu)先級(jí)進(jìn)程的調(diào)度延遲,即高優(yōu)先級(jí)進(jìn)程從進(jìn)入ready狀態(tài)到獲得CPU的延遲時(shí)間。該tracer只針對實(shí)時(shí)進(jìn)程。
4)preemptoff
跟蹤并記錄禁止內(nèi)核搶占的函數(shù),并清晰地顯示出禁止搶占時(shí)間最長的內(nèi)核函數(shù)。
5)preemptirqsoff
跟蹤和記錄禁止中斷或禁止搶占的內(nèi)核函數(shù),以及禁止時(shí)間最長的函數(shù)。
3、其他類
1)blk
跟蹤塊設(shè)備函數(shù)。
2)branch
跟蹤內(nèi)核程序中的likely和unlikely分支預(yù)測命中率情況。branch tracer能夠記錄這些分支語句有多少次預(yù)測成功,從而優(yōu)化程序提供線索。
3)nop
不跟蹤任務(wù)內(nèi)核活動(dòng)。將nop寫入current_tracer文件可刪除之前所用的跟蹤器,并清空之前收集到的跟蹤信息。
ftrace可用來排查下面問題:
1)特定內(nèi)核函數(shù)調(diào)用的頻次(function)。
2)內(nèi)核函數(shù)在被調(diào)用的過程中路徑(調(diào)用棧)(function+stack)。
3)內(nèi)核函數(shù)調(diào)用的子函數(shù)流程(function graph)。
4)由于搶占導(dǎo)致的高延時(shí)路徑等。
四、ftrace使用方法
ftrace使用方法概括如下:
1)關(guān)閉并配置tracer類型
2)配置tracer參數(shù)
3)打開并查看tracer內(nèi)容
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、設(shè)置tracer參數(shù)
# 跟蹤blk_start_request函數(shù)
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
如果想查看函數(shù)調(diào)用棧,可增加如下配置:
root@linaro-alip:/sys/kernel/debug/tracing# echo 0 > tracing_on
root@linaro-alip:/sys/kernel/debug/tracing# echo > trace
# 配置函數(shù)棧跟蹤
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> ## 顯示函數(shù)調(diào)用棧
=> 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、設(shè)置tracer參數(shù)
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() { ## 顯示函數(shù)內(nèi)部調(diào)用時(shí)間
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
下面介紹如何配置跟蹤進(jìn)程pid調(diào)用流程功能。
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、設(shè)置tracer參數(shù)
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卡相關(guān)操作
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 | }
...
其它類型后續(xù)介紹。
注:ftrace也可以用trace-cmd命令代替操作debugfs下的trace節(jié)點(diǎn)跟蹤,配合kernelshark,可圖形化分析數(shù)據(jù)。