英語で読む

次の方法で共有


KeQueryNodeActiveAffinity2 関数 (wdm.h)

このルーチンは、指定された NUMA ノードの現在の複数グループ プロセッサ アフィニティを返します。

構文

C++
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. RelationNumaNodeKeQueryLogicalProcessorRelationship を呼び出して、指定されたプロセッサ番号に関連付けられている NUMA ノードに直接クエリを実行します。

次の例は、Windows Server 2022 以降で問題になるコードを示し、両方の回避策を示しています。

C++
//
// 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 サポート