tracepoint(追蹤點)
kprobe 讓你追蹤任何核心函式,但它脆弱:它釘在一個內部函式上,而那函式的名稱與形狀可能每次發行都改變。tracepoint 是相反的交易。它是核心開發者「刻意」放進原始碼裡、位在一個有意義事件上的追蹤鉤子——「一個行程即將被排程」「一個封包被丟棄」「一次區塊 I/O 完成了」——並承諾維持它的穩定,帶有一組有文件記載的欄位,好讓工具能長期倚賴它。
具體來說,tracepoint 是一個具名、靜態的插樁點,在選定的那一行編進核心。當沒人在看時,它處於休眠、幾乎不花成本——它的實作方式使得一個未啟用的 tracepoint 基本上就是一個被預測會略過的分支,所以正常路徑上的負擔可忽略。當某個工具啟用它時,tracepoint 就活化,並在每次發生時,把一筆定義好的欄位紀錄(例如,對一個排程事件:前一個工作、下一個工作、以及它們的優先序)交給任何在聽的人——ftrace、perf、或一支 eBPF 程式。因為開發者替它命名、並承諾跨版本維持它的欄位穩定,所以針對 tracepoint 寫的腳本能在核心升級後繼續運作,這是 kprobe 做不到的。
它之所以重要,是因為它是可靠、可攜的核心可觀測性的基礎:最常被觀察的核心事件(排程、系統呼叫、區塊 I/O、網路)正是以 tracepoint 的形式暴露出來,好讓正式環境工具能依賴它們。相對於 kprobe 的取捨是「覆蓋面對穩定性」:tracepoint 只存在於開發者選擇加入的地方,所以對於一個沒有 tracepoint 的任意內部函式,你只好退回 kprobe 並接受它的脆弱。誠實的提醒:「穩定」是一個意圖的承諾,不是絕對保證——tracepoints 仍可能在核心演進時被改變或移除,只是遠不會像一個內部函式名那樣隨意。
# 掛上「穩定」的排程切換 tracepoint,統計每個工作的切換次數 $ bpftrace -e 'tracepoint:sched:sched_switch { @[args->prev_comm] = count(); }' # 欄位 args->prev_comm、args->next_comm 是這個 tracepoint 有文件記載、穩定契約的一部分
tracepoint 在一個有意義的核心事件上暴露具名、穩定的欄位,所以這段腳本能撐過核心升級,而以 kprobe 為基礎的可能撐不過。
把這對工具想成一份契約:tracepoint 是核心為觀察者維護的穩定、有文件介面,而 kprobe 伸進私有內部——有 tracepoint 時優先用它,只在沒有時才退回 kprobe。