說明背景
文檔作為會議的記錄和補充,會議主題是《使用Ftrace研究Linux內核》,主講人謝歡。回放鏈接
基本內容
1、Ftrace整體框架
-
function tracer:在函數(shù)頭掛鉤子函數(shù)
-
function graph tracer:可以帶時間戳函數(shù)執(zhí)行流打印
-
kprobe:一般是掛在函數(shù)入口點,用于獲取參數(shù)
-
trace event:函數(shù)執(zhí)行時調用靜態(tài)的鉤子函數(shù)
-
kretprobe:通常是函數(shù)出口點,執(zhí)行鉤子函數(shù)
2、使用方式
Ftrace通過tracefs文件系統(tǒng)的控制文件來進行調試。如果內核構建階段配置ftrace,默認會掛載tracefs到/sys/kernel/tracing,也可以在運行環(huán)境手動掛載
接下來的內容我會根據(jù)課程介紹,整理出ftrace不同功能的使用案例,一些問答和和觀點以及個人對課程總結。
function tracer使用
case01: 過濾"vfs_open"函數(shù)
觀察結果:圖示能看到所有執(zhí)行vfs_open的跟蹤信息。
function graph tracer使用
case01: 函數(shù)"vfs_open"的執(zhí)行時間
echo vfs_open > ./set_ftrace_filter # 過濾要跟蹤的函數(shù)
echo function_graph > ./current_tracer # 設置當前使用的tracer
echo 1 > ./options/funcgraph-proc # 啟用進程TASK/PID打印
cp trace /test.txt && cat /test.txt
觀察結果:查看到vfs_open被執(zhí)行的調試信息包括TASK/PID,函數(shù)的執(zhí)行時間在,接口名。原理上是通過在函數(shù)的入口點和出口點(kprobe/kretprobe)掛鉤子來實現(xiàn)的。
case02: 函數(shù)"vfs_open"向下執(zhí)行流
echo > ./set_ftrace_filter # 不使用過濾!!!
echo vfs_open > ./set_graph_function # 使用函數(shù)圖表
echo function_graph > ./current_tracer # 過濾要跟蹤的函數(shù)
echo 1 > ./options/funcgraph-proc # 打印進程TASK/PID
echo 1 > ./options/funcgraph-tail # 尾部注釋(方便觀察)
cp trace /test.txt && cat /test.txt

觀察結果:vfs_open被執(zhí)行時,能看到向下的執(zhí)行流程,其中涉及到的函數(shù)調用和相關信息會打印出來。
kprobe event
case01: 查看"vfs_open"當前打開文件名
# 理論計算:
# $arg1, 第一個參數(shù)
# +0x8($arg1), 地址偏移+0x8
# +0x70(+0x8($arg1)), 相當與C語言的 *(*($arg1 + 0x8) + 0x70)
echo 'p vfs_open name=+0x70(+0x8($arg1)):string namep=+0(+0x60(+0x8($arg1))):string' > ./kprobe_events
echo 1 > ./events/kprobes/p_vfs_open_0/enable
echo > trace && cat /test.txt
cp trace /test.txt && cat /test.txt
觀察結果:圖示看到一些vfs_open函數(shù)的kprobe事件,name是當前被查看的文件名。kprobe通過參數(shù)加地址偏移計算拿到特定成員的地址
case02: 捕獲"vfs_open"查看指定文件的信息的事件
# 功能: 利用filter和trigger文件
root@debian:/sys/kernel/debug/tracing# ls ./events/kprobes/p_vfs_open_0/
enable filter format hist id inject trigger
# 格式: kprobe event
root@debian:/sys/kernel/debug/tracing# cat ./events/kprobes/p_vfs_open_0/format
echo 'p vfs_open name=+0x70(+0x8($arg1)):string namep=+0(+0x60(+0x8($arg1))):string' > ./kprobe_events
echo 1 > ./events/kprobes/p_vfs_open_0/enable # 過濾包含"test"字段的文件的事件
echo 'name ~ "*test*"' > ./events/kprobes/p_vfs_open_0/filter
echo > trace && cat /test.txt
echo 'stacktrace if name ~ "*test*"' > ./events/kprobes/p_vfs_open_0/trigger # 包含"test"字段的文件的事件會觸發(fā)"stacktrace"堆棧打印
trace event
cat /sys/kernel/debug/tracing/available_events # 查看當前支持的跟蹤事件列表
case01: 打開驅動中跟蹤節(jié)點
echo 1 > /sys/kernel/debug/tracing/events/gsgpu/enable &&
echo 0 > /sys/kernel/debug/tracing/trace &&
/root/run_test.sh ; cp /sys/kernel/debug/tracing/trace /test.txt &&
echo 0 > /sys/kernel/debug/tracing/events/gsgpu/enable
cat /test.txt
case02: 通過filter過濾事件
echo 0 > /sys/kernel/debug/tracing/events/gsgpu/enable &&
echo 1 > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/enable &&
echo 0 > /sys/kernel/debug/tracing/trace &&
echo "bo_size >= 50000" > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/filter &&
/root/run_test.sh ; cp /sys/kernel/debug/tracing/trace /test.txt &&
echo 0 > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/filter
cat /test.txt
case03: 通過trigger查看棧回溯
echo 0 > /sys/kernel/debug/tracing/events/gsgpu/enable &&
echo 1 > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/enable &&
echo 0 > /sys/kernel/debug/tracing/trace &&
echo 'stacktrace' > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/trigger &&
/root/run_test.sh ; cp /sys/kernel/debug/tracing/trace /test.txt &&
echo '!stacktrace' > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/trigger &&
cat /test.txt
objtrace
case01:觀察對象數(shù)據(jù)在函數(shù)中流動
源碼位置:https://github.com/x-lugoo/linux/tree/objtrace-v9
[root@JeffXie tracing]# cat ./events/kprobes/p_bio_add_page_0/trigger
Available triggers: traceon traceoff snapshot stacktrace enable_event disable_event hist objtrace
cd /sys/kernel/debug/tracing/
echo 'p bio_add_page arg1=$arg1 arg2=$arg2' > ./kprobe_events
echo 'objtracearg1,0x285 if comm == "cat"' > ./events/kprobes/p_bio_add_page_0/trigger
# du -sh /test.txt // 12K
cat /test.txt > /dev/null
cat ./trace
觀察結果:參數(shù)arg1對應object對象,由于有kprobe匹配到目標參數(shù)達到觸發(fā)條件,我看到圖示中打印的調試信息。這樣就可以觀察到指定接口的參數(shù)在內核函數(shù)中是怎樣流動的
一些觀點
-
1、ftrace很多功能在國內使用不充分,比如tracer網(wǎng)上資料少,ftrace功能很強大,可挖掘的潛力大。像是大家對shell的使用,如果大家能積累更多的案例,這樣能更好的普及和使用。
-
2、ftrace和正常的日志環(huán)形緩沖區(qū)不同,如果大量日志向同一個緩沖區(qū)輸入,一會導致信息混亂,二是容易覆蓋有效數(shù)據(jù)。使用ftrace的過濾等功能,可以更好的解決此類問題(適用更加復雜的業(yè)務場景)。補充ftrace其他功能:自動保存結果輸出到文件;生成直方圖;觸發(fā)其他事件;等等。
-
3、ftrace對內核的通用性還是比較強的,相比ebpf來說ftrace對于低版本的內核更加友好。
-
4、ftrace的用戶群體大,但是名聲沒有ebpf的功能大。
-
5、ftrace的tracer在linux中使用shell腳本來實現(xiàn),如果想要觀察和定位,使用這種手段方便;如果轉發(fā)類或者做業(yè)務相關的,推薦使用ebpf比較多。可以根據(jù)各自優(yōu)勢應用到不同的場景,也可以兩者結合使用。
一些問答
問
perf/ftrace/ebpf關系
答
基于kprobe的ebpf通過 fd找到字節(jié)碼程序,當perf使用相同功能的時候,可以依據(jù) fd來找到這個字節(jié)碼程序。基于kprobe的ebpf本質上是基于ftrace, 使用ftrace框架來調用字節(jié)碼程序
#使用bpftrace工具將ebpf程 序掛載到"kprobe:do_ nanosleep"bpftrace -e 'kprobe:do_nanosleep { printf("PID %d sleeping... ", pid); }'
問
kprobe和function trace的鉤子有什么區(qū)別?
答
基本相同,kprobe的鉤子函數(shù)會做更多的解析工作,例如解析更多的 field(例如argN或stackN等)
問
什么是no trace函數(shù)?
答
如果函數(shù)本身參與ftrace功能,不能用于trace(避免遞歸) 這樣的函數(shù)一般都是no trace。
問
uprobe是用什么實現(xiàn)的?
答
uprobe在用戶層,基于斷點指令來實現(xiàn)。
問
ftrace對性能影響多大?
答
看如何使用?如果對所有函數(shù)使用function tracer,如果只使用一個性能事件性能消耗很小。
問
如果從學習內核的角度來講,怎樣把ftrace作為一個輔助的工具來上手內核?
答
在調試內核的時候,通常使用printk/printf來使用,使用ftrace的前提要戒掉這個習慣,然后使用ftrace工具來調試。
問
對于可靠性和安全性比較高的領域,對于ftrace是不是要慎用一些?
答
是的,對原理理解要求比較高一些。對原理比較清楚的話,能很好的縮小ftrace的使用范圍,來進一步降低對系統(tǒng)的性能消耗。
問
如何評估這些調試工具的開銷?
答
正確對待ftrace是一個輔助工具,前提還是要對代碼比較熟悉,ftrace輔助對代碼的觀察。
問
ftrace這樣的工具好處?
答
使用在不破壞內核的情況下,提供一個對內核可觀測手段;提供基礎的tracer功能,靈活運用好tracer功能對分析問題幫助;perf工具將各種類型的掛載點收入囊中,一統(tǒng)江湖。
問
linux內核中有這么多鉤子?都有什么局限,如何選擇
答
看具體想使用哪些功能,比如查看函數(shù)怎么執(zhí)行,選擇function tracer;比如查看某一個函數(shù)的參數(shù),使用kprobe掛載點對應的鉤子函數(shù)不一樣的。
問
ftrace的tracer在linux中使用shell腳本來實現(xiàn),如果想要觀察和定位,使用這種手段方便;如果轉發(fā)類或者做業(yè)務相關的,推薦使用ebpf比較多
答
各有優(yōu)勢,應用到不同的場景,也可以兩者結合使用。
問
在嵌入式場景,內存資源比較緊張的時候適用么?
答
內存消耗比較小。也可以設置,buffer可以調小一些。
問
ftrace在性能消耗比ebpf更小么?
答
也不一定,看使用那部分功能。
問
有沒有推薦的日志化性能分析的圖形工具?
答
tracecmd和KernelShark。
個人總結
內核源碼中放置很多靜態(tài)跟蹤節(jié)點,這些節(jié)點可以被關聯(lián)到對應的回調函數(shù)。當我想要調試某個子系統(tǒng)/模塊時,通過debug系統(tǒng)將對應的節(jié)點開啟(將回調函數(shù)掛鉤子到靜態(tài)跟蹤點上,與之關聯(lián)),這樣內核在執(zhí)行到跟蹤點位置的時候會調用鉤子函數(shù),最終執(zhí)行結果將被輸出寫到一個環(huán)形日志緩存區(qū)里,通過debug系統(tǒng)查看信息。
作為一種內核層面的調試手段,trace event利用了ftrace框架,算是ftrace的一個應用吧。當我想要調試某一個模塊,開啟對應的節(jié)點就好了,trace event基于現(xiàn)有的跟蹤節(jié)點(一般是寫代碼的添加好的)效率高些,或者解決新的bug時將關鍵調試信息固化到調試系統(tǒng)里。
從做工作的角度,我能體會到的是trace event工具能帶來工作效率的提升。從學習的角度,我相信使用ftrace工具能更加方便觀測內核。
審核編輯 :李倩
-
內核
+關注
關注
3文章
1416瀏覽量
41413 -
Linux
+關注
關注
87文章
11509瀏覽量
213714
原文標題:會議記錄|使用Ftrace研究Linux內核
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
如何配置和驗證Linux內核參數(shù)
Linux內核編譯失敗?移動硬盤和虛擬機的那些事兒

樹莓派4 性能大比拼:標準Linux與實時Linux 4.19內核的延遲測試

基于OpenSBI的linux nommu實現(xiàn)

騰訊云內核團隊修復Linux關鍵Bug
嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-Linux內核移植之內核簡介
飛凌嵌入式ElfBoard ELF 1板卡-Linux內核移植之內核簡介
Linux系統(tǒng)中shell命令解析
deepin社區(qū)亮相第19屆中國Linux內核開發(fā)者大會
linux內核中通用HID觸摸驅動

詳解linux內核的uevent機制
linux驅動程序如何加載進內核
linux驅動程序的編譯方法是什么
Linux內核測試技術

Linux內核中的頁面分配機制

評論