다음을 통해 공유


KeQueryNodeActiveAffinity2 함수(wdm.h)

이 루틴은 지정된 NUMA 노드의 현재 다중 그룹 프로세서 선호도를 반환합니다.

구문

NTSTATUS KeQueryNodeActiveAffinity2(
  [in]  USHORT          NodeNumber,
  [out] PGROUP_AFFINITY GroupAffinities,
  [in]  USHORT          GroupAffinitiesCount,
  [out] PUSHORT         GroupAffinitiesRequired
);

매개 변수

[in] NodeNumber

쿼리할 노드의 노드 번호를 제공합니다.

[out] GroupAffinities

성공하면 그룹 번호와 식별된 그룹의 선호도 마스크를 수신하는 GROUP_AFFINITY 구조의 배열에 대한 포인터를 제공합니다.

[in] GroupAffinitiesCount

그룹 친화성 배열의 요소 수를 지정하는 USHORT 형식의 값입니다. 배열이 너무 작아 노드 선호도를 보유할 수 없는 경우 STATUS_BUFFER_TOO_SMALL 반환되고 필요한 요소 수가 GroupAffinitiesRequired에 반환됩니다.

[out] GroupAffinitiesRequired

노드 선호도를 나타내는 데 필요한 그룹 선호도 수를 수신하는 USHORT 형식의 값에 대한 포인터입니다. 메모리 전용 NUMA 노드의 경우 0이 반환됩니다.

반환 값

노드 선호도를 성공적으로 쿼리했는지 STATUS_SUCCESS.

잘못된 노드 번호를 지정했는지 STATUS_INVALID_PARAMETER.

제공된 배열이 너무 작으면 STATUS_BUFFER_TOO_SMALL.

설명

Windows Server 2022부터 운영 체제는 더 이상 큰 NUMA 노드를 분할하지 않습니다. 대신 Windows는 시스템의 실제 NUMA 토폴로지를 보고합니다. 노드에 64개 이상의 프로세서가 포함된 경우 NUMA 노드는 둘 이상의 그룹에 걸쳐 있습니다. 이 경우 시스템은 각 NUMA 노드에 대한 기본 그룹을 할당합니다. 기본 그룹은 항상 가장 많은 프로세서를 포함하는 그룹입니다. 지정된 NUMA 노드의 활성 프로세서 수를 확인하려면(모든 그룹에서) KeQueryNodeActiveProcessorCount를 호출합니다. 이 동작 변경에 대한 자세한 내용은 NUMA 지원을 참조하세요.

레거시 노드 분할 동작을 다시 사용하도록 설정하려면 레지스트리를 다음과 같이 변경하고 시스템을 다시 부팅합니다.

reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NUMA" /v SplitLargeNodes /t REG_DWORD /d 1

드라이버가 KeQueryNodeActiveAffinity를 호출하여 프로세서를 NUMA 노드에 매핑하고 NUMA 노드당 프로세서가 64개를 초과하는 시스템에서 코드가 실행되는 경우 다음 해결 방법 중 하나를 사용합니다.

  1. KeQueryNodeActiveAffinity2와 같은 다중 그룹 노드 선호도 API(사용자 모드 및 커널 모드)로 마이그레이션합니다.

  2. RelationNumaNode를 사용하여 KeQueryLogicalProcessorRelationship을 호출하여 지정된 프로세서 번호와 연결된 NUMA 노드를 직접 쿼리합니다.

다음 예제에서는 Windows Server 2022 이상에서 문제가 될 수 있는 코드를 보여 줍니다. 그런 다음 두 가지 해결 방법을 모두 보여 줍니다.

//
// Problematic implementation using KeQueryNodeActiveAffinity.
//

    USHORT CurrentNode;
    USHORT HighestNodeNumber;
    GROUP_AFFINITY NodeAffinity;
    ULONG ProcessorIndex;
    PROCESSOR_NUMBER ProcessorNumber;

    HighestNodeNumber = KeQueryHighestNodeNumber();
    for (CurrentNode = 0; CurrentNode <= HighestNodeNumber; CurrentNode += 1) {

        KeQueryNodeActiveAffinity(CurrentNode, &NodeAffinity, NULL);
        while (NodeAffinity.Mask != 0) {

            ProcessorNumber.Group = NodeAffinity.Group;
            BitScanForward(&ProcessorNumber.Number, NodeAffinity.Mask);

            ProcessorIndex = KeGetProcessorIndexFromNumber(&ProcessorNumber);

            ProcessorNodeContexts[ProcessorIndex] = NodeContexts[CurrentNode;]

            NodeAffinity.Mask &= ~((KAFFINITY)1 << ProcessorNumber.Number);
        }
    }

//
// Resolution using KeQueryNodeActiveAffinity2.
//

    USHORT CurrentIndex;
    USHORT CurrentNode;
    USHORT CurrentNodeAffinityCount;
    USHORT HighestNodeNumber;
    ULONG MaximumGroupCount;
    PGROUP_AFFINITY NodeAffinityMasks;
    ULONG ProcessorIndex;
    PROCESSOR_NUMBER ProcessorNumber;
    NTSTATUS Status;

    MaximumGroupCount = KeQueryMaximumGroupCount();
    NodeAffinityMasks = ExAllocatePool2(POOL_FLAG_PAGED,
                                        sizeof(GROUP_AFFINITY) * MaximumGroupCount,
                                        'tseT');

    if (NodeAffinityMasks == NULL) {
        return STATUS_NO_MEMORY;
    }

    HighestNodeNumber = KeQueryHighestNodeNumber();
    for (CurrentNode = 0; CurrentNode <= HighestNodeNumber; CurrentNode += 1) {

        Status = KeQueryNodeActiveAffinity2(CurrentNode,
                                            NodeAffinityMasks,
                                            MaximumGroupCount,
                                            &CurrentNodeAffinityCount);
        NT_ASSERT(NT_SUCCESS(Status));

        for (CurrentIndex = 0; CurrentIndex < CurrentNodeAffinityCount; CurrentIndex += 1) {

            CurrentAffinity = &NodeAffinityMasks[CurrentIndex];

            while (CurrentAffinity->Mask != 0) {

                ProcessorNumber.Group = CurrentAffinity.Group;
                BitScanForward(&ProcessorNumber.Number, CurrentAffinity->Mask);

                ProcessorIndex = KeGetProcessorIndexFromNumber(&ProcessorNumber);

                ProcessorNodeContexts[ProcessorIndex] = NodeContexts[CurrentNode];

                CurrentAffinity->Mask &= ~((KAFFINITY)1 << ProcessorNumber.Number);
            }
        }
    }

//
// Resolution using KeQueryLogicalProcessorRelationship.
//

    ULONG ProcessorCount;
    ULONG ProcessorIndex;
    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX ProcessorInformation;
    ULONG ProcessorInformationSize;
    PROCESSOR_NUMBER ProcessorNumber;
    NTSTATUS Status;

    ProcessorCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);

    for (ProcessorIndex = 0; ProcessorIndex < ProcessorCount; ProcessorIndex += 1) {

        Status = KeGetProcessorNumberFromIndex(ProcessorIndex, &ProcessorNumber);
        NT_ASSERT(NT_SUCCESS(Status));

        ProcessorInformationSize = sizeof(ProcessorInformation);
        Status = KeQueryLogicalProcessorRelationship(&ProcessorNumber,
                                                     RelationNumaNode,
                                                     &ProcessorInformation,
                                                     &ProcessorInformationSize);
        NT_ASSERT(NT_SUCCESS(Status));

        NodeNumber = ProcessorInformation.NumaNode.NodeNumber;

        ProcessorNodeContexts[ProcessorIndex] = NodeContexts[NodeNumber];
    }

요구 사항

요구 사항
지원되는 최소 서버 Windows Server 2022
머리글 wdm.h
IRQL 모든 수준

추가 정보

KeQueryNodeActiveAffinity

KeQueryNodeActiveProcessorCount

NUMA 지원