-/// best_group() retrieves logical processor information using Windows specific
-/// API and returns the best group id for the thread with index idx. Original
-/// code from Texel by Peter Ă–sterlund.
-
-int best_group(size_t idx) {
-
- int threads = 0;
- int groups = 0;
- int cores = 0;
- DWORD returnLength = 0;
- DWORD byteOffset = 0;
-
- // Early exit if the needed API is not available at runtime
- HMODULE k32 = GetModuleHandle("Kernel32.dll");
- auto fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
- if (!fun1)
- return -1;
-
- // First call to get returnLength. We expect it to fail due to null buffer
- if (fun1(RelationAll, nullptr, &returnLength))
- return -1;
-
- // Once we know returnLength, allocate the buffer
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
- ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength);
-
- // Second call, now we expect to succeed
- if (!fun1(RelationAll, buffer, &returnLength))
- {
- free(buffer);
- return -1;
- }
-
- while (byteOffset < returnLength)
- {
- if (ptr->Relationship == RelationGroup)
- groups += ptr->Group.MaximumGroupCount;
-
- else if (ptr->Relationship == RelationProcessorCore)
- {
- cores++;
- threads += (ptr->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
- }
-
- assert(ptr->Size);
- byteOffset += ptr->Size;
- ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);
- }
-
- free(buffer);
-
- std::vector<int> core_groups;
-
- // Run as many threads as possible on the same group until core limit is
- // reached, then move on filling the next group.
- for (int n = 0; n < groups; n++)
- for (int i = 0; i < cores / groups; i++)
- core_groups.push_back(n);
-
- // In case a core has more than one logical processor (we assume 2) and we
- // have still threads to allocate, then spread them evenly across available
- // groups.
- for (int t = 0; t < threads - cores; t++)
- core_groups.push_back(t % groups);
-
- // If we still have more threads than the total number of logical processors
- // then return -1 and let the OS to decide what to do.
- return idx < core_groups.size() ? core_groups[idx] : -1;
+// best_node() retrieves logical processor information using Windows specific
+// API and returns the best node id for the thread with index idx. Original
+// code from Texel by Peter Ă–sterlund.
+
+static int best_node(size_t idx) {
+
+ int threads = 0;
+ int nodes = 0;
+ int cores = 0;
+ DWORD returnLength = 0;
+ DWORD byteOffset = 0;
+
+ // Early exit if the needed API is not available at runtime
+ HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll"));
+ auto fun1 = (fun1_t) (void (*)()) GetProcAddress(k32, "GetLogicalProcessorInformationEx");
+ if (!fun1)
+ return -1;
+
+ // First call to GetLogicalProcessorInformationEx() to get returnLength.
+ // We expect the call to fail due to null buffer.
+ if (fun1(RelationAll, nullptr, &returnLength))
+ return -1;
+
+ // Once we know returnLength, allocate the buffer
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
+ ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) malloc(returnLength);
+
+ // Second call to GetLogicalProcessorInformationEx(), now we expect to succeed
+ if (!fun1(RelationAll, buffer, &returnLength))
+ {
+ free(buffer);
+ return -1;
+ }
+
+ while (byteOffset < returnLength)
+ {
+ if (ptr->Relationship == RelationNumaNode)
+ nodes++;
+
+ else if (ptr->Relationship == RelationProcessorCore)
+ {
+ cores++;
+ threads += (ptr->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
+ }
+
+ assert(ptr->Size);
+ byteOffset += ptr->Size;
+ ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) (((char*) ptr) + ptr->Size);
+ }
+
+ free(buffer);
+
+ std::vector<int> groups;
+
+ // Run as many threads as possible on the same node until the core limit is
+ // reached, then move on to filling the next node.
+ for (int n = 0; n < nodes; n++)
+ for (int i = 0; i < cores / nodes; i++)
+ groups.push_back(n);
+
+ // In case a core has more than one logical processor (we assume 2) and we
+ // have still threads to allocate, then spread them evenly across available
+ // nodes.
+ for (int t = 0; t < threads - cores; t++)
+ groups.push_back(t % nodes);
+
+ // If we still have more threads than the total number of logical processors
+ // then return -1 and let the OS to decide what to do.
+ return idx < groups.size() ? groups[idx] : -1;