Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This routine returns the current multi-group processor affinity of the given NUMA node.
Syntax
NTSTATUS KeQueryNodeActiveAffinity2(
[in] USHORT NodeNumber,
[out] PGROUP_AFFINITY GroupAffinities,
[in] USHORT GroupAffinitiesCount,
[out] PUSHORT GroupAffinitiesRequired
);
Parameters
[in] NodeNumber
Supplies the node number of the node to query.
[out] GroupAffinities
Supplies a pointer to an array of GROUP_AFFINITY structures that upon success receive a group number and the affinity mask of the identified group.
[in] GroupAffinitiesCount
A value of type USHORT that specifies the number of elements in the group affinities array. If the array is too small to hold the node affinity then STATUS_BUFFER_TOO_SMALL is returned and the number of elements required is returned in GroupAffinitiesRequired.
[out] GroupAffinitiesRequired
A pointer to a value of type USHORT that receives the number of group affinities required to represent the node affinity. In the case of a memory-only NUMA node, zero is returned.
Return value
STATUS_SUCCESS if the node affinity was queried successfully.
STATUS_INVALID_PARAMETER if an invalid node number was specified.
STATUS_BUFFER_TOO_SMALL if the supplied array is too small.
Remarks
Starting in Windows Server 2022, the operating system no longer splits large NUMA nodes; instead, Windows reports the true NUMA topology of the system. When a node contains more than 64 processors, a NUMA node spans across more than a single group. In this case, the system assigns a primary group for each NUMA node. The primary group is always the one containing the most processors. To determine the number of active processors in a given NUMA node (across all groups), call KeQueryNodeActiveProcessorCount. For more info about this change in behavior, see NUMA Support.
To re-enable the legacy node splitting behavior, make the following change to the registry and reboot the system:
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NUMA" /v SplitLargeNodes /t REG_DWORD /d 1
If your driver maps processors to NUMA nodes by calling KeQueryNodeActiveAffinity, and your code runs on systems with more than 64 processors per NUMA node, use one of the following workarounds:
Migrate to the multi-group node affinity APIs (user-mode and kernel-mode), such as KeQueryNodeActiveAffinity2.
Call KeQueryLogicalProcessorRelationship with RelationNumaNode to directly query the NUMA node associated with a given processor number.
The following example shows code that would be problematic on Windows Server 2022 and later, and then shows both workarounds.
//
// 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];
}
Requirements
Requirement | Value |
---|---|
Minimum supported server | Windows Server 2022 |
Header | wdm.h |
IRQL | Any level |