共用方式為


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列舉值,指出叫用回呼的原因。 可能的值為 PcwCallbackAddCounterPcwCallbackRemoveCounterPcwCallbackEnumerateInstancesPcwCallbackCollectData

[in] Info

PCW_CALLBACK_INFORMATION等位的指標,提供叫用提供者回呼原因的詳細數據。 詳細數據會位於對應至 參數的 Type 欄位中。 例如,如果 Type == PcwCallbackEnumerateInstances ,則詳細數據將會在 中 Info->EnumerateInstances

[in, optional] Context

呼叫 PcwRegister 或呼叫 CTRPP 產生的 Register 函式時,提供者所提供的回呼內容 (叫 PcwRegister 用) 。

傳回值

PCW_CALLBACK如果回呼完成且沒有錯誤,或NTSTATUS錯誤碼,則回呼函式應該會傳回 STATUS_SUCCESS 。 請注意,此傳回碼僅供參考之用,而且即使回呼傳回錯誤,取用者的要求處理仍會繼續。

備註

計數器集提供者可以透過兩個不同的系統,將資訊提供給取用者:

  • 提供者可以使用 PcwCreateInstancePcwCloseInstance 來維護可用實例的清單和對應的計數器數據。 此系統很容易實作,但彈性有限。 使用此系統時,提供者不需要提供回呼函式。 如需此系統的詳細資訊,請參閱 PcwCreateInstance的檔。

  • 提供者可以提供 PCW_CALLBACK 函式,以視需要由性能計數器連結庫叫用以收集數據。

回呼實作必須是安全線程。 多個不同的取用者可能會同時在不同的線程上向提供者要求數據。

回呼必須處理 PcwCallbackEnumerateInstancesPcwCallbackCollectData 要求類型。 回呼通常不需要處理其他要求類型,但在複雜的案例中,回呼可能也會處理 PcwCallbackAddCounterPcwCallbackRemoveCounter 優化數據收集 (,也就是在沒有使用中查詢時停用統計數據追蹤) 。

回呼負責產生 Name 計數器集實例的值 Id

  • 實例 Id 值必須隨著時間穩定, (相同的邏輯實例應該針對回呼) 的所有調用使用相同的 Id 值,應該是唯一的 (例如,不要只對所有實例使用 0) ,而且應該小於0xFFFFFFFE (不要使用 PCW_ANY_INSTANCE_ID) 。 可能的話,實例 Id 應該有意義的 (例如,進程計數器集可能會使用 PID 作為 Id) ,而不是任意 (例如序號) 。

  • 實例 Name 值必須隨著時間穩定, (相同的邏輯實例應該針對回呼的所有調用使用相同的 Name 值,) 且必須是唯一的。 如果計數器集支援多個實例,則實例 Name 不應該是空白的。 字串比對是使用不區分大小寫的比較來完成,因此 Name 值不只依大小寫而有所不同。

處理 PcwCallbackCollectData 要求時,基本回呼實作只會針對每個計數器集實例叫用 PcwAddInstance (或 CTRPP 產生的AddXxx函式) 一次。 如需詳細資訊,請參閱 CTRPP 產生的 AddXxx 函式

下列優化可能在必要時用於更進階的實作:

  • 如果 Info->CollectData.CounterMask != (UINT64)-1 取用者不需要計數器集中的所有計數器。 在此情況下,回呼可能會將對應的值保留為計數器數據區塊中的0,以優化數據收集。

  • 如果Info->CollectData.InstanceId != PCW_ANY_INSTANCE_ID取用者只想要與 相等CollectData.InstanceId的實例InstanceId相關數據。 回呼可以略過 對 具有不相符 InstanceId之實例的呼叫PcwAddInstance,以優化數據收集。

  • 如果 Info->CollectData.InstanceMask != "*" 取用者只想要與 InstanceName 符合 通配符模式 CollectData.InstanceMask的 實例相關數據。 回呼可以略過 對 具有不相符 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 範例中指令清單的 CTRPP 產生的 Register KCS.man 函式。

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;
}

DriverEntry在 KCS 範例的例程中,KcsGeometricWaveCallback函式會在註冊計數器集時KcsRegisterGeometricWave指定為 Callback

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

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

規格需求

需求
最低支援的用戶端 可在 Windows 7 和更新版本的 Windows 中使用。
目標平台 桌面
標頭 wdm.h (包括 Wdm.h、Ntddk.h)
IRQL IRQL <=APC_LEVEL

另請參閱

PcwRegister

PcwAddInstance

PcwCreateInstance

PCW_CALLBACK_TYPE

PCW_CALLBACK_INFORMATION

CTRPP

性能計數器連結庫 (PERFLIB 2.0 版)