*/
#include <pthread.h>
+#include <stdbool.h>
#include <stdint.h>
#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_lcore.h>
+#include <rte_os.h>
#include "eal_private.h"
#include "eal_thread.h"
#include "eal_windows.h"
-/* global data structure that contains the CPU map */
-static struct _wcpu_map {
- unsigned int total_procs;
- unsigned int proc_sockets;
- unsigned int proc_cores;
- unsigned int reserved;
- struct _win_lcore_map {
- uint8_t socket_id;
- uint8_t core_id;
- } wlcore_map[RTE_MAX_LCORE];
-} wcpu_map = { 0 };
-
-/*
- * Create a map of all processors and associated cores on the system
- */
-void
+/** Number of logical processors (cores) in a processor group (32 or 64). */
+#define EAL_PROCESSOR_GROUP_SIZE (sizeof(KAFFINITY) * CHAR_BIT)
+
+struct lcore_map {
+ uint8_t socket_id;
+ uint8_t core_id;
+};
+
+struct socket_map {
+ uint16_t node_id;
+};
+
+struct cpu_map {
+ unsigned int socket_count;
+ unsigned int lcore_count;
+ struct lcore_map lcores[RTE_MAX_LCORE];
+ struct socket_map sockets[RTE_MAX_NUMA_NODES];
+};
+
+static struct cpu_map cpu_map = { 0 };
+
+/* eal_create_cpu_map() is called before logging is initialized */
+static void
+log_early(const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ vfprintf(stderr, format, va);
+ va_end(va);
+}
+
+int
eal_create_cpu_map(void)
{
- wcpu_map.total_procs =
- GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
-
- LOGICAL_PROCESSOR_RELATIONSHIP lprocRel;
- DWORD lprocInfoSize = 0;
- BOOL ht_enabled = FALSE;
-
- /* First get the processor package information */
- lprocRel = RelationProcessorPackage;
- /* Determine the size of buffer we need (pass NULL) */
- GetLogicalProcessorInformationEx(lprocRel, NULL, &lprocInfoSize);
- wcpu_map.proc_sockets = lprocInfoSize / 48;
-
- lprocInfoSize = 0;
- /* Next get the processor core information */
- lprocRel = RelationProcessorCore;
- GetLogicalProcessorInformationEx(lprocRel, NULL, &lprocInfoSize);
- wcpu_map.proc_cores = lprocInfoSize / 48;
-
- if (wcpu_map.total_procs > wcpu_map.proc_cores)
- ht_enabled = TRUE;
-
- /* Distribute the socket and core ids appropriately
- * across the logical cores. For now, split the cores
- * equally across the sockets.
- */
- unsigned int lcore = 0;
- for (unsigned int socket = 0; socket <
- wcpu_map.proc_sockets; ++socket) {
- for (unsigned int core = 0;
- core < (wcpu_map.proc_cores / wcpu_map.proc_sockets);
- ++core) {
- wcpu_map.wlcore_map[lcore]
- .socket_id = socket;
- wcpu_map.wlcore_map[lcore]
- .core_id = core;
- lcore++;
- if (ht_enabled) {
- wcpu_map.wlcore_map[lcore]
- .socket_id = socket;
- wcpu_map.wlcore_map[lcore]
- .core_id = core;
- lcore++;
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infos, *info;
+ DWORD infos_size;
+ bool full = false;
+
+ infos_size = 0;
+ if (!GetLogicalProcessorInformationEx(
+ RelationNumaNode, NULL, &infos_size)) {
+ DWORD error = GetLastError();
+ if (error != ERROR_INSUFFICIENT_BUFFER) {
+ log_early("Cannot get NUMA node info size, error %lu\n",
+ GetLastError());
+ rte_errno = ENOMEM;
+ return -1;
+ }
+ }
+
+ infos = malloc(infos_size);
+ if (infos == NULL) {
+ log_early("Cannot allocate memory for NUMA node information\n");
+ rte_errno = ENOMEM;
+ return -1;
+ }
+
+ if (!GetLogicalProcessorInformationEx(
+ RelationNumaNode, infos, &infos_size)) {
+ log_early("Cannot get NUMA node information, error %lu\n",
+ GetLastError());
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ info = infos;
+ while ((uint8_t *)info - (uint8_t *)infos < infos_size) {
+ unsigned int node_id = info->NumaNode.NodeNumber;
+ GROUP_AFFINITY *cores = &info->NumaNode.GroupMask;
+ struct lcore_map *lcore;
+ unsigned int i, socket_id;
+
+ /* NUMA node may be reported multiple times if it includes
+ * cores from different processor groups, e. g. 80 cores
+ * of a physical processor comprise one NUMA node, but two
+ * processor groups, because group size is limited by 32/64.
+ */
+ for (socket_id = 0; socket_id < cpu_map.socket_count;
+ socket_id++) {
+ if (cpu_map.sockets[socket_id].node_id == node_id)
+ break;
+ }
+
+ if (socket_id == cpu_map.socket_count) {
+ if (socket_id == RTE_DIM(cpu_map.sockets)) {
+ full = true;
+ goto exit;
+ }
+
+ cpu_map.sockets[socket_id].node_id = node_id;
+ cpu_map.socket_count++;
+ }
+
+ for (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {
+ if ((cores->Mask & ((KAFFINITY)1 << i)) == 0)
+ continue;
+
+ if (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores)) {
+ full = true;
+ goto exit;
}
+
+ lcore = &cpu_map.lcores[cpu_map.lcore_count];
+ lcore->socket_id = socket_id;
+ lcore->core_id =
+ cores->Group * EAL_PROCESSOR_GROUP_SIZE + i;
+ cpu_map.lcore_count++;
}
+
+ info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(
+ (uint8_t *)info + info->Size);
}
+
+exit:
+ if (full) {
+ /* Not a fatal error, but important for troubleshooting. */
+ log_early("Enumerated maximum of %u NUMA nodes and %u cores\n",
+ cpu_map.socket_count, cpu_map.lcore_count);
+ }
+
+ free(infos);
+
+ return 0;
}
-/*
- * Check if a cpu is present by the presence of the cpu information for it
- */
int
eal_cpu_detected(unsigned int lcore_id)
{
- return (lcore_id < wcpu_map.total_procs);
+ return lcore_id < cpu_map.lcore_count;
}
-/*
- * Get CPU socket id for a logical core
- */
unsigned
eal_cpu_socket_id(unsigned int lcore_id)
{
- return wcpu_map.wlcore_map[lcore_id].socket_id;
+ return cpu_map.lcores[lcore_id].socket_id;
}
-/*
- * Get CPU socket id (NUMA node) for a logical core
- */
unsigned
eal_cpu_core_id(unsigned int lcore_id)
{
- return wcpu_map.wlcore_map[lcore_id].core_id;
+ return cpu_map.lcores[lcore_id].core_id;
+}
+
+unsigned int
+eal_socket_numa_node(unsigned int socket_id)
+{
+ return cpu_map.sockets[socket_id].node_id;
}