Ftrace設計作爲一個內部的tracer提供給系統的開發者和設計者,幫助他們弄清kernel正在發生的行爲,它能夠調式分析延遲和性能問題。對於前一章節,我們學習了Ftrace發展到現在已經不僅僅是作爲一個function tracer了,它實際上成爲了一個通用的trace工具的框架
- 一方面已經從function tracer擴展到irqsoff tracer、preemptoff tracer
- 另一方面靜態的trace event也成爲trace的一個重要組成部分
通過前面兩節的學習,我們知道了什麼是ftrace,能夠解決什麼問題,從這章開始我們主要是學習,怎麼去使用ftreace解決問題。
1 ftrace基礎用法
ftrace 通過 debugfs 向用戶態提供訪問接口。配置內核時激活 debugfs 後會創建目錄 /sys/kernel/debug ,debugfs 文件系統就是掛載到該目錄。要掛載該目錄,需要將如下內容添加到 /etc/fstab 文件:
debugfs /sys/kernel/debug debugfs defaults 0 0 1
或者可以在運行時掛載:
mount -t debugfs debugfs /sys/kernel/debug
激活內核對 ftrace 的支持後會在 debugfs 下創建一個 tracing 目錄 /sys/kernel/debug/tracing 。該目錄下包含了 ftrace 的控制和輸出文件
root@100ask:/sys/kernel/debug/tracing# ls
available_events events README snapshot trace_pipe
available_filter_functions free_buffer saved_cmdlines stack_max_size trace_stat
available_tracers function_profile_enabled saved_cmdlines_size stack_trace tracing_cpumask
buffer_percent hwlat_detector saved_tgids stack_trace_filter tracing_max_latency
buffer_size_kb instances set_event synthetic_events tracing_on
buffer_total_size_kb kprobe_events set_event_pid timestamp_mode tracing_thresh
current_tracer kprobe_profile set_ftrace_filter trace uprobe_events
dynamic_events max_graph_depth set_ftrace_notrace trace_clock uprobe_profile
dyn_ftrace_total_info options set_ftrace_pid trace_marker
enabled_functions per_cpu set_graph_function trace_marker_raw
error_log printk_formats set_graph_notrace trace_options
其中重點關注以下文件
- trace查看選擇器
查看支持的跟蹤器available_tracers
root@100ask:/sys/kernel/debug/tracing# cat available_tracers
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
類型 | 含義 |
---|---|
function | 函數調用追蹤器,可以看出哪個函數何時調用,可以通過過濾器指定要跟蹤的函數 |
function_graph | 函數調用圖表追蹤器,可以看出哪個函數被哪個函數調用,何時返回 |
blk | block I/O追蹤器,blktrace用戶應用程序 使用的跟蹤器 |
mmiotrace | MMIO(Memory Mapped I/O)追蹤器,用於Nouveau驅動程序等逆向工程 |
wakeup | 跟蹤進程喚醒信息,進程調度延遲追蹤器 |
wakeup_rt | 與wakeup相同,但以實時進程爲對象 |
nop | 不會跟蹤任何內核活動,將 nop 寫入 current_tracer 文件可以刪除之前所使用的跟蹤器,並清空之前收集到的跟蹤信息,即刷新 trace 文件 |
wakeup_dl | 跟蹤並記錄喚醒SCHED_DEADLINE任務所需的最大延遲(如"wakeup”和"wakeup_rt”一樣) |
mmiotrace | 一種特殊的跟蹤器,用於跟蹤二進制模塊。它跟蹤模塊對硬件的所有調用 |
hwlat | 硬件延遲跟蹤器。它用於檢測硬件是否產生任何延遲 |
查看當前的跟蹤器current_tracer ,可以echo選擇
root@100ask:/sys/kernel/debug/tracing# cat current_tracer
nop
- trace使能
tracing_on :是否往循環buffer寫跟蹤記錄,可以echo設置
root@100ask:/sys/kernel/debug/tracing# cat tracing_on
1
-
trace過濾器選擇(可選)
-
set_ftrace_filter/set_graph_notrace:(function跟蹤器)函數過濾器,echo xxx設置要跟蹤的函數,
root@100ask:/sys/kernel/debug/tracing# cat set_ftrace_filter
all functions enabled
-
-
trace數據讀取
- trace:可以cat讀取跟蹤記錄的buffer內容(查看的時候會臨時停止跟蹤)
- trace_pipe:類似trace可以動態讀取的流媒體文件(差異是每次讀取後,再讀取會讀取新內容)
所以對於ftrace的三步法爲:
- 1 設置tracer類型
- 2 設置tracer參數
- 3 使能tracer
1.2 function trace實例
function,函數調用追蹤器, 跟蹤函數調用,默認跟蹤所有函數,如果設置set_ftrace_filter, 則跟蹤過濾的函數,可以看出哪個函數何時調用。
-
available_filter_functions:列出當前可以跟蹤的內核函數,不在該文件中列出的函數,無法跟蹤其活動
-
enabled_functions:顯示有回調附着的函數名稱。
-
function_profile_enabled:打開此選項,在trace_stat中就會顯示function的統計信息。
-
set_ftrace_filter:用於指定跟蹤的函數
-
set_ftrace_notrace:用於指定不跟蹤的函數
-
set_ftrace_pid:用於指定要跟蹤特定進程的函數
Disable tracer:
echo 0 > tracing_on
設置 tracer 類型爲 function:
echo function > current_tracer
set_ftrace_filter 表示要跟蹤的函數,這裏我們只跟蹤 dev_attr_show 函數:
echo dev_attr_show > set_ftrace_filter
Enable tracer:
echo 1 > tracing_on
提取trace結果:
從上圖可以看到 function trace 一個函數的方法基本就是三板斧:
- 設置 current_tracer 爲 function
- 設置要 trace 的函數
- 打開 trace 開關,開始 trace
- 從 trace 信息我們可以獲取很多重要信息:
- 進程信息,TASK-PID,對應任務的名字
- 進程運行的 CPU
- 執行函數時的系統狀態,包括中斷,搶佔等狀態信息
- 執行函數的時間輟,字段 TIMESTAMP 是時間戳,其格式爲“.”,表示執行該函數時對應的時間戳
- FUNCTION 一列則給出了被跟蹤的函數,函數的調用者通過符號 “<-” 標明,這樣可以觀察到函數的調用關係。
function 跟蹤器可以跟蹤內核函數的調用情況,可用於調試或者分析 bug ,還可用於瞭解和觀察 Linux 內核的執行過程。同時ftrace允許你對一個特定的進程進行跟蹤,在/sys/kernel/debug/tracing目錄下,文件set_ftrace_pid的值要更新爲你想跟蹤的進程的PID。
echo $PID > set_ftrace_pid
1.3 function_graph Trace 實例
function_graph 跟蹤器則可以提供類似 C 代碼的函數調用關係信息。通過寫文件 set_graph_function 可以顯示指定要生成調用關係的函數,缺省會對所有可跟蹤的內核函數生成函數調用關係圖。
函數圖跟蹤器對函數的進入與退出進行跟蹤,這對於跟蹤它的執行時間很有用。函數執行時間超過10微秒的標記一個“+”號,超過1000微秒的標記爲一個“!”號。通過echo function_graph > current_tracer可以啓用函數圖跟蹤器。
與 function tracer 類似,設置 function_graph 的方式如下:
設置 tracer 類型爲 function_graph:
echo function_graph > current_tracer
set_graph_function 表示要跟蹤的函數:
echo __do_fault > set_graph_function
echo 1 > tracing_on
捕捉到的 trace 內容
我們跟蹤的是 __do_fault 函數,但是 function_graph tracer 會跟蹤函數內的調用關係和函數執行時間,可以協助我們確定代碼執行流程。比如一個函數內部執行了很多函數指針,不能確定到底執行的是什麼函數,可以用 function_graph tracer 跟蹤一下。
- CPU 字段給出了執行函數的 CPU 號,本例中都爲 1 號 CPU。
- DURATION 字段給出了函數執行的時間長度,以 us 爲單位。
- FUNCTION CALLS 則給出了調用的函數,並顯示了調用流程。
1.4 wakeup
wakeup tracer追蹤普通進程從被喚醒到真正得到執行之間的延遲。
1.5 wakeup-rt
non-RT進程通常看平均延遲。RT進程的最大延遲非常有意義,反應了調度器的性能
二,trace event 用法
2.1 trace event 簡介
trace event 就是利用 ftrace 框架,實現低性能損耗,對執行流無影響的一種信息輸出機制。相比 printk,trace event:
- 不開啓沒有性能損耗
- 開啓後不影響代碼流程
- 不需要重新編譯內核即可獲取 debug 信息
2.2 使用實例
上面提到了 function 的 trace,在 ftrace 裏面,另外用的多的就是 event 的 trace,我們可以在 events 目錄下面看支持那些事件:
上面列出來的都是分組的,我們可以繼續深入下去,譬如下面是查看 sched 相關的事件
對於某一個具體的事件,我們也可以查看:
上述目錄裏面,都有一個 enable 的文件,我們只需要往裏面寫入 1,就可以開始 trace 這個事件。譬如下面就開始 trace sched_wakeup 這個事件:
我們也可以 trace sched 裏面的所有事件:
三,高級技巧
查看函數調用棧
查看函數調用棧是內核調試最最基本得需求,常用方法:
- 函數內部添加 WARN_ON(1)
- ftrace
trace 函數的時候,設置 echo 1 > options/func_stack_trace 即可在 trace 結果中獲取追蹤函數的調用棧。
以 dev_attr_show 函數爲例,看看 ftrace 如何幫我們獲取調用棧:
#cd /sys/kernel/debug/tracing
#echo 0 > tracing_on
#echo function > current_tracer
#echo schedule > set_ftrace_filter
// 設置 func_stack_trace
#echo 1 > options/func_stack_trace
#echo 1 > tracing_on
如何跟蹤一個命令,但是這個命令執行時間很短
我們可以設置ftrace過濾器控制相關文件:
- set_ftrace_filter function tracer :只跟蹤某個函數
- set_ftrace_notrace function tracer :不跟蹤某個函數
- set_graph_function function_graph tracer :只跟蹤某個函數
- set_graph_notrace function_graph tracer :不跟蹤某個函數
- set_event_pid trace event :只跟蹤某個進程
- set_ftrace_pid function/function_graph tracer :只跟蹤某個進程
如果這時候問:如何跟蹤某個進程內核態的某個函數?
答案是肯定的,將被跟蹤進程的 pid 設置到 set_event_pid/set_ftrace_pid 文件即可。
但是如果問題變成了,我要調試 kill 的內核執行流程,如何辦呢?
因爲 kill 運行時間很短,我們不能知道它的 pid,所以就沒法過濾了。
調試這種問題的小技巧,即 腳本化,這個技巧在很多地方用到:
sh -c "echo $$ > set_ftrace_pid; echo 1 > tracing_on; kill xxx; echo 0 > tracing_on"
如何跟蹤過濾多個進程?多個函數?
- 函數名雷同,可以使用正則匹配
# cd /sys/kernel/debug/tracing
# echo 'dev_attr_*' > set_ftrace_filter
# cat set_ftrace_filter
dev_attr_store
dev_attr_show
- 追加某個函數
用法爲:echo xxx >> set_ftrace_filter,例如,先設置 dev_attr_*:
# cd /sys/kernel/debug/tracing
# echo 'dev_attr_*' > set_ftrace_filter
# cat set_ftrace_filter
dev_attr_store
dev_attr_show
再將 ip_rcv 追加到跟蹤函數中:
# cd /sys/kernel/debug/tracing
# echo ip_rcv >> set_ftrace_filter
# cat set_ftrace_filter
dev_attr_store
dev_attr_show
ip_rcv
基於模塊過濾
格式爲:
$ echo 'write*:mod:ext3' > set_ftrace_filter
從過濾列表中刪除某個函數,使用“感嘆號”
感嘆號用來移除某個函數,把上面追加的 ip_rcv 去掉:
# cd /sys/kernel/debug/tracing
# cat set_ftrace_filter
dev_attr_store
dev_attr_show
ip_rcv
# echo '!ip_rcv' >> set_ftrace_filter
# cat set_ftrace_filter
dev_attr_store
四,前端工具
我們可以手工操作/sys/kernel/debug/tracing路徑下的大量的配置文件接口,來使用ftrace的強大功能。但是這些接口對普通用戶來說太多太複雜了,我們可以使用對ftrace功能進行二次封裝的一些命令來操作。
trace-cmd就是ftrace封裝命令其中的一種。該軟件包由兩部分組成
- trace-cmd:提供了數據抓取和數據分析的功能
- kernelshark:可以用圖形化的方式來詳細分析數據,也可以做數據抓取
4.1 trace-cmd
下載編譯ARM64 trace-cmd方法:
git clone [https://github.com/rostedt/trace-cmd.git](https://github.com/rostedt/trace-cmd.git)
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
make
先通過 record 子命令將結果記錄到 trace.dat,再通過 report 命令進行結果提取。命令解釋:
- -p:指定當前的 tracer,類似 echo function > current_tracer,可以是支持的 tracer 中的任意一個
- -l:指定跟蹤的函數,可以設置多個,類似 echo function_name > set_ftrace_filter
- --func-stack:記錄被跟蹤函數的調用棧
在很有情況下不能使用函數追蹤,需要依賴 事件追蹤 的支持,例如:
4.2 kernelshark圖形化分析數據
trace-cmd report主要是使用統計的方式來找出熱點。如果要看vfs_read()一個具體的調用過程,除了使用上一節的trace-cmd report命令,還可以使用kernelshark圖形化的形式來查看,可以在板子上使用trace-cmd record 記錄事件,把得到的trace.data放到linux 桌面系統,用kernelshark打開,看到圖形化的信息