パフォーマンス解析用のカスタムデータ収集

インテル® VTune™ プロファイラー

この記事は、インテル® デベロッパー・ゾーンに公開されている「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 解析の実行

  1. インテル® VTune™ プロファイラーを起動します。

  2. [Configure Analysis (解析の設定)] ボタンをクリックして、新しい解析を設定します。

  3. 次のフィールドを設定します。

    • [WHERE (どこを)] ペインでは、[Local Host (ローカルホスト)] ターゲット・システム・タイプを選択します。
    • [HOW (どのように)] ペインでは、解析ツリーの [Algorithm (アルゴリズム)] グループから [Hotspots Analysis (hotspots 解析)] を選択します。
    • [WHAT (何を)] ペインでは、アプリケーション、プロセス ID、またはシステム全体の収集を選択します。この例では、Mandelbrot アプリケーションを使用します。
    • [WHAT (何を)] ペインで [Advanced Options (詳細オプション)] セクションを開き、[Custom Collector (カスタムコレクター)] テキストボックスで CustomCollector バッチファイルを指定します。
  4. [Command Line (コマンドライン)] ボタン をクリックして、コマンドラインから解析を実行します。

データ収集が開始すると、4 つの出力ウィンドウが表示されます。

  • 1 つは Mandelbrot アプリケーション用です。

  • 残りの 3 つは CustomCollector データコレクター用です。

データ収集が完了すると、インテル® VTune™ プロファイラーは AMPLXE_COLLECT_CMD の停止コマンドとカスタム・データ・コレクターを呼び出します。コレクターは、カスタムデータを AMPLXE_DATA_DIR のインテル® VTune™ プロファイラーの結果ディレクトリーに書き込みます。

インテル® VTune™ プロファイラーは、収集のファイナライズ時にカスタムデータを結果に統合します。

結果が表示されたら、[Bottom-up (ボトムアップ)] タブに切り替えて、タイムライン表示でカスタムデータを確認します。この例では、以下のことが分かります。

  • カスタムデータ ・カウンター 0、2、4 は瞬間値として表示されています。
  • カスタム・データ・カウンター 1、3、5 は累積値として表示されています。

カスタム・データ・ファイルの使用

次に、解析中に作成されたカスタム・データ・ファイルを調べてみましょう。

インテル® VTune™ プロファイラーの結果が含まれるフォルダーを開きます。3 つのカスタム・データ・ファイルがすべて含まれているデータ・サブフォルダーを確認します。

カスタム・データ・ファイルの命名規則は次のとおりです。
<ユーザー定義の文字列>-hostname-<テスト対象システムのホスト名>.csv

例:
MyData-hostname-<テスト対象システムのホスト名>.csv

カスタム・データ・ファイルを理解する

カスタム・データ・ファイルのヘッダーは、キャプチャーしたメトリックの名前と対応するデータ型を示します。例えば、以下のカスタム・データ・ファイルのヘッダーは、カウンター 0 が 瞬間値 (Instant Value) であり、カウンター 1 が 累積値 (Counter Rate) であることを示しています。

カスタムファイルの各データ行の先頭は、その時点で収集されたほかのデータと対応付けるため、タイムスタンプでなければなりません。

以下の例では、カスタム・データ・ファイルのさまざまな使い方を説明します。

  • タイムスタンプの生成
  • 離散データ型情報の書き込み
  • パス名のフォーマット
  • 既存のカスタムデータの追加
  • カスタム間隔データの表示

タイムスタンプの生成

この例では、timeGetSystemTime を呼び出して、データの各行にタイムスタンプを生成します。

#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 サブディレクトリーにコピーして、以下の操作を行います。

  1. インテル® VTune™ プロファイラーの GUI で [Collection Log (収集ログ)] タブを開きます。
  2. [Re-resolve (再解決)] ボタン () をクリックして、再度データをファイナライズします。これにより、インテル® VTune™ プロファイラーの収集時間範囲内のタイムスタンプを持つ新しいカスタム・データ・ファイルが含まれます。
  3. ファイナライズが完了したら、[Bottom-up (ボトムアップ)] タブに切り替えて、データ内にカウンター 6 とカウンター 7 が表示されていることを確認します。

カスタム間隔データの表示

カスタム間隔データ (英語) を収集すると、結果のファイナライズ後、この情報がタイムラインの [Frame Rate (フレームレート)] に表示されます。

次の例では、MyInterval1MyInterval2 というカスタム間隔データがオーバーラップしています。以下のポップアップ・ウィンドウで、それぞれの間隔の開始時間を確認できます。タイムライン上にマウスをホバーすると、すべてのアクティブな間隔とその開始時間および継続時間が表示されます。

カスタム間隔データファイルは、前述の命名規則と書式規則に従わなければなりません。

  • ファイル名は、<ユーザー定義文字列>-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

関連情報

タイトルとURLをコピーしました