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
Header wdm.h
IRQL 任意のレベル

こちらもご覧ください

KeQueryNodeActiveAffinity

KeQueryNodeActiveProcessorCount

NUMA サポート