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 节点,返回零。

返回值

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. 迁移到多组节点相关性 API (用户模式和内核模式) ,例如 KeQueryNodeActiveAffinity2

  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 支持