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 열거형 값입니다. 가능한 값은 PcwCallbackAddCounter, PcwCallbackRemoveCounter, PcwCallbackEnumerateInstancesPcwCallbackCollectData입니다.

[in] Info

공급자 콜백이 호출된 이유에 대한 세부 정보를 제공하는 PCW_CALLBACK_INFORMATION 공용 구조체에 대한 포인터입니다. 세부 정보는 매개 변수에 해당하는 Type 필드에 있습니다. 예를 들어 이면 Type == PcwCallbackEnumerateInstances 세부 정보가 에 있습니다 Info->EnumerateInstances.

[in, optional] Context

PcwRegister를 호출하거나 CTRPP에서 생성된 Register 함수(를 호출)를 호출할 때 공급자가 제공한 콜백 컨텍스트입니다PcwRegister.

반환 값

콜백 함수는 PCW_CALLBACK 콜백이 오류 없이 완료된 경우 를 반환하거나, NTSTATUS 그렇지 않으면 오류 코드를 반환 STATUS_SUCCESS 해야 합니다. 이 반환 코드는 정보 제공 용도로만 사용되며 콜백이 오류를 반환하더라도 소비자 요청 처리는 계속됩니다.

설명

카운터셋 공급자는 다음 두 가지 시스템을 통해 소비자에게 정보를 제공할 수 있습니다.

  • 공급자는 및 PcwCloseInstance 를 사용하여 PcwCreateInstance 사용 가능한 인스턴스 목록과 해당 카운터 데이터를 유지할 수 있습니다. 이 시스템은 구현이 간단하지만 유연성이 제한적입니다. 이 시스템을 사용하는 경우 공급자는 콜백 함수를 제공할 필요가 없습니다. 이 시스템에 대한 자세한 내용은 PcwCreateInstance에 대한 설명서를 참조하세요.

  • 공급자는 데이터를 수집하는 데 필요한 경우 성능 카운터 라이브러리에서 호출할 함수를 제공할 PCW_CALLBACK 수 있습니다.

콜백 구현은 스레드로부터 안전해야 합니다. 여러 다른 소비자가 서로 다른 스레드에서 공급자의 데이터를 동시에 요청할 수 있습니다.

콜백은 및 PcwCallbackCollectData 요청 형식을 PcwCallbackEnumerateInstances 처리해야 합니다. 콜백은 일반적으로 다른 요청 형식을 처리할 필요가 없지만 복잡한 시나리오에서는 콜백이 데이터 수집을 처리 PcwCallbackAddCounter 하고 PcwCallbackRemoveCounter 최적화할 수도 있습니다(즉, 쿼리가 활성화되지 않은 경우 통계 추적을 사용하지 않도록 설정).

콜백은 카운터셋 인스턴스에 대한 및 Id 값을 생성 Name 합니다.

  • 인스턴스 Id 값은 시간이 지남에 따라 안정적이어야 하며(동일한 논리 instance 콜백의 모든 호출에 대해 동일한 Id 값을 사용해야 함), 고유해야 하고(예: 모든 인스턴스에 대해 단순히 0을 사용하지 않음) 0xFFFFFFFE 미만이어야 합니다(사용하지 PCW_ANY_INSTANCE_ID마세요). 가능하면 instance Id 의미 있어야 합니다(예: 프로세스 카운터 세트는 임의(예: 시퀀스 번호) 대신 PIDId를 로 사용할 수 있음).

  • 인스턴스 Name 값은 시간이 지남에 따라 안정적이어야 하며(동일한 논리 instance 콜백의 모든 호출에 대해 동일한 Name 값을 사용해야 함) 고유해야 합니다. 카운터 세트가 여러 인스턴스를 지원하는 경우 instance Name 비워 두면 안 됩니다. 문자열 일치는 대/소문자를 구분하지 않는 비교를 사용하여 수행되므로 Name 값이 대/소문자만 달라서는 안 됩니다.

요청을 처리할 PcwCallbackCollectData 때 기본 콜백 구현은 각 카운터 세트 instance 대해 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 != "*" 소비자는 의 와일드카드 패턴CollectData.InstanceMaskInstanceName 일치하는 가 있는 인스턴스에 대한 데이터만 원합니다. 콜백은 일치하지 않는 InstanceName인스턴스에 대한 호출 PcwAddInstance 을 건너뛰어 데이터 수집을 최적화할 수 있습니다. 와일드카드 일치는 올바르게 구현하기 어렵기 때문에 instance 데이터 수집 비용이 많이 드는 경우에만 이 최적화를 사용하는 것이 좋습니다.

대부분의 경우 요청에 대한 콜백 구현은 에 대한 PcwCallbackEnumerateInstancesPcwCallbackCollectData구현과 동일합니다. 콜백은 필요에 따라 호출에서 실제 카운터 데이터를 생략하여 데이터 수집을 최적화할 PcwAddInstance 수 있습니다(즉, 및 Data 매개 변수에 대해 Count 0 및 NULL을 전달).

콜백 구현은 다음과 같이 구성할 수 있습니다.

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 소비자 요청을 처리하는 함수를 구현합니다. 다음 코드 예제에서는 시뮬레이션된 데이터를 열거하고 수집하는 라는 KcsGeometricWaveCallback 함수를 보여 PCW_CALLBACK 줍니다. 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 의 루틴에서 함수는 카운터 세트를 등록할 때 KcsRegisterGeometricWaveCallback 지정됩니다.

    //
    // 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)