インテル® VTune™ プロファイラー・ユーザーガイド

ユーザー定義同期 API

インテル® VTune™ プロファイラーは、Windows* および POSIX* API のほとんどをサポートしますが、独自の同期構造を定義すると便利なことがあります。独自にビルドされた構造は、通常、インテル® VTune™ プロファイラーによって追跡されません。ただし、インテル® VTune™ プロファイラーでは、ユーザー定義の同期構造の統計情報を収集する同期 API が提供されます。

ユーザー定義同期 API は、再開状態で動作するスレッドごとの関数です。この関数はポーズ状態では動作しません。

同期構造は、一般に一連のシグナルとしてモデル化できます。1 つまたは複数のスレッドが、別のスレッドグループからのシグナルで、何らかのアクションを続行することがあります。スレッドがいつシグナルの待機を開始したか、そしていつシグナルが発生したかを追跡することで、同期 API はユーザー定義の同期オブジェクトを取得して、コードの理解に役立つ情報を提供することができます。API は、一連のプリミティブとメモリーハンドルを使用して、ユーザー定義の同期オブジェクトに関連する統計を収集します。

ユーザー定義同期 API は、スレッド化解析タイプと連携します。

コードでユーザー定義同期 API を使用

次の表は、Windows* または Linux* オペレーティング・システムで利用可能なユーザー定義の同期 API プリミティブについて説明します。

使用するプリミティブ

説明

void __itt_sync_create (void *addr, const __itt_char *objtype, const __itt_char *objname, int attribute)

char または Unicode* 文字列を使用する同期オブジェクトの作成を登録します。

void __itt_sync_rename (void *addr, const __itt_char *name)

作成後、char または Unicode* 文字列を使用して同期オブジェクトに名前を割り当てます。

void __itt_sync_destroy (void *addr)

破棄されたオブジェクトのライフタイムを追跡します。

· void __itt_sync_prepare (void *addr)

ユーザー定義同期オブジェクトでスピンループに入ります。

void __itt_sync_cancel (void *addr)

スピン・オブジェクトを取得せずにスピンループを出ます。

void __itt_sync_acquired (void *addr)

スピンループの正常終了を定義します (同期オブジェクトの取得)。

void __itt_sync_releasing (void *addr)

同期オブジェクトを解放するコードを開始します。このプリミティブは、ロック解放呼び出しの前に呼び出されます。

各 API は単一の引数、アドレス (addr) を持ちます。値ではなくアドレスを指定して、2 つ以上の異なるカスタム同期オブジェクトを区別します。インテル® VTune™ プロファイラーは、アドレスごとに個別のカスタム・オブジェクトを追跡できます。そのため、同じカスタム・オブジェクトで異なるコード領域へのアクセスを保護するには、同じ addr パラメーターを使用します。

コードに正しく埋め込まれていると、プリミティブはコードの同期タイプをインテル® VTune™ プロファイラーに通知します。各 prepare プリミティブは、キャンセル・プリミティブまたは取得プリミティブとペアで使用する必要があります。

ユーザー定義同期構造には任意の数の同期オブジェクトを含めることができます。同期オブジェクトは、ユーザー定義同期 API がオブジェクトの追跡に使用する固有のメモリーハンドルから起動する必要があります。オブジェクトが一意のメモリーポインターを使用する限り、ユーザー定義同期 API を使用して、同時に複数の同期オブジェクトを追跡できます。これは、Windows* API の WaitForMultipleObjects 関数に似たモデル・オブジェクトであると考えることができます。同期オブジェクトのグループから、さらに複雑な同期構造を作成できます。ただし、誤った動作を引き起こす可能性があるため、異なるユーザー定義同期構造をインターレースすることは推奨できません。

API 使用のヒント

ユーザー定義同期 API は、コード内に適切に配置する必要があります。ユーザー定義同期 API を適切に使用するには次のガイドラインに従ってください。

使用例: ユーザー定義スピン待機

prepare API は、現在のスレッドがメモリー位置のシグナルを待機していることをインテル® VTune™ プロファイラーに通知します。この呼び出しは、ユーザー同期構造を呼び出す前に行わなければなりません。prepare API は、acquired または cancel API 呼び出しとペアである必要があります。

次のコード例は、ユーザー定義のスピン待機構造と組み合わせて prepare および acquired API を使用する方法を示します。

long spin = 1;
. . ..
....
__itt_sync_prepare((void *) &spin );
while(ResourceBusy);
// スピン待機
__itt_sync_acquired((void *) &spin );

cancel API は、スレッドが同期構造をテストし、別のスレッドからのシグナルを待機する間に、他のワークを実行するなどのシナリオに適用できます。次のコード例を参照してください。

long spin = 1;
....
....
__itt_sync_prepare((void *) &spin );
while(ResourceBusy)
{
    __itt_sync_cancel((void *) &spin );
    
    //
    // ワークを記述
    //
    .....
    .....
    //
//  ワークが完了すると、この構造はロック変数をテストし取得を試みます
//  これを行う前に、prepare API を呼び出す必要があります。
    //
    __itt_sync_prepare((void *) &spin );
}
__itt_sync_acquired((void *) &spin);

ロックを取得した後、スレッドはロックを解放する前に解放 API を呼び出す必要があります。次の例は、リリース API の使用方法を示します。

long spin = 1;
....
....
__itt_sync_releasing((void *) &spin );
// コードはここでリソースを解放する必要があります

使用例: ユーザー定義同期クリティカル・セクション

次のコード例は、ユーザー定義同期 API を使用して追跡可能なクリティカル・セクションを作成する方法を示します。

CSEnter()
{
  __itt_sync_prepare((void*) &cs);
  while(LockIsUsed)
  {
    if(LockIsFree)
    {
    // 実際にロックを取得するコードを記述
    __itt_sync_acquired((void*) &cs);
    }
    if(timeout)
    {
    __itt_sync_cancel((void*) &cs );
    }
  }
}
CSLeave()
{
if(LockIsMine)
    {
        __itt_sync_releasing((void*) &cs);
        // 実際にロックを解放するコードを記述
    }
}

このクリティカル・セクションの例は、ユーザー定義同期プリミティブを作成します。次のことに注意して例を参照してください。

使用例: ユーザーレベル同期バリア

バリアなど上位レベルの構造も同期 API を使用して容易にモデル化できます。次のコード例は同期 API を使用して追跡されるバリア構造を作成する方法を示します。

Barrier()
{
    teamflag = false;
    __itt_sync_releasing((void *) &counter);
    InterlockedIncrement(&counter);  // OS とコンパイラーに適したアトミック・インクリメントを使用

    if( counter == thread count )
    {
        __itt_sync_acquired((void *) &counter);
        __itt_sync_releasing((void *) &teamflag);
        teamflag = true;
        counter = 0;
    }
    else
    {
        __ itt_sync_prepare((void *) &teamflag);
        Wait for team flag
        __ itt_sync_acquired((void *) &teamflag);
    }
}

次のことに注意して例を参照してください。

関連情報