ユーザー定義の同期 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 プリミティブは、cancel プリミティブまたは acquired プリミティブとペアにする必要があります。

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

API 使用のヒント

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

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

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

次のコード例は、ユーザー定義のスピン待機構造と組み合わせて使用される準備および取得 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);

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

long spin = 1; 
. . . . . . . . 
__itt_sync_prepare((void *) &spin ); 
while(ResourceBusy); // スピンウェイト; 
__itt_sync_acquired((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); 
        // teamflag を待機 
        __ itt_sync_acquired((void *) &teamflag); 
    } 
}

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

関連情報