FreeBSD DTrace 基礎了解
背景
可以知道的相關背景知識
歷史
最早在 Sun 裡面使用,後來移植到不同作業統,後來在 illumos 上面也有,在 Windows 也有。OpenDTrace 專案於 2016 年 9 月在GitHub上啟動,專案提供了程式碼和系統內部機制的完整文件。
Brendan Gregg 是澳洲系統效能工程師與開放原始碼開發者,以發明「火焰圖(Flame Graph)」而聞名。他是電腦系統觀測性與效能分析領域的領軍人物,著作廣受產業與學術界引用。2026 年起任職於 OpenAI,負責優化 ChatGPT 的資料中心效能。
Brendan 創建了多個 DTrace script 範本,DTrace 書籍就是他寫的。
事件
在 Track 系統中,我們可以看到不同事件
- 硬體事件,使用硬體計數器 (PMC/PMU),用來分析效能像是:
- FreeBSD pmcstat
- Linux 的 perf
- 偵測 Kernel 的函式,可以用靜態或者動態的 probe,像是:
- FreeBSD 的 DTrace
- FreeBSD truss 追蹤 syscall
- FreeBSD ktrace 為特定 process 開啟核心 log
- Linux strace 追蹤 syscall,使用傳統 ptrace syscall
- Linux ftrace,追蹤核心函式,背後使用 Linux kprobe
- Linux uprobes 追蹤使用者函式
- Linux eBPF,Linux 的 DTrace
靜態事件就是真的一開始編譯就編譯進去,動態事件就是動態添加的,像是函式的進入 and 返回。
比起傳統 ptrace 用一個 process 追蹤,其他損失效能比較小。
DTrace
通常 DTrace 追蹤 Kernel 的一些 static probe,也提供動態 probe,也有提供在 userspace 的 static probe,例如有套件包含一個 DTrace 選項,用於啟用靜態偵測器在這些使用者套件上面。
預設有開啟 DTrace,要確認相關的 dtraceall 核心模組有被載入。
$ dtrace -l | more
49840 fbt kernel ufs_getacl_nfs4_internal return
49841 fbt kernel ufs_getacl entry
49842 fbt kernel ufs_getacl return
49843 fbt kernel ufs_setacl_nfs4_internal entry
49844 fbt kernel ufs_setacl_nfs4_internal return
49845 fbt kernel ufs_setacl entry
49846 fbt kernel ufs_setacl return
...可以看到很多 DTrace 相關的 probe,可以用 dtrac -l 得到,從左到右邊可以看到的欄位是
- ID: 每個 probe 都有自己獨一無二的 ID
- PROVIDER: 這個 probe 的提供者,可能是
- fbt: function bound
- dtrace: dtrace 提供的
- syscall: syscall
- MODULE: 這是屬於哪個 moduler,像是可能是 kernel 的函式,freebsd32 等
- FUNCTION NAME: 最小的這個 probe 的名字
- entry/return/start/done …: 指定進入 funciton 或是離開的時候
DTrace Kernel Support
我們需要開啟一些選項,DTrace 預設在 FreeBDS GENERIC 核心有開啟。
參考 https://docs.freebsd.org/en/books/handbook/dtrace/#dtrace-out-of-kernel and https://wiki.freebsd.org/DTrace/KernelSupport。
基礎例子
請看 http://cozy-kola.medium.com/freebsd-dtrace-%E7%94%A8%E6%B3%95-445c97e684cb
基礎例子 2
請參考 The DTrace One-Liner Tutorial:
dtrace:::BEGIN 是一個特殊的函式,你可以用他來設定變數跟列印出標頭。
dtrace -n 'syscall::open*:entry { printf("%s %s", execname, copyinstr(arg0)); }' 這邊用到特殊的字串:
execname: DTrace built-in 變數,目前正在執行這個 syscall 的 process 名字arg0: 文件名字copyinstr(arg0): 把 user-space 的 C string 複製進 kernel space,可以讓我們列印出來
dtrace -n 'syscall:::entry { @[execname, probefunc] = count(); }' 用到:
probefunc: syscall 用到的名字@[...]: 聚合,計數字count(): 增加 1
dtrace -n 'syscall::read:entry { self->ts = timestamp; } syscall::read:return /self->ts/ {
@ = quantize(timestamp - self->ts); self->ts = 0; }'如上,用 self->ts 儲存現在時間,self-ts 是每個 thread 的 local 變數。
DTrace Script
並且 FreeBSD 提供很多現有的 DTrace script 來用,像是在 /usr/share/dtrace 還有 sysutils/dtrace-toolkit 套件 (套件上的不一定全部能用)。
同樣請看 http://cozy-kola.medium.com/freebsd-dtrace-%E7%94%A8%E6%B3%95-445c97e684cb
Kernel Module
我們也可以在 Kernel module 上面開啟 DTrace 來 debug module。你可以用 DTrace 追蹤載入模組的函式,像是自己寫的 MAC Module 裡面有一個 Utility function casper_deny_default 我可以用下面指令來追蹤。
kola@generic:~/proj/mac_casper/test/performance/macro/sockstat $ sudo dtrace -n 'fbt:casper_deny_default::return { printf("%s returned %d", probefunc, arg1); }'
dtrace: description 'fbt:mac_casper::return ' matched 133 probes或者指定回傳為特定值的追蹤:dtrace -n 'fbt:mac_casper::return /arg1 == 13/ { printf("%s() in %s returned EACCES (13)", probefunc, execname); }'