PCW_CALLBACK コールバック関数 (wdm.h)

プロバイダーは、必要に応じて、インスタンスの列挙やカウンターセット データの収集などの要求をコンシューマーが行ったときに通知を受け取る関数を実装 PCW_CALLBACK できます。 パフォーマンス カウンター ライブラリ (PERFLIB バージョン 2.0) は、コンシューマーの要求をPCW_CALLBACK完了する前に 関数を呼び出します。

構文

PCW_CALLBACK PcwCallback;

NTSTATUS PcwCallback(
  [in]           PCW_CALLBACK_TYPE Type,
  [in]           PPCW_CALLBACK_INFORMATION Info,
  [in, optional] PVOID Context
)
{...}

パラメーター

[in] Type

コールバック 呼び出された理由を示すPCW_CALLBACK_TYPE列挙値。 指定できる値は、PcwCallbackAddCounterPcwCallbackRemoveCounterPcwCallbackEnumerateInstances、および PcwCallbackCollectData です。

[in] Info

プロバイダー コールバックが呼び出された理由の詳細を提供する、 PCW_CALLBACK_INFORMATION 共用体へのポインター。 詳細は、 パラメーターに対応するフィールドに格納 Type されます。 たとえば、その場合 Type == PcwCallbackEnumerateInstances 、詳細は になります Info->EnumerateInstances

[in, optional] Context

PcwRegister を呼び出すとき、または CTRPP によって生成された Register 関数 (PcwRegisterを呼び出す) を呼び出すときに、プロバイダーによって提供されたコールバック コンテキスト。

戻り値

コールバック関数はPCW_CALLBACK、コールバックがエラーなしで完了した場合は を返し、それ以外の場合はエラー コードをNTSTATUS返すSTATUS_SUCCESS必要があります。 このリターン コードは情報提供のみを目的としており、コールバックからエラーが返された場合でも、コンシューマーの要求の処理が続行されることに注意してください。

注釈

カウンターセット プロバイダーは、次の 2 つの異なるシステムを介してコンシューマーに情報を提供できます。

  • プロバイダーは、 と PcwCloseInstance を使用PcwCreateInstanceして、使用可能なインスタンスと対応するカウンター データの一覧を維持できます。 このシステムは簡単に実装できますが、柔軟性は限られています。 このシステムを使用する場合、プロバイダーはコールバック関数を指定する必要はありません。 このシステムの詳細については、 PcwCreateInstance のドキュメントを参照してください。

  • プロバイダーは、データを PCW_CALLBACK 収集するために必要に応じてパフォーマンス カウンター ライブラリによって呼び出される関数を提供できます。

コールバック実装はスレッド セーフである必要があります。 複数の異なるコンシューマーが、異なるスレッドでプロバイダーから同時にデータを要求する場合があります。

コールバックは、 と PcwCallbackCollectData 要求の型をPcwCallbackEnumerateInstances処理する必要があります。 通常、コールバックは他の要求の種類を処理する必要はありませんが、複雑なシナリオでは、コールバックがデータ収集を処理 PcwCallbackAddCounter して PcwCallbackRemoveCounter 最適化する場合もあります (つまり、アクティブなクエリがない場合に統計の追跡を無効にする場合)。

コールバックは、カウンターセット インスタンスの NameId の値を生成する役割を担います。

  • インスタンス Id の値は、時間の経過と同時に安定している必要があります (同じ論理インスタンスはコールバックのすべての呼び出しに同じ Id 値を使用する必要があります)。一意である必要があります (たとえば、すべてのインスタンスに 0 を使用するだけではいけません)。また、0xFFFFFFFE未満にする必要があります (使用 PCW_ANY_INSTANCE_IDしないでください)。 可能であれば、インスタンス Id は意味のあるものにする必要があります (たとえば、プロセス カウンターセットでは、任意の (シーケンス番号など) ではなく、 として IdPID を使用する場合があります)。

  • インスタンス Name の値は、時間の経過と同時に安定している必要があります (同じ論理インスタンスがコールバックのすべての呼び出しに同じ Name 値を使用する必要があります)。また、一意である必要があります。 カウンターセットが複数のインスタンスをサポートしている場合は、インスタンス Name を空白にしないでください。 文字列の一致は大文字と小文字を区別しない比較を使用して行われるので Name 、値は大文字と小文字のみで異なるべきではありません。

要求を処理 PcwCallbackCollectData する場合、基本的なコールバック実装では、カウンターセット インスタンスごとに PcwAddInstance (または CTRPP によって生成された AddXxx 関数) を 1 回呼び出すだけです。 詳細については、「 CTRPP によって生成された AddXxx 関数」を参照してください。

次の最適化は、必要に応じて、より高度な実装で使用できます。

  • その場合 Info->CollectData.CounterMask != (UINT64)-1 、コンシューマーはカウンターセット内のすべてのカウンターを必要としません。 この場合、コールバックは、対応する値をカウンター データ ブロックに 0 のままにすることで、データ収集を最適化できます。

  • その場合Info->CollectData.InstanceId != PCW_ANY_INSTANCE_ID、コンシューマーは、 と等しいCollectData.InstanceIdインスタンスに関するデータのみを必要とInstanceIdします。 コールバックでは、 が一致InstanceIdしないインスタンスの の 呼び出しをPcwAddInstanceスキップすることで、データ収集が最適化される場合があります。

  • その場合Info->CollectData.InstanceMask != "*"、コンシューマーは、 のワイルドカード パターンCollectData.InstanceMaskに一致する を持つInstanceNameインスタンスに関するデータのみを必要とします。 コールバックでは、 が一致InstanceNameしないインスタンスの の 呼び出しをPcwAddInstanceスキップすることで、データ収集が最適化される場合があります。 ワイルドカードマッチングは正しく実装するのが難しいので、この最適化はインスタンスデータ収集が非常に高価な場合にのみ推奨されます。

ほとんどの場合、要求のコールバック実装 PcwCallbackEnumerateInstances は、 の実装 PcwCallbackCollectDataと同じになります。 コールバックは、必要に応じて、 の呼び出しPcwAddInstanceで実際のカウンター データを省略することによって (つまり、 パラメーターと Data パラメーターに 0 と NULL を渡すことによって) データ収集をCount最適化できます。

コールバック実装は、次のように構造化できます。

NTSTATUS NTAPI
MyProviderCallback(
    _In_ PCW_CALLBACK_TYPE Type,
    _In_ PPCW_CALLBACK_INFORMATION Info,
    _In_opt_ PVOID Context)
{
    PCW_MASK_INFORMATION* MaskInfo;
    PAGED_CODE();

    switch (Type)
    {
    case PcwCallbackCollectData:
        MaskInfo = &Info->CollectData;
        break;

    case PcwCallbackEnumerateInstances:
        MaskInfo = &Info->EnumerateInstances;
        break;

    case PcwCallbackAddCounter:
        // Optional (for optimizing data collection):
        // InterlockedIncrement(&CollectionEnableCount);
        return STATUS_SUCCESS; // Normally no action needed.

    case PcwCallbackRemoveCounter:
        // Optional (for optimizing data collection):
        // InterlockedDecrement(&CollectionEnableCount);
        return STATUS_SUCCESS; // Normally no action needed.
    }

    // Common code for CollectData and EnumerateInstances.
    // Note that this code needs to be thread-safe, as multiple
    // threads might invoke this callback at the same time.

    for (Instance : InstanceList) { // Pseudocode, need thread-safe enumeration
        NTSTATUS Status;

        // Optional optimization:
        // if (MaskInfo->InstanceId != PCW_ANY_INSTANCE_ID && Instance->Id != MaskInfo->InstanceId) {
        //     continue;
        // }

        // Note that in most cases, you'll use a CTRPP-generated Add wrapper instead of directly
        // calling PcwAddInstance.
        Status = PcwAddInstance(MaskInfo->Buffer,
                                &Instance->Name,
                                Instance->Id,
                                1, // Number of items in PcwData array
                                &Instance->PcwData);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }
    }

    return STATUS_SUCCESS;
}

ほとんどのカウンターセット プロバイダーは 、CTRPP ツールを使用してカウンターセット マニフェストを処理し、ヘルパー関数を生成します。これには、関数のラップ PcwRegister (CTRPP によってカウンター記述子が生成されます) や PcwAddInstance (CTRPP によって PcwAddInstanceプロバイダーのデータ構造をで必要な形式にラップするためのコードが生成されます)。

この例では、KCS サンプルのマニフェストに対 KCS.man して CTRPP によって生成される Register 関数を参照してください。

EXTERN_C FORCEINLINE NTSTATUS
KcsRegisterGeometricWave(
    __in_opt PPCW_CALLBACK Callback,
    __in_opt PVOID CallbackContext
    )
{
    PCW_REGISTRATION_INFORMATION RegInfo;
    UNICODE_STRING Name = RTL_CONSTANT_STRING(L"Geometric Waves");
    PCW_COUNTER_DESCRIPTOR Descriptors[] = {
        { 1, 0, FIELD_OFFSET(GEOMETRIC_WAVE_VALUES, Triangle), RTL_FIELD_SIZE(GEOMETRIC_WAVE_VALUES, Triangle)},
        { 2, 0, FIELD_OFFSET(GEOMETRIC_WAVE_VALUES, Square), RTL_FIELD_SIZE(GEOMETRIC_WAVE_VALUES, Square)},
    };

    PAGED_CODE();

    RtlZeroMemory(&RegInfo, sizeof RegInfo);

    RegInfo.Version = PCW_CURRENT_VERSION;
    RegInfo.Counters = Descriptors;
    RegInfo.CounterCount = RTL_NUMBER_OF(Descriptors);
    RegInfo.Callback = Callback;
    RegInfo.CallbackContext = CallbackContext;
    RegInfo.Name = &Name;

    return PcwRegister(&KcsGeometricWave, &RegInfo);
}

カウンターセット プロバイダーは、コンシューマー要求を PCW_CALLBACK 処理する 関数を実装します。 次のコード例は、シミュレートされたデータを PCW_CALLBACK 列挙して収集する という名前 KcsGeometricWaveCallback の関数を示しています。 (を KcsAddGeometricWave 呼び出 PcwAddInstanceす CTRPP によって生成されたヘルパー関数であることに注意してください)。

NTSTATUS
KcsAddGeometricInstance (
    _In_ PPCW_BUFFER Buffer,
    _In_ PCWSTR Name,
    _In_ ULONG Id,
    _In_ ULONG MinimalValue,
    _In_ ULONG Amplitude
    )
{
    ULONG Index;
    LARGE_INTEGER Timestamp;
    UNICODE_STRING UnicodeName;
    GEOMETRIC_WAVE_VALUES Values;

    PAGED_CODE();

    KeQuerySystemTime(&Timestamp);

    Index = (Timestamp.QuadPart / 10000000) % 10;

    Values.Triangle = MinimalValue + Amplitude * abs(5 - Index) / 5;
    Values.Square = MinimalValue + Amplitude * (Index < 5);

    RtlInitUnicodeString(&UnicodeName, Name);

    return KcsAddGeometricWave(Buffer, &UnicodeName, Id, &Values);
}

NTSTATUS NTAPI
KcsGeometricWaveCallback (
    __in PCW_CALLBACK_TYPE Type,
    __in PPCW_CALLBACK_INFORMATION Info,
    __in_opt PVOID Context
    )
{
    NTSTATUS Status;
    UNICODE_STRING UnicodeName;

    UNREFERENCED_PARAMETER(Context);

    PAGED_CODE();

    switch (Type) {
    case PcwCallbackEnumerateInstances:

        //
        // Instances are being enumerated, so we add them without values.
        //

        RtlInitUnicodeString(&UnicodeName, L"Small Wave");
        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,
                                     &UnicodeName,
                                     0,
                                     NULL);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        RtlInitUnicodeString(&UnicodeName, L"Medium Wave");
        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,
                                     &UnicodeName,
                                     1,
                                     NULL);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        RtlInitUnicodeString(&UnicodeName, L"Large Wave");
        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,
                                     &UnicodeName,
                                     2,
                                     NULL);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        break;

 case PcwCallbackCollectData:

        //
        // Add values for 3 instances of Geometric Wave Counterset.
        //

        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,
                                         L"Small Wave",
                                         0,
                                         40,
                                         20);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,
                                         L"Medium Wave",
                                         1,
                                         30,
                                         40);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,
                                         L"Large Wave",
                                         2,
                                         20,
                                         60);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        break;
    }

    return STATUS_SUCCESS;
}

KCS サンプルの DriverEntry ルーチンでは、 KcsGeometricWaveCallback 関数はカウンターセットを Callback 登録するときに KcsRegisterGeometricWave として指定されます。

    //
    // Register Countersets during DriverEntry. (TODO: Unregister at driver unload.)
    //

    Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

要件

要件
サポートされている最小のクライアント Windows 7 以降のバージョンの Windows で使用できます。
対象プラットフォーム デスクトップ
Header wdm.h (Wdm.h、Ntddk.h を含む)
IRQL IRQL <=APC_LEVEL

こちらもご覧ください

PcwRegister

PcwAddInstance

PcwCreateInstance

PCW_CALLBACK_TYPE

PCW_CALLBACK_INFORMATION

CTRPP

パフォーマンス カウンター ライブラリ (PERFLIB バージョン 2.0)