此例程返回给定 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 节点,将返回零。
返回值
如果已成功查询节点相关性,则 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 个处理器的系统上运行,请使用以下解决方法之一:
迁移到多组节点关联 API(用户模式和内核模式),例如 KeQueryNodeActiveAffinity2。
使用 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 | 任何级别 |