この記事は、インテル® デベロッパー・ゾーンに公開されている「Intel® VTune™ Profiler Performance Analysis Cookbook」の「Custom Data Collection for Performance Analysis」の日本語参考訳です。原文は更新される可能性があります。原文と翻訳文の内容が異なる場合は原文を優先してください。
インテル® VTune™ プロファイラーの解析にカスタムデータを挿入するため、データコレクターを設定する方法を説明します。収集データに関する追加のコンテキストと情報を取得して、解析を強化します。
インテル® VTune™ プロファイラーでパフォーマンス・データを収集する場合、収集データと対話するようにカスタム・データ・コレクターを設定し、収集が完了したらカスタムデータを挿入できます。
このレシピでは、この方法を紹介します。
コンテンツ・エキスパート: Jeffrey Reinemann
使用するもの
以下は、このパフォーマンス解析シナリオで使用するハードウェアとソフトウェアのリストです。
アプリケーション:
- Mandelbrot: ここでは、このサンプル・アプリケーションを使用しますが、任意のアプリケーションを使用できます。
- CustomCollector (英語): このバッチファイルをカスタム・データ・コレクターとして使用しますが、任意のコンパイル済みプログラムや Python* スクリプトを使用できます。
解析ツール: インテル® VTune™ プロファイラー 2023.0 以降の hotspots 解析
データコレクターを理解する
CustomCollector データ・コレクター・バッチ・ファイルには、以下のコードが含まれます。
@Echo Off Echo %AMPLXE_COLLECT_CMD% if "%AMPLXE_COLLECT_CMD%" == "start" goto start if "%AMPLXE_COLLECT_CMD%" == "stop" goto stop Echo Invalid command Exit 1 :start Rem Start command in non-blocking mode Rem echo start my_collector_command_to_start_collection "%AMPLXE_DATA_DIR%"\data_file-hostname-%COMPUTERNAME%.csv Start C:\Source\CustomCollectorWin\Debug\CustomCollectorWin.exe Start C:\Source\CustomCollectorWin\Debug\CustomCollectorWin.exe 2 Start C:\Source\CustomCollectorWin\Debug\CustomCollectorWin.exe 4 Exit 0 :stop Echo stop "%AMPLXE_DATA_DIR%\..\log\CustomCollector0PID.txt" Echo|set /p="taskkill /PID " > "%TEMP%\stop0.bat type "%AMPLXE_DATA_DIR%\..\log\CustomCollector0PID.txt" >> "%TEMP%"\stop0.bat Call "%TEMP%"\stop0.bat Exit 0 Echo stop "%AMPLXE_DATA_DIR%\..\log\CustomCollector2PID.txt" Echo|set /p="taskkill /PID " > "%TEMP%\stop2.bat type "%AMPLXE_DATA_DIR%\..\log\CustomCollector2PID.txt" >> "%TEMP%"\stop2.bat Call "%TEMP%"\stop2.bat Echo stop "%AMPLXE_DATA_DIR%\..\log\CustomCollector4PID.txt" Echo|set /p="taskkill /PID " > "%TEMP%\stop4.bat type "%AMPLXE_DATA_DIR%\..\log\CustomCollector4PID.txt" >> "%TEMP%"\stop4.bat Call "%TEMP%"\stop4.bat Exit 0
コレクターは、収集の開始、停止、一時停止、再開を指示する収集コマンド引数 AMPLXE_COLLECT_CMD など、いくつかの環境変数を使用できますが、このバッチファイルは開始と停止のみ使用します。
その他の環境変数には、解析結果に統合されるカスタムデータを書き込むデータ・ディレクトリー・パス名 (AMPLXE_DATA_DIR) などがあります。
CustomCollector バッチファイルを実行すると、カスタム・データ・コレクターの複数のインスタンスが実行され、さまざまなメトリックが収集されます。各インスタンスは 2 つのカスタムデータ変数を提供し、3 つのインスタンスから合計 6 つの変数が提供されます。
hotspots 解析の実行
インテル® VTune™ プロファイラーを起動します。
[Configure Analysis (解析の設定)] ボタンをクリックして、新しい解析を設定します。
次のフィールドを設定します。
- [WHERE (どこを)] ペインでは、[Local Host (ローカルホスト)] ターゲット・システム・タイプを選択します。
- [HOW (どのように)] ペインでは、解析ツリーの [Algorithm (アルゴリズム)] グループから [Hotspots Analysis (hotspots 解析)] を選択します。
- [WHAT (何を)] ペインでは、アプリケーション、プロセス ID、またはシステム全体の収集を選択します。この例では、Mandelbrot アプリケーションを使用します。
- [WHAT (何を)] ペインで [Advanced Options (詳細オプション)] セクションを開き、[Custom Collector (カスタムコレクター)] テキストボックスで CustomCollector バッチファイルを指定します。
[Command Line (コマンドライン)] ボタン をクリックして、コマンドラインから解析を実行します。
データ収集が開始すると、4 つの出力ウィンドウが表示されます。
1 つは Mandelbrot アプリケーション用です。
残りの 3 つは CustomCollector データコレクター用です。
データ収集が完了すると、インテル® VTune™ プロファイラーは AMPLXE_COLLECT_CMD の停止コマンドとカスタム・データ・コレクターを呼び出します。コレクターは、カスタムデータを AMPLXE_DATA_DIR のインテル® VTune™ プロファイラーの結果ディレクトリーに書き込みます。
インテル® VTune™ プロファイラーは、収集のファイナライズ時にカスタムデータを結果に統合します。
結果が表示されたら、[Bottom-up (ボトムアップ)] タブに切り替えて、タイムライン表示でカスタムデータを確認します。この例では、以下のことが分かります。
カスタム・データ・ファイルの使用
次に、解析中に作成されたカスタム・データ・ファイルを調べてみましょう。
インテル® VTune™ プロファイラーの結果が含まれるフォルダーを開きます。3 つのカスタム・データ・ファイルがすべて含まれているデータ・サブフォルダーを確認します。
カスタム・データ・ファイルの命名規則は次のとおりです。
<ユーザー定義の文字列>-hostname-<テスト対象システムのホスト名>.csv
例:
MyData-hostname-<テスト対象システムのホスト名>.csv
カスタム・データ・ファイルを理解する
カスタム・データ・ファイルのヘッダーは、キャプチャーしたメトリックの名前と対応するデータ型を示します。例えば、以下のカスタム・データ・ファイルのヘッダーは、カウンター 0 が 瞬間値 (Instant Value) であり、カウンター 1 が 累積値 (Counter Rate) であることを示しています。
カスタムファイルの各データ行の先頭は、その時点で収集されたほかのデータと対応付けるため、タイムスタンプでなければなりません。
以下の例では、カスタム・データ・ファイルのさまざまな使い方を説明します。
- タイムスタンプの生成
- 離散データ型情報の書き込み
- パス名のフォーマット
- 既存のカスタムデータの追加
- カスタム間隔データの表示
タイムスタンプの生成
この例では、time と GetSystemTime を呼び出して、データの各行にタイムスタンプを生成します。
#define UTC_FORMAT "%Y-%m-%d %H:%M:%S" char* get_utc_time() { SYSTEMTIME system_time; static time_t previous_local_time; time_t local_time; struct tm gm_time; int millisec; char *time_fmt = NULL; time(&local_time); GetSystemTime(&system_time); millisec = system_time.wMilliseconds; if ((millisec == 0) && (local_time == previous_local_time)) local_time++; // missed second rollover gmtime_s(&gm_time, &local_time); previous_local_time = local_time; time_fmt = (char *) malloc(128); if (time_fmt) { strftime(time_fmt, 128, UTC_FORMAT, &gm_time); sprintf_s(time_fmt, 128, "%s.%03d", time_fmt, millisec); } return time_fmt; } // get_utc_time
離散データ型情報の書き込み
この例では、離散データ型の瞬間値と累積値をカスタム・データ・ファイルに書き込みます。
// Discrete data format: tsc.[QPC|CLOCK_MONOTONIC_RAW|RDTSC|UTC],CounterName1.COUNT|INST[,CounterName2.COUNT|INST],[pid],[tid] #define DISCRETE_FORMAT_1 "%s,%llu,%llu,,\n" #define DISCRETE_FORMAT_2 "%s,%llu,%llu,%lu,\n" #define DISCRETE_HEADER "tsc.UTC,Counter%c.COUNT,Counter%c.COUNT,pid,tid\n" void write_discrete_data(FILE *file_out, char *buffer, uint64_t tsc, uint64_t counter1, uint64_t counter2, DWORD dPid, DWORD dTid) { char *utc_time = get_utc_time(); size_t bytes_written = 0; if (buffer && file_out && utc_time) { // buffer and file_out valid if ((dPid == 0) && (dTid == 0)) sprintf_s(buffer, BUFFER_SIZE, DISCRETE_FORMAT_1, utc_time, counter1, counter2); else sprintf_s(buffer, BUFFER_SIZE, DISCRETE_FORMAT_2, utc_time, counter1, counter2, dPid); bytes_written = fwrite(buffer, strlen(buffer), 1, file_out); fflush(file_out); } if (utc_time) free(utc_time); } // write_discrete_data
パス名のフォーマット
この例では、インテル® VTune™ プロファイラーの環境変数を使用して、カスタム・データ・ファイル (収集インスタンス用に作成される) のフルパス名をフォーマットします。
if (command) _dupenv_s(&command, &length, "AMPLXE_COLLECT_CMD"); length = BUFFER_SIZE; if (datadir) _dupenv_s(&datadir, &length, "AMPLXE_DATA_DIR"); if (filename && hostname) { // filename and hostname valid length = BUFFER_SIZE; _dupenv_s(&hostname, &length, "COMPUTERNAME"); // log my process id so CustomCollector.bat can stop me sprintf_s(filename, BUFFER_SIZE, "%s\\..\\log\\CustomCollector%cPId.txt", datadir, instance_id); printf("Data file: %s\n", filename); fopen_s(&file_out, filename, "wb"); if (file_out) { // file_out valid sprintf_s(buffer, BUFFER_SIZE, "%u", my_pid); fwrite(buffer, strlen(buffer), 1, file_out); fclose(file_out); file_out = NULL; } // Note: appending .amr.corp.intel.com is unique to my test environment sprintf_s(filename, BUFFER_SIZE, "%s\\MyData%c-hostname-%s.amr.corp.intel.com.csv", datadir, instance_id, hostname); std::cout << filename << std::endl; errnum = fopen_s(&file_out, filename, "wb");
既存のカスタムデータの追加
インテル® VTune™ プロファイラーのカスタム・コレクター・インターフェイスから独立して実行するカスタム・データ・コレクターがある場合、このデータを解析結果に含めるには、インテル® VTune™ プロファイラーの解析の実行中に独立したカスタム・データ・コレクターを実行する必要があります。インテル® VTune™ プロファイラーは、実行時間範囲内のタイムスタンプを持つデータのみを含めます。
また、独立したデータコレクターのカスタム・データ・ファイルが、前述のファイル名の命名規則と書式規則を順守していることを確認する必要があります。
例えば、このカスタム・データ・ファイルは、カウンター 6 とカウンター 7 を結果に追加します。
新しいカスタム・データ・ファイルをインテル® VTune™ プロファイラーの結果 data サブディレクトリーにコピーして、以下の操作を行います。
- インテル® VTune™ プロファイラーの GUI で [Collection Log (収集ログ)] タブを開きます。
- [Re-resolve (再解決)] ボタン () をクリックして、再度データをファイナライズします。これにより、インテル® VTune™ プロファイラーの収集時間範囲内のタイムスタンプを持つ新しいカスタム・データ・ファイルが含まれます。
- ファイナライズが完了したら、[Bottom-up (ボトムアップ)] タブに切り替えて、データ内にカウンター 6 とカウンター 7 が表示されていることを確認します。
カスタム間隔データの表示
カスタム間隔データ (英語) を収集すると、結果のファイナライズ後、この情報がタイムラインの [Frame Rate (フレームレート)] に表示されます。
次の例では、MyInterval1 と MyInterval2 というカスタム間隔データがオーバーラップしています。以下のポップアップ・ウィンドウで、それぞれの間隔の開始時間を確認できます。タイムライン上にマウスをホバーすると、すべてのアクティブな間隔とその開始時間および継続時間が表示されます。
カスタム間隔データファイルは、前述の命名規則と書式規則に従わなければなりません。
- ファイル名は、<ユーザー定義文字列>-hostname-<テスト対象システムのホスト名>.csv という構造になっています。
- ヘッダーは、間隔の名前、開始時間、停止時間を示し、プログラム ID とスレッド ID を含めることもできます。
以下の例では、間隔データをカスタム・データ・ファイルに書き込む方法を示しています。
// You can mix multiple intervals in the data. Starting one interval stops the previous interval. // The format for the interval data is name,start_tsc.[QPC|CLOCK_MONOTONIC_RAW|RDTSC|UTC],end_tsc,[pid],[tid] #define INTERVAL_FORMAT "%s,%s,%s,,\n" #define INTERVAL_FORMAT_2 "%s,%s,%s,%lu,\n" #define INTERVAL_HEADER "name,start_tsc.UTC,end_tsc,pid,tid\n" void write_interval_data(FILE* file_out, char* buffer, const char* name, char *start_utc, char *end_utc, DWORD dPid, DWORD dTid) { size_t bytes_written = 0; if (buffer && file_out) { // buffer and file_out valid if ((dPid != 0) || (dTid != 0)) sprintf_s(buffer, BUFFER_SIZE, INTERVAL_FORMAT_2, name, start_utc, end_utc, dPid); else sprintf_s(buffer, BUFFER_SIZE, INTERVAL_FORMAT, name, start_utc, end_utc); bytes_written = fwrite(buffer, strlen(buffer), 1, file_out); fflush(file_out); if (bytes_written < 1) std::cout << "fwrite() failed\n"; } } // write_interval_data
関連情報
- 外部データのインポート (英語)
- 外部データの CSV ファイルの作成 (英語)
- custom-collector リファレンス情報 (英語)