目錄

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); }'

Reference