XRay フライトデータレコーダトレースフォーマット¶
- バージョン:
2017-07-20 時点で 1
はじめに¶
XRay トレースをフライトデータレコーダーモードで収集する場合、アプリケーションの各スレッドはトレースデータで満たすバッファを要求し、ある時点で確定され、フラッシュされます。
プロファイラの目標はオーバーヘッドを最小限に抑えることであり、フラッシュされたデータはバッファに直接対応します。
このドキュメントでは、トレースファイルのフォーマットについて説明します。
概要¶
各トレースファイルは、特定のスレッドにおける一連のイベントに対応します。
ファイルには、ヘッダーの後に、区別されたレコードタイプのシーケンスが続きます。
バイトフィールドのエンディアンは、トレースファイルを生成したプラットフォームのエンディアンと一致します。
ヘッダーセクション¶
トレースファイルは 32 バイトのヘッダーで始まります。
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
version |
|
4 |
バージョン化されたリーダーを想定しています。このドキュメントでは、version == 1 の場合のフォーマットについて説明します。 |
|
type |
4 |
|
トレースのタイプをエンコードする列挙型。フライトデータレコーダーモードのトレースは type == 1 です。 |
bitfield |
|
4 |
バイトにアラインされていないパラメータを保持します。以下で詳しく説明します。 |
|
cycle_frequency |
8 |
|
イベントの期間をティックで測定するために使用される CPU オシレータの周波数 (ヘルツ)。 |
buffer_size
フィールド |
8 |
説明 |
---|---|---|
ヘッダーに続くトレースのデータ部分のサイズ (バイト)。 |
|
reserved |
8 |
|
将来の使用のために予約されています。 |
8 |
|
ファイルヘッダーの bitfield パラメータは、以下のフィールドで構成されています。 |
サイズ (ビット)
説明
constant_tsc
1
イベント間のティックを記録するために使用されるプラットフォームのタイムスタンプカウンターが、CPU 周波数の変化にもかかわらず一定の周波数でティックするかどうか。 0 == 非定数。 1 == 定数。
nonstop_tsc
1
CPU が低電力状態にあるかどうかにかかわらず、tsc がカウントを続けるかどうか。 0 == 停止。 1 == 継続。
(残り30ビット)
意味がありません。
フィールド |
8 |
説明 |
---|---|---|
トレースのヘッダーに続いて、ヘッダーの buffer_size フィールドと一致するサイズのデータセクションがあります。 |
|
データセクションは、異なるタイプの要素のストリームです。 |
シーケンスには、いくつかのカテゴリのデータがあります。 |
|
|
|
|
|
|
|
メモリフォーマットのリーダーは、ステートマシンを維持する必要があります。フォーマットはアラインメントのためのパディングを行わず、シークできません。 |
関数レコードは 8 バイトのレイアウトです。このレイアウトは、計装された関数のコールスタックとその期間を再構築するための情報をエンコードします.
フィールド
サイズ (ビット) |
説明 |
説明 |
---|---|---|
discriminant |
|
1 |
リーダーが関数レコードまたはメタデータレコードを読み取る必要があるかどうかを示します。関数レコードの場合は |
|
action |
3 |
|
関数が開始されているか、終了されているか、最適化によって生成された非標準のエントリまたは終了かを示します。 |
function_id |
|
28 |
関数の数値 ID。xray 計装マップを介して名前に解決されます。計装マップは、コンパイル時に xray によってオブジェクトファイルに構築され、関数 ID をアドレスにペアリングします。パッチ用およびバイナリシンボルを検索して名前を取得するためのルックアップとして使用されます。
tsc_delta
32
前回のレコードがデルタまたはその他の TSC リセットイベントを記録してからのタイムスタンプカウンターのティック数。
リトルエンディアンマシンでは、ビットフィールドは最下位ビットから最上位ビットの順に並べられます。リーダーは 8 ビット値を読み取り、判別子にマスク 0x01
を適用できます。同様に、32 ビットを読み取り、0x04
だけ右に符号なしシフトして function_id フィールドを取得できます。
フィールド |
ビッグエンディアンマシンでは、ビットフィールドは最上位ビットから最下位ビットの順に書き込まれます。リーダーは 8 ビット値を読み取り、判別子の 7 ビットだけ右に符号なしシフトします。 function_id フィールドは、32 ビット値を読み取り、マスク |
説明 |
---|---|---|
トレースのヘッダーに続いて、ヘッダーの buffer_size フィールドと一致するサイズのデータセクションがあります。 |
|
タイプ |
番号 |
|
Entry |
0 |
|
Exit |
1
説明 |
サイズ (ビット) |
---|---|
0 |
典型的な関数終了。 |
1 |
Tail_Exit |
2 |
2 |
3 |
末尾呼び出しの最適化による関数の終了。 |
4 |
Entry_Args |
5 |
4 |
6 |
引数を記録する関数エントリ |
Entry_Args レコードには、引数自体は含まれていません。代わりに、ログに記録された各引数のメタデータレコードが、ストリーム内の関数レコードの後に続きます.
バッファ全体に 16 バイトのメタデータレコードが散在しています。通常、計装されたバイナリの場合、関数レコードよりもまばらになり、バイナリ実行状態の全体像を提供します.
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
メタデータレコードのレイアウトはレコードに部分的に依存しますが、共通の構造を共有しています. |
|
関数レコードについて説明したのと同じビットフィールドルールが、MetadataRecords の最初のバイトに適用されます。このバイト内では、リトルエンディアンマシンは lsb から msb の順序を使用し、ビッグエンディアンマシンは msb から lsb の順序を使用します. |
8 |
|
フィールド |
サイズ
説明
バッファ全体に 16 バイトのメタデータレコードが散在しています。通常、計装されたバイナリの場合、関数レコードよりもまばらになり、バイナリ実行状態の全体像を提供します.
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
discriminant |
|
1 bit |
リーダーが関数レコードまたはメタデータレコードを読み取る必要があるかどうかを示します。メタデータレコードの場合は |
|
record_kind |
8 |
|
フィールド |
7 bits
メタデータレコードのタイプ。
data
バッファ全体に 16 バイトのメタデータレコードが散在しています。通常、計装されたバイナリの場合、関数レコードよりもまばらになり、バイナリ実行状態の全体像を提供します.
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
15 bytes |
|
レコードタイプごとに異なる方法で使用されるデータフィールド。 |
列挙型レコードの種類の表を次に示します。 |
|
種類 |
8 |
|
フィールド |
番号
NewBuffer
0
バッファ全体に 16 バイトのメタデータレコードが散在しています。通常、計装されたバイナリの場合、関数レコードよりもまばらになり、バイナリ実行状態の全体像を提供します.
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
列挙型レコードの種類の表を次に示します。 |
|
EndOfBuffer |
8 |
|
フィールド |
1
NewCPUId
2
TSCWrap
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
3 |
|
WallTimeMarker |
8 |
|
フィールド |
4
XRayは、カスタムイベントをログに記録する機能を提供します。これは、RPCのトレース情報や、アプリケーション固有の同様のトレースデータを記録するために活用できます。
カスタムイベント自体は、バッファ内で任意のサイズを持つ、構造化されていない(アプリケーション定義の)メモリセグメントです。それらの前には、CustomEventMarkerが存在とサイズを示します。
CustomEventMarkerデータセグメント
フィールド |
サイズ (バイト) |
説明 |
---|---|---|
event_size |
|
先行するイベントのサイズ。 |
列挙型レコードの種類の表を次に示します。 |
|
イベントのタイムスタンプカウンター。 |
8 |
|
フィールド |
バッファの終わりレコード¶
バッファの終わりレコードタイプは、このバッファにトレースデータがこれ以上ないことを示します。リーダーは、バッファの開始前に示された残りの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を記録します。つまり、末尾呼び出しの最適化が使用されなかった場合、呼び出しスタックからポップされる最後の関数です。
インストルメンテーションの対象としてマークされているすべての関数が、必ずしもトレースにあるとは限りません。トレーサーは、重要でない関数のトレースを保持するためにヒューリスティックを使用します。
すべてのエントリに、トレースされたExitまたはTail Exitがある必要はありません。バッファの容量が不足したり、インストルメント化された関数が終了する前に、プログラムがトレーサーにバッファを返すためのファイナライズを要求する可能性があります。