インストルメントとトレーステクノロジー API (ITT API) とジャストインタイム・プロファイル API (JIT API) は、オープンソースのコンポーネントです。GitHub* リポジトリーでソースコードにアクセスし、貢献することもできます。
JIT (ジャストインタイム) プロファイル API は、実行時にコンパイルされるコードからパフォーマンス・ツールに有用な情報をレポートします。これを行うには、JIT コンパイル済みのコード実行する前に、情報を報告するため JIT プロファイル API 呼び出しをコード・ジェネレーターに挿入する必要があります。この情報は実行時に収集され、インテル® VTune™ プロファイラーなどのツールが JIT コンパイルコードに関連するパフォーマンス・メトリックを表示するために使用されます。
JIT プロファイル API を使用して、JavaScript* コードのトレースの動的 JIT コンパイル、OpenCL* アプリケーションでの JIT 実行、Java*/.NET マネージド実行環境、およびカスタム ISV JIT エンジンなどの環境をプロファイルできます。
標準のインテル® VTune™ プロファイラーのインストールには、静的コンポーネント (静的ライブラリーとソースファイル) とプロファイラー・オブジェクトが含まれています。実行時にコードを生成する JIT エンジンは、静的コンポーネントを介してプロファイラー・オブジェクトと通信します。実行時に JIT エンジンはプロファイラー・オブジェクトによってトレースファイルに格納された JIT コンパイル済みコードの情報をレポートします。収集が完了すると、インテル® VTune™ プロファイラーは生成されたトレースファイルを参照して JIT コンパイルされたコードを解決します。インテル® VTune™ プロファイラーがインストールされていない場合、プロファイルは無効化されます。
JIT プロファイル API を使用して以下を行います。
JIT プロファイルは、イベントベース・サンプリング向けの [アプリケーションを起動] ターゲットオプションでサポートされます。
JIT プロファイル API には 2 つの環境変数が含まれており、それぞれの環境変数には特定のランタイム・ライブラリーへのパスが含まれています。
これらの変数は、JIT API のスタブ実装をインテル® VTune™ プロファイラー JIT API コレクターに置き換えることを通知するために使用されます。JIT API を使用してコードをインストルメントし、それをインテル® VTune™ プロファイラー JIT API スタブ (libittnotify.lib/libittnotify.a) にリンクし環境変数が設定されると、コードはこれらの環境変数で定義されたライブラリをロードします。
ittnotify_collector がデータを収集できるように、これらの環境変数は必ず設定してください。 Windows*: INTEL_JIT_PROFILER32=<install-dir>\bin32\runtime\ittnotify_collector.dll INTEL_JIT_PROFILER64=<install-dir>\bin64\runtime\ittnotify_collector.dll Linux*: INTEL_JIT_PROFILER32=<install-dir>/lib32/runtime/libittnotify_collector.so INTEL_JIT_PROFILER64=<install-dir>/lib64/runtime/libittnotify_collector.so FreeBSD*: INTEL_JIT_PROFILER64=<target-package>/lib64/runtime/libittnotify_collector.so
これは、JIT プロファイル API を使用して、トレースベースおよびメソッドベースの JIT コンパイル済みコードをプロファイルする最も一般的なシナリオです。
#include <jitprofiling.h>
if (iJIT_IsProfilingActive() != iJIT_SAMPLING_ON) {
return;
}
iJIT_Method_Load jmethod = {0};
jmethod.method_id = iJIT_GetNewMethodID();
jmethod.method_name = "method_name";
jmethod.class_file_name = "class_name";
jmethod.source_file_name = "source_file_name";
jmethod.method_load_address = code_addr;
jmethod.method_size = code_size;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL);
使用法
すでにレポートされているメソッドに、iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED イベントが再度レポートされるとメソッドは無効化され、そのメモリー領域はアンロードされたものとして扱われます。インテル® VTune™ プロファイラーは、オーバーライトされるまでメソッドで収集されたメトリックを表示します。
同じアセンブリー命令 (コード位置) に対して複数のソース行を示す行番号情報がある場合、インテル® VTune™ プロファイラーは最初の行番号を適用します。
動的に生成されたコードにはモジュール名が関連付けられます。レポートを生成するには、コマンドラインで iJIT_Method_Load_V2 構造を使用します。
関数を同じメソッド ID で複数回登録する際に異なるモジュール名を指定すると、インテル® VTune™ プロファイラーは最初に登録されたモジュール名を選択します。異なる JIT エンジン間で同じ関数を区別したい場合、関数ごとに異なるメソッド ID を指定します。ほかのシンボル情報 (ソースファイルなど) は同一にすることができます。
JIT プロファイル API を使用して、時間経過においてコード領域が重複する可能性がある再 JIT (リソースが制限される環境では一般的) を含む、関数分割 (同一関数に属する複数の集合または素集合コード) を解析できます。
#include <jitprofiling.h>
unsigned int method_id = iJIT_GetNewMethodID();
iJIT_Method_Load a = {0};
a.method_id = method_id;
a.method_load_address = 0x100;
a.method_size = 0x20;
iJIT_Method_Load b = {0};
b.method_id = method_id;
b.method_load_address = 0x200;
b.method_size = 0x30;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&b);
使用法
もし、iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED イベントが再度レポートされるとメソッドは無効化され、そのメモリー領域はアンロードされたものとして扱われます。
同じメソッド ID でレポートされるすべてのコード領域は、同一のメソッドに属していると見なされます。シンボル情報 (メソッド名、ソースファイル名) は、最初に取得されたものが適用され、同じメソッド ID を持つ後続のすべての通知は同じ行番号のテーブル情報に対して処理されます。そのため、インテル® VTune™ プロファイラーは、最初のソースファイル名からファイル名を取得し、現在の通知の行番号テーブルを使用してサンプルをソース行に対応付けます。
異なるソースファイル名と同じメソッド ID で 2 番目のコード領域を登録すると、この情報は保存され、最初のコード領域の拡張子とは見なされずインテル® VTune™ プロファイラーは、最初のコード領域のソースファイルを使用するため、誤ったパフォーマンス・メトリックのマッピングが行われます。
2 番目のコード領域を最初の領域と同じソースファイルと同じメソッド ID で登録すると、そのソースファイルは破棄されますが、インテル® VTune™ プロファイラーはメトリックを適切にソースファイルにマッピングできます。
2 番目のコード領域を NULL ソースファイルと同じメソッド ID で登録すると、行番号情報は最初のコード領域のソースファイルに関連付けられます。
JIT プロファイル API を使用して、入れ子になったインラインメソッドの複数階層を含むインライン関数を調査して、パフォーマンス・メトリックの分布を表示できます。
#include <jitprofiling.h>
// method_id parent_id
// [-- c --] 3000 2000
// [---- d -----] 2001 1000
// [---- b ----] 2000 1000
// [------------ a ----------------] 1000 n/a
iJIT_Method_Load a = {0};
a.method_id = 1000;
iJIT_Method_Inline_Load b = {0};
b.method_id = 2000;
b.parent_method_id = 1000;
iJIT_Method_Inline_Load c = {0};
c.method_id = 3000;
c.parent_method_id = 2000;
iJIT_Method_Inline_Load d = {0};
d.method_id = 2001;
d.parent_method_id = 1000;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&b);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&c);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&d);
使用法
それぞれのインライン (iJIT_Method_Inline_Load) メソッドは、直結する親関数と自身の 2 つのメソッド ID と関連付ける必要があります。
同じ親メソッドのインラインメソッドのアドレス領域は、互いに重複できません。
親メソッドとインラインメソッドがレポートされるまで、親メソッドの実行は開始できません。
入れ子になったインラインメソッドでは、iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED イベントの順番はそれほど重要ではありません。
インラインメソッドまたは上位の親メソッドがオーバーライトされると、インラインメソッドを含む親は無効化され、そのメモリー領域はアンロードされたものとして扱われます。