/// CPU Information Auto-Detection /// Author : Qiuwen Lu /// Date : 2016-08-08 #include #include #include #include #include #include #include #include #include #include struct hwinfo_core { unsigned int enable; unsigned int cpu_id; unsigned int physical_cpu_id; unsigned int socket_id; }; struct hwinfo_main { /* logical cpus, including hardware-thread cpus */ unsigned int nr_total_cpus; /* counts of numa nodes */ unsigned int nr_total_sockets; /* detailed info of logical cpus */ struct hwinfo_core coreinfo[RTE_MAX_LCORE]; }; #define __FILE_LINUX_CPUS "/sys/devices/system/cpu/present" #define __FILE_LINUX_PCPU_ID "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_id" #define __FILE_LINUX_SOCKET_ID "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/physical_package_id" #define SYS_CPU_DIR "/sys/devices/system/cpu/cpu%u" #define CORE_ID_FILE "topology/core_id" #define NUMA_NODE_PATH "/sys/devices/system/node" /* parse a sysfs (or other) file containing one integer value */ static int eal_parse_sysfs_value(const char *filename, unsigned long *val) { FILE *f; char buf[BUFSIZ]; char *end = NULL; if ((f = fopen(filename, "r")) == NULL) { RTE_LOG(ERR, EAL, "%s(): cannot open sysfs value %s\n", __func__, filename); return -1; } if (fgets(buf, sizeof(buf), f) == NULL) { RTE_LOG(ERR, EAL, "%s(): cannot read sysfs value %s\n", __func__, filename); fclose(f); return -1; } *val = strtoul(buf, &end, 0); if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs value %s\n", __func__, filename); fclose(f); return -1; } fclose(f); return 0; } static int linux_get_nr_total_cpus(void) { char buffer[MR_STRING_MAX], *string; FILE *fd; fd = fopen(__FILE_LINUX_CPUS, "r"); if (fd == NULL) return -1; if (fgets(buffer, sizeof(buffer), fd) == NULL) { fclose(fd); return -1; } fclose(fd); string = index(buffer, '-'); if (string == NULL) return -1; return (atoi(++string) + 1); } static int linux_get_physical_cpu_id(int lcore_id) { char path[PATH_MAX]; unsigned long id; int len = snprintf(path, sizeof(path), SYS_CPU_DIR "/%s", lcore_id, CORE_ID_FILE); if (len <= 0 || (unsigned)len >= sizeof(path)) goto err; if (eal_parse_sysfs_value(path, &id) != 0) goto err; return (unsigned)id; err: MR_ERROR("Error reading core id value from %s " "for lcore %u - assuming core 0\n", SYS_CPU_DIR, lcore_id); return 0; } static int linux_get_socket_id(int lcore_id) { unsigned socket; for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) { char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/node%u/cpu%u", NUMA_NODE_PATH, socket, lcore_id); if (access(path, F_OK) == 0) return socket; } return 0; } static int hwinfo_cpu_scan(struct hwinfo_main * ctx) { int nr_cpus = linux_get_nr_total_cpus(); if (nr_cpus < 0) { MR_ERROR("Cannot get count of total cpus"); return nr_cpus; } int bitmap_socket[RTE_MAX_NUMA_NODES] = { 0 }; int count_sockets = 0; int count_cpus = 0; // 计算CPU信息 for (int cpu_id = 0; cpu_id < nr_cpus; cpu_id++) { int pcpu_id = linux_get_physical_cpu_id(cpu_id); int socket_id = linux_get_socket_id(cpu_id); if (pcpu_id < 0) { MR_ERROR("Cannot get physical id of cpu %d\n", cpu_id); continue; } if (socket_id < 0) { MR_ERROR("Cannot get socket id for cpu %d\n", cpu_id); continue; } ctx->coreinfo[cpu_id].enable = 1; ctx->coreinfo[cpu_id].cpu_id = cpu_id; ctx->coreinfo[cpu_id].physical_cpu_id = pcpu_id; ctx->coreinfo[cpu_id].socket_id = socket_id; count_cpus++; bitmap_socket[socket_id] = 1; } // 根据Socket的标志位,计算Socket的数量。 for (int socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) { count_sockets += bitmap_socket[socket_id] > 0 ? 1 : 0; } assert(count_cpus > 0); assert(count_sockets > 0); ctx->nr_total_cpus = count_cpus; ctx->nr_total_sockets = count_sockets; return 0; } int hwinfo_deinit(struct hwinfo_main * object) { return 0; } int hwinfo_init(struct sc_main * sc) { struct hwinfo_main * hwinfo_main; // 分配存储空间 hwinfo_main = ZMALLOC(sizeof(struct hwinfo_main)); MR_VERIFY_MALLOC(hwinfo_main); // 检测处理器信息 int retval = hwinfo_cpu_scan(hwinfo_main); if (retval < 0) goto errout; sc->hwinfo_main = hwinfo_main; return RT_SUCCESS; errout: if (hwinfo_main != NULL) hwinfo_deinit(hwinfo_main); return RT_ERR; } int hwinfo_nr_sockets(struct hwinfo_main * object) { return object->nr_total_sockets; } int hwinfo_nr_cpus(struct hwinfo_main * object) { return object->nr_total_cpus; } int hwinfo_physical_cpu_id(struct hwinfo_main * object, int cpu_id) { if (!object->coreinfo[cpu_id].enable) return -1; return object->coreinfo[cpu_id].physical_cpu_id; } int hwinfo_socket_id(struct hwinfo_main * object, int cpu_id) { if (!object->coreinfo[cpu_id].enable) return -1; return object->coreinfo[cpu_id].socket_id; }