XRay 飛行資料記錄器追蹤格式¶
- 版本:
1,截至 2017-07-20
簡介¶
當以飛行資料記錄器模式收集 XRay 追蹤資料時,應用程式的每個執行緒都會宣告緩衝區以填入追蹤資料,這些資料會在某個時間點完成並刷新。
分析器的目標是盡可能減少開銷,刷新後的資料直接對應到緩衝區。
本文檔描述追蹤檔案的格式。
概要¶
每個追蹤檔案都對應於特定執行緒中的一系列事件。
檔案包含一個標頭,後跟一系列可區分的記錄類型。
位元組欄位的位元組順序與產生追蹤檔案的平台的位元組順序相符。
標頭區段¶
追蹤檔案以 32 位元組的標頭開始。
欄位 |
大小 (位元組) |
描述 |
---|---|---|
版本 |
|
預期會有版本化的讀取器。本文檔描述當版本 == 1 時的格式 |
類型 |
|
一個枚舉,編碼追蹤的類型。飛行資料記錄器模式追蹤的類型 == 1 |
位元欄位 |
|
保存未對齊位元組的參數。詳見下文。 |
cycle_frequency |
|
CPU 振盪器頻率,單位為赫茲,用於測量事件持續時間,單位為滴答。 |
buffer_size |
|
追蹤資料部分的大小,單位為位元組,緊隨標頭之後。 |
保留 |
|
保留供未來使用。 |
檔案標頭的位元欄位參數由以下欄位組成。
欄位 |
大小 (位元) |
描述 |
---|---|---|
constant_tsc |
|
平台的時間戳計數器是否以恆定頻率滴答,儘管 CPU 頻率發生變化。 0 == 非恆定。 1 == 恆定。 |
nonstop_tsc |
|
tsc 是否在 CPU 處於低功耗狀態時繼續計數。 0 == 停止。 1 == 非停止。 |
保留 |
|
無意義。 |
資料區段¶
在追蹤中的標頭之後是一個資料區段,其大小與標頭中的 buffer_size 欄位相符。
資料區段是不同類型元素的串流。
序列中有幾個類別的資料。
函式 記錄
:函式記錄包含進入和退出函式執行的時序。函式記錄各有 8 個位元組。元資料 記錄
:元資料記錄有多種用途。主要用於捕獲對於每個函式而言記錄成本可能過高,但又需要用於情境化細粒度時序的資訊。它們也用作使用者定義事件資料酬載的標記。元資料記錄各有 16 個位元組。事件 資料
:自由形式資料可能與二進制檔追蹤的事件相關聯,並編碼由處理函式定義的資料。事件資料始終以標記記錄開頭,該記錄指示其大小。函式 引數
:某些函式的引數包含在追蹤中。這些引數可以是指標位址或原始類型,它們被讀取並獨立於其在高階語言中的類型進行記錄。對於追蹤器而言,它們都是數字。具有附加引數的函式記錄將在其函式進入記錄上指示它們的存在。我們僅支援記錄從引數零開始的連續函式引數序列,這將是成員函式調用的 “this” 指標。例如,我們不支援記錄第一個和第三個引數。
記憶體格式的讀取器必須維護一個狀態機。該格式未嘗試為對齊進行填充,並且不可搜尋。
函式記錄¶
函式記錄具有 8 位元組的佈局。此佈局編碼資訊以重建儀器化函式的呼叫堆疊及其持續時間。
欄位 |
大小 (位元) |
描述 |
---|---|---|
discriminant |
|
指示讀取器應讀取函式記錄還是元資料記錄。對於函式記錄,設定為 |
action |
|
指定函式是正在進入、退出,還是由最佳化產生的非標準進入或退出。 |
function_id |
|
函式的數字 ID。透過 xray 儀器化地圖解析為名稱。儀器化地圖由 xray 在編譯時建置到物件檔案中,並將函式 ID 與位址配對。它用於修補,並作為查找二進制檔符號以獲取名稱的工具。 |
tsc_delta |
|
自上一個記錄記錄增量或其他 TSC 重置事件以來,時間戳計數器的滴答數。 |
在小端機器上,位元欄位的順序從最低有效位到最高有效位。讀取器可以讀取 8 位元值並應用遮罩 0x01
作為 discriminant。同樣地,它們可以讀取 32 位元並無符號右移 0x04
以獲取 function_id 欄位。
在大端機器上,位元欄位的寫入順序從最高有效位到最低有效位。讀取器將讀取 8 位元值並無符號右移 7 位元作為 discriminant。function_id 欄位可以透過讀取 32 位元值並應用遮罩 0x0FFFFFFF
來獲取。
函式動作類型如下。
類型 |
數字 |
描述 |
---|---|---|
進入 |
|
典型的函式進入。 |
退出 |
|
典型的函式退出。 |
Tail_Exit |
|
由於尾部呼叫最佳化而從函式退出。 |
Entry_Args |
|
記錄引數的函式進入。 |
Entry_Args 記錄不包含引數本身。相反,每個記錄的引數的元資料記錄都跟在串流中的函式記錄之後。
元資料記錄¶
在緩衝區中散佈著 16 位元組的元資料記錄。對於典型儀器化的二進制檔,它們將比函式記錄更稀疏,並且它們提供了二進制檔執行狀態的更完整圖片。
元資料記錄佈局部分取決於記錄,但它們共享一個通用結構。
為函式記錄描述的相同位元欄位規則適用於 MetadataRecords 的第一個位元組。在這個位元組中,小端機器使用 lsb 到 msb 排序,而大端機器使用 msb 到 lsb 排序。
欄位 |
大小 |
描述 |
---|---|---|
discriminant |
|
指示讀取器應讀取函式記錄還是元資料記錄。對於元資料記錄,設定為 |
record_kind |
|
元資料記錄的類型。 |
data |
|
一個資料欄位,用於每種記錄類型的方式不同。 |
以下是列舉的記錄類型表。
數字 |
類型 |
---|---|
0 |
NewBuffer |
1 |
EndOfBuffer |
2 |
NewCPUId |
3 |
TSCWrap |
4 |
WallTimeMarker |
5 |
CustomEventMarker |
6 |
CallArgument |
NewBuffer 記錄¶
每個緩衝區都以緊隨標頭之後的 NewBuffer 記錄開始。它記錄追蹤所屬的執行緒 ID。
其資料區段如下。
欄位 |
大小 (位元組) |
描述 |
---|---|---|
thread_Id |
|
緩衝區的執行緒 ID。 |
保留 |
|
未使用。 |
WallClockTime 記錄¶
在 NewBuffer 記錄之後,每個緩衝區都會記錄一個絕對時間,作為時間戳計數器增量記錄的持續時間的參考框架。
其資料區段如下。
欄位 |
大小 (位元組) |
描述 |
---|---|---|
seconds |
|
絕對時間刻度上的秒數。起點未指定,取決於追蹤器配置的實作和平台。 |
microseconds |
|
時間的微秒部分。 |
保留 |
|
未使用。 |
NewCpuId 記錄¶
每個函式進入都會調用一個例程來確定哪個 CPU 正在執行。通常,這是透過 readtscp 完成的,它同時讀取時間戳計數器。
如果追蹤檢測到執行已切換 CPU,或者如果這是第一個儀器化進入點,則追蹤器將輸出 NewCpuId 記錄。
其資料區段如下。
欄位 |
大小 (位元組) |
描述 |
---|---|---|
cpu_id |
|
CPU ID。 |
absolute_tsc |
|
時間戳計數器的絕對值。 |
保留 |
|
未使用。 |
TSCWrap 記錄¶
由於每個函式記錄都使用 32 位元值來表示自上次參考以來時間戳計數器的滴答數,因此此值可能會溢位,尤其是對於稀疏儀器化的二進制檔。
當此增量不適合 32 位元表示時,會以 TSCWrap 記錄的形式寫入參考絕對時間戳計數器記錄。
其資料區段如下。
欄位 |
大小 (位元組) |
描述 |
---|---|---|
absolute_tsc |
|
時間戳計數器值。 |
保留 |
|
未使用。 |
CallArgument 記錄¶
緊隨 Entry_Args 類型函式記錄之後,可能有一個或多個 CallArgument 記錄,其中包含追蹤函式的參數值。
CallArgument 記錄序列的順序與函式參數的順序一一對應。
CallArgument 資料區段
欄位 |
大小 (位元組) |
描述 |
---|---|---|
argument |
|
數字引數 (可能是指標位址)。 |
保留 |
|
未使用。 |
CustomEventMarker 記錄¶
XRay 提供了記錄自定義事件的功能。這可以用於記錄 RPC 的追蹤資訊或類似地追蹤特定於應用程式的資料。
自定義事件本身是記憶體的一個非結構化 (應用程式定義的) 區段,其大小在緩衝區內是任意的。它們前面有 CustomEventMarkers 以指示它們的存在和大小。
CustomEventMarker 資料區段
欄位 |
大小 (位元組) |
描述 |
---|---|---|
event_size |
|
前導事件的大小。 |
absolute_tsc |
|
事件的時間戳計數器。 |
保留 |
|
未使用。 |
EndOfBuffer 記錄¶
EndOfBuffer 記錄類型指示此緩衝區中沒有更多追蹤資料。讀取器應尋找超出緩衝區開始之前表示的剩餘 buffer_size,並尋找另一個標頭或 EOF。
格式文法與不變性¶
並非所有元資料記錄和函式記錄的序列都是有效資料。序列應解析為狀態機。有效格式的期望可以表示為上下文無關文法。
這是嘗試以 EBNF 格式的語句解釋格式。
Format := Header ThreadBuffer* EOF
ThreadBuffer := NewBuffer WallClockTime NewCPUId BodySequence* End
BodySequence := NewCPUId | TSCWrap | Function | CustomEvent
Function := (Function_Entry_Args CallArgument*) | Function_Other_Type
CustomEvent := CustomEventMarker CustomEventUnstructuredMemory
End := EndOfBuffer RemainingBufferSizeToSkip
函式記錄順序¶
有一些澄清可能有助於理解對函式記錄的期望。
具有 Exit 的函式預期在追蹤中在其前面有一個對應的 Entry 或 Entry_Args 函式記錄。
Tail_Exit 函式記錄記錄程式計數器將採取的返回位址的函式 ID。換句話說,如果未使用尾部呼叫最佳化,則將從呼叫堆疊中彈出的最終函式。
並非所有標記為儀器化的函式都一定在追蹤中。追蹤器使用啟發式方法來保留非平凡函式的追蹤。
並非每個進入都必須具有追蹤的退出或尾部退出。緩衝區可能耗盡空間,或者程式可能會請求追蹤器在儀器化函式退出之前完成以返回緩衝區。