unsigned long long nodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED) { unsigned long long freeMem = 0; int n; if (numa_available() < 0) { nodeReportError(VIR_ERR_NO_SUPPORT, "%s", _("NUMA not supported on this host")); goto cleanup; } for (n = 0 ; n <= numa_max_node() ; n++) { long long mem; if (numa_node_size64(n, &mem) < 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to query NUMA free memory")); goto cleanup; } freeMem += mem; } cleanup: return freeMem; }
static int virNodeParseNode(const char *sysfs_dir) { char *file = NULL; char *possible = NULL; char *tmp; int ret = -1; if (virAsprintf(&file, "%s/node/possible", sysfs_dir) < 0) { virReportOOMError(); goto cleanup; } /* Assume that a missing node/possible file implies no NUMA * support, and hence all cpus belong to the same node. */ if (!virFileExists(file)) { ret = 1; goto cleanup; } if (virFileReadAll(file, 1024, &possible) < 0) goto cleanup; if (virStrToLong_i(possible, &tmp, 10, &ret) < 0 || (*tmp == '-' && virStrToLong_i(tmp+1, &tmp, 10, &ret) < 0) || *tmp != '\n') { nodeReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse possible nodes '%s'"), possible); goto cleanup; } ret++; cleanup: VIR_FREE(file); VIR_FREE(possible); return ret; }
int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) { struct utsname info; memset(nodeinfo, 0, sizeof(*nodeinfo)); uname(&info); if (virStrcpyStatic(nodeinfo->model, info.machine) == NULL) return -1; #ifdef __linux__ { int ret; FILE *cpuinfo = fopen(CPUINFO_PATH, "r"); if (!cpuinfo) { virReportSystemError(errno, _("cannot open %s"), CPUINFO_PATH); return -1; } ret = linuxNodeInfoCPUPopulate(cpuinfo, nodeinfo); fclose(cpuinfo); if (ret < 0) return -1; /* Convert to KB. */ nodeinfo->memory = physmem_total () / 1024; return ret; } #else /* XXX Solaris will need an impl later if they port QEMU driver */ nodeReportError(VIR_ERR_NO_SUPPORT, "%s", _("node info not implemented on this platform")); return -1; #endif }
int nodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long *freeMems, int startCell, int maxCells) { int n, lastCell, numCells; int ret = -1; int maxCell; if (numa_available() < 0) { nodeReportError(VIR_ERR_NO_SUPPORT, "%s", _("NUMA not supported on this host")); goto cleanup; } maxCell = numa_max_node(); if (startCell > maxCell) { nodeReportError(VIR_ERR_INTERNAL_ERROR, _("start cell %d out of range (0-%d)"), startCell, maxCell); goto cleanup; } lastCell = startCell + maxCells - 1; if (lastCell > maxCell) lastCell = maxCell; for (numCells = 0, n = startCell ; n <= lastCell ; n++) { long long mem; if (numa_node_size64(n, &mem) < 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to query NUMA free memory")); goto cleanup; } freeMems[numCells++] = mem; } ret = numCells; cleanup: return ret; }
/* Return the positive decimal contents of the given * DIR/cpu%u/FILE, or -1 on error. If MISSING_OK and the * file could not be found, return 1 instead of an error; this is * because some machines cannot hot-unplug cpu0, or because * hot-unplugging is disabled. */ static int virNodeGetCpuValue(const char *dir, unsigned int cpu, const char *file, bool missing_ok) { char *path; FILE *pathfp; int value = -1; char value_str[INT_BUFSIZE_BOUND(value)]; char *tmp; if (virAsprintf(&path, "%s/cpu%u/%s", dir, cpu, file) < 0) { virReportOOMError(); return -1; } pathfp = fopen(path, "r"); if (pathfp == NULL) { if (missing_ok && errno == ENOENT) value = 1; else virReportSystemError(errno, _("cannot open %s"), path); goto cleanup; } if (fgets(value_str, sizeof(value_str), pathfp) == NULL) { virReportSystemError(errno, _("cannot read from %s"), path); goto cleanup; } if (virStrToLong_i(value_str, &tmp, 10, &value) < 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, _("could not convert '%s' to an integer"), value_str); goto cleanup; } cleanup: VIR_FORCE_FCLOSE(pathfp); VIR_FREE(path); return value; }
int linuxNodeGetMemoryStats(FILE *meminfo, int cellNum, virNodeMemoryStatsPtr params, int *nparams) { int ret = -1; int i = 0, j = 0, k = 0; int found = 0; int nr_param; char line[1024]; char meminfo_hdr[VIR_NODE_MEMORY_STATS_FIELD_LENGTH]; unsigned long val; struct field_conv { const char *meminfo_hdr; // meminfo header const char *field; // MemoryStats field name } field_conv[] = { {"MemTotal:", VIR_NODE_MEMORY_STATS_TOTAL}, {"MemFree:", VIR_NODE_MEMORY_STATS_FREE}, {"Buffers:", VIR_NODE_MEMORY_STATS_BUFFERS}, {"Cached:", VIR_NODE_MEMORY_STATS_CACHED}, {NULL, NULL} }; if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) { nr_param = LINUX_NB_MEMORY_STATS_ALL; } else { nr_param = LINUX_NB_MEMORY_STATS_CELL; } if ((*nparams) == 0) { /* Current number of memory stats supported by linux */ *nparams = nr_param; ret = 0; goto cleanup; } if ((*nparams) != nr_param) { nodeReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid stats count")); goto cleanup; } while (fgets(line, sizeof(line), meminfo) != NULL) { char *buf = line; if (STRPREFIX(buf, "Node ")) { /* * /sys/devices/system/node/nodeX/meminfo format is below. * So, skip prefix "Node XX ". * * Node 0 MemTotal: 8386980 kB * Node 0 MemFree: 5300920 kB * : */ char *p; p = buf; for (i = 0; i < 2; i++) { p = strchr(p, ' '); if (p == NULL) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no prefix found")); goto cleanup; } p++; } buf = p; } if (sscanf(buf, "%s %lu kB", meminfo_hdr, &val) < 2) continue; for (j = 0; field_conv[j].meminfo_hdr != NULL; j++) { struct field_conv *convp = &field_conv[j]; if (STREQ(meminfo_hdr, convp->meminfo_hdr)) { virNodeMemoryStatsPtr param = ¶ms[k++]; if (virStrcpyStatic(param->field, convp->field) == NULL) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Field kernel memory too long for destination")); goto cleanup; } param->value = val; found++; break; } } if (found >= nr_param) break; } if (found == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no available memory line found")); goto cleanup; } ret = 0; cleanup: return ret; }
int linuxNodeGetCPUStats(FILE *procstat, int cpuNum, virNodeCPUStatsPtr params, int *nparams) { int ret = -1; char line[1024]; unsigned long long usr, ni, sys, idle, iowait; unsigned long long irq, softirq, steal, guest, guest_nice; char cpu_header[3 + INT_BUFSIZE_BOUND(cpuNum)]; if ((*nparams) == 0) { /* Current number of cpu stats supported by linux */ *nparams = LINUX_NB_CPU_STATS; ret = 0; goto cleanup; } if ((*nparams) != LINUX_NB_CPU_STATS) { nodeReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid parameter count")); goto cleanup; } if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS) { strcpy(cpu_header, "cpu"); } else { snprintf(cpu_header, sizeof(cpu_header), "cpu%d", cpuNum); } while (fgets(line, sizeof(line), procstat) != NULL) { char *buf = line; if (STRPREFIX(buf, cpu_header)) { /* aka logical CPU time */ int i; if (sscanf(buf, "%*s %llu %llu %llu %llu %llu" // user ~ iowait "%llu %llu %llu %llu %llu", // irq ~ guest_nice &usr, &ni, &sys, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice) < 4) { continue; } for (i = 0; i < *nparams; i++) { virNodeCPUStatsPtr param = ¶ms[i]; switch (i) { case 0: /* fill kernel cpu time here */ if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_KERNEL) == NULL) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Field kernel cpu time too long for destination")); goto cleanup; } param->value = (sys + irq + softirq) * TICK_TO_NSEC; break; case 1: /* fill user cpu time here */ if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_USER) == NULL) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Field kernel cpu time too long for destination")); goto cleanup; } param->value = (usr + ni) * TICK_TO_NSEC; break; case 2: /* fill idle cpu time here */ if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_IDLE) == NULL) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Field kernel cpu time too long for destination")); goto cleanup; } param->value = idle * TICK_TO_NSEC; break; case 3: /* fill iowait cpu time here */ if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_IOWAIT) == NULL) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Field kernel cpu time too long for destination")); goto cleanup; } param->value = iowait * TICK_TO_NSEC; break; default: break; /* should not hit here */ } } ret = 0; goto cleanup; } } nodeReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid cpu number")); cleanup: return ret; }
int linuxNodeInfoCPUPopulate(FILE *cpuinfo, const char *sysfs_cpudir, virNodeInfoPtr nodeinfo) { char line[1024]; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; unsigned int cpu; unsigned long core, sock, cur_threads; cpu_set_t core_mask; cpu_set_t socket_mask; int online; nodeinfo->cpus = 0; nodeinfo->mhz = 0; nodeinfo->cores = 0; nodeinfo->nodes = 1; # if HAVE_NUMACTL if (numa_available() >= 0) nodeinfo->nodes = numa_max_node() + 1; # endif if (!virStrcpyStatic(sysfs_path, sysfs_cpudir)) { virReportSystemError(errno, _("cannot copy %s"), sysfs_cpudir); return -1; } /* NB: It is impossible to fill our nodes, since cpuinfo * has no knowledge of NUMA nodes */ /* NOTE: hyperthreads are ignored here; they are parsed out of /sys */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { # if defined(__x86_64__) || \ defined(__amd64__) || \ defined(__i386__) char *buf = line; if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo cpu MHz")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } # elif defined(__powerpc__) || \ defined(__powerpc64__) char *buf = line; if (STRPREFIX(buf, "clock")) { char *p; unsigned int ui; buf += 5; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo cpu MHz")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; /* No other interesting infos are available in /proc/cpuinfo. * However, there is a line identifying processor's version, * identification and machine, but we don't want it to be caught * and parsed in next iteration, because it is not in expected * format and thus lead to error. */ } # else # warning Parser for /proc/cpuinfo needs to be adapted for your architecture # endif } /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the core, socket * thread and topology information from /sys */ cpudir = opendir(sysfs_cpudir); if (cpudir == NULL) { virReportSystemError(errno, _("cannot opendir %s"), sysfs_cpudir); return -1; } CPU_ZERO(&core_mask); CPU_ZERO(&socket_mask); while ((cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; online = cpu_online(cpu); if (online < 0) { closedir(cpudir); return -1; } if (!online) continue; nodeinfo->cpus++; /* Parse core */ core = parse_core(cpu); if (!CPU_ISSET(core, &core_mask)) { CPU_SET(core, &core_mask); nodeinfo->cores++; } /* Parse socket */ sock = parse_socket(cpu); if (!CPU_ISSET(sock, &socket_mask)) { CPU_SET(sock, &socket_mask); nodeinfo->sockets++; } cur_threads = count_thread_siblings(cpu); if (cur_threads == 0) { closedir(cpudir); return -1; } if (cur_threads > nodeinfo->threads) nodeinfo->threads = cur_threads; } if (errno) { virReportSystemError(errno, _("problem reading %s"), sysfs_path); closedir(cpudir); return -1; } closedir(cpudir); /* there should always be at least one cpu, socket and one thread */ if (nodeinfo->cpus == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found")); return -1; } if (nodeinfo->sockets == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); return -1; } if (nodeinfo->threads == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); return -1; } /* nodeinfo->sockets is supposed to be a number of sockets per NUMA node, * however if NUMA nodes are not composed of whole sockets, we just lie * about the number of NUMA nodes and force apps to check capabilities XML * for the actual NUMA topology. */ if (nodeinfo->sockets % nodeinfo->nodes == 0) nodeinfo->sockets /= nodeinfo->nodes; else nodeinfo->nodes = 1; return 0; }
int linuxNodeInfoCPUPopulate(FILE *cpuinfo, const char *sysfs_dir, virNodeInfoPtr nodeinfo) { char line[1024]; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; unsigned int cpu; unsigned long core, sock, cur_threads; cpu_set_t core_mask; cpu_set_t socket_mask; int online; int ret = -1; char *sysfs_cpudir = NULL; unsigned int cpu_cores = 0; nodeinfo->cpus = 0; nodeinfo->mhz = 0; nodeinfo->cores = 0; /* Start with parsing /proc/cpuinfo; although it tends to have * fewer details. Hyperthreads are ignored at this stage. */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { # if defined(__x86_64__) || \ defined(__amd64__) || \ defined(__i386__) char *buf = line; if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } if (STRPREFIX(buf, "cpu cores")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu cores from cpuinfo")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && (*p == '\0' || c_isspace(*p))) cpu_cores = ui; } # elif defined(__powerpc__) || \ defined(__powerpc64__) char *buf = line; if (STRPREFIX(buf, "clock")) { char *p; unsigned int ui; buf += 5; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; /* No other interesting infos are available in /proc/cpuinfo. * However, there is a line identifying processor's version, * identification and machine, but we don't want it to be caught * and parsed in next iteration, because it is not in expected * format and thus lead to error. */ } # else # warning Parser for /proc/cpuinfo needs to be adapted for your architecture # endif } /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the * core, node, socket, thread and topology information from /sys */ if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_dir) < 0) { virReportOOMError(); goto cleanup; } cpudir = opendir(sysfs_cpudir); if (cpudir == NULL) { virReportSystemError(errno, _("cannot opendir %s"), sysfs_cpudir); goto cleanup; } CPU_ZERO(&core_mask); CPU_ZERO(&socket_mask); while ((cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; online = virNodeGetCpuValue(sysfs_cpudir, cpu, "online", true); if (online < 0) { closedir(cpudir); goto cleanup; } if (!online) continue; nodeinfo->cpus++; /* Parse core */ core = virNodeGetCpuValue(sysfs_cpudir, cpu, "topology/core_id", false); if (!CPU_ISSET(core, &core_mask)) { CPU_SET(core, &core_mask); nodeinfo->cores++; } /* Parse socket */ sock = virNodeParseSocket(sysfs_cpudir, cpu); if (!CPU_ISSET(sock, &socket_mask)) { CPU_SET(sock, &socket_mask); nodeinfo->sockets++; } cur_threads = virNodeCountThreadSiblings(sysfs_cpudir, cpu); if (cur_threads == 0) { closedir(cpudir); goto cleanup; } if (cur_threads > nodeinfo->threads) nodeinfo->threads = cur_threads; } if (errno) { virReportSystemError(errno, _("problem reading %s"), sysfs_cpudir); closedir(cpudir); goto cleanup; } if (closedir(cpudir) < 0) { virReportSystemError(errno, _("problem closing %s"), sysfs_cpudir); goto cleanup; } if ((nodeinfo->nodes = virNodeParseNode(sysfs_dir)) <= 0) goto cleanup; /* There should always be at least one cpu, socket, node, and thread. */ if (nodeinfo->cpus == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found")); goto cleanup; } if (nodeinfo->sockets == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); goto cleanup; } if (nodeinfo->threads == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); goto cleanup; } /* Platform like AMD Magny Cours has two NUMA nodes each package, and * the two nodes share the same core ID set, it results in the cores * number calculated from sysfs is not the actual cores number. Use * "cpu cores" in /proc/cpuinfo as the cores number instead in this case. * More details about the problem: * https://www.redhat.com/archives/libvir-list/2012-May/msg00607.html */ if (cpu_cores && (cpu_cores > nodeinfo->cores)) nodeinfo->cores = cpu_cores; /* nodeinfo->sockets is supposed to be a number of sockets per NUMA node, * however if NUMA nodes are not composed of whole sockets, we just lie * about the number of NUMA nodes and force apps to check capabilities XML * for the actual NUMA topology. */ if (nodeinfo->sockets % nodeinfo->nodes == 0) nodeinfo->sockets /= nodeinfo->nodes; else nodeinfo->nodes = 1; ret = 0; cleanup: VIR_FREE(sysfs_cpudir); return ret; }
int linuxNodeInfoCPUPopulate(FILE *cpuinfo, virNodeInfoPtr nodeinfo) { char line[1024]; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; unsigned int cpu; unsigned long cur_threads; int socket; unsigned long long socket_mask = 0; unsigned int remaining; int online; nodeinfo->cpus = 0; nodeinfo->mhz = 0; nodeinfo->cores = 1; nodeinfo->nodes = 1; # if HAVE_NUMACTL if (numa_available() >= 0) nodeinfo->nodes = numa_max_node() + 1; # endif /* NB: It is impossible to fill our nodes, since cpuinfo * has no knowledge of NUMA nodes */ /* NOTE: hyperthreads are ignored here; they are parsed out of /sys */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { char *buf = line; if (STRPREFIX(buf, "processor")) { /* aka a single logical CPU */ buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':') { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo processor")); return -1; } nodeinfo->cpus++; } else if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo cpu MHz")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } else if (STRPREFIX(buf, "cpu cores")) { /* aka cores */ char *p; unsigned int id; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "parsing cpuinfo cpu cores %c", *buf); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &id) == 0 && (*p == '\0' || c_isspace(*p)) && id > nodeinfo->cores) nodeinfo->cores = id; } } if (!nodeinfo->cpus) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no cpus found")); return -1; } /* OK, we've parsed what we can out of /proc/cpuinfo. Get the socket * and thread information from /sys */ remaining = nodeinfo->cpus; cpudir = opendir(CPU_SYS_PATH); if (cpudir == NULL) { virReportSystemError(errno, _("cannot opendir %s"), CPU_SYS_PATH); return -1; } while ((errno = 0), remaining && (cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; online = cpu_online(cpu); if (online < 0) { closedir(cpudir); return -1; } if (!online) continue; remaining--; socket = parse_socket(cpu); if (socket < 0) { closedir(cpudir); return -1; } if (!(socket_mask & (1 << socket))) { socket_mask |= (1 << socket); nodeinfo->sockets++; } cur_threads = count_thread_siblings(cpu); if (cur_threads == 0) { closedir(cpudir); return -1; } if (cur_threads > nodeinfo->threads) nodeinfo->threads = cur_threads; } if (errno) { virReportSystemError(errno, _("problem reading %s"), CPU_SYS_PATH); closedir(cpudir); return -1; } closedir(cpudir); /* there should always be at least one socket and one thread */ if (nodeinfo->sockets == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); return -1; } if (nodeinfo->threads == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); return -1; } return 0; }
int linuxNodeInfoCPUPopulate(FILE *cpuinfo, virNodeInfoPtr nodeinfo, bool need_hyperthreads) { char line[1024]; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; unsigned int cpu; unsigned long cur_threads; int socket; unsigned long long socket_mask = 0; unsigned int remaining; int online; nodeinfo->cpus = 0; nodeinfo->mhz = 0; nodeinfo->cores = 1; nodeinfo->nodes = 1; # if HAVE_NUMACTL if (numa_available() >= 0) nodeinfo->nodes = numa_max_node() + 1; # endif /* NB: It is impossible to fill our nodes, since cpuinfo * has no knowledge of NUMA nodes */ /* NOTE: hyperthreads are ignored here; they are parsed out of /sys */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { char *buf = line; if (STRPREFIX(buf, "processor")) { /* aka a single logical CPU */ buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':') { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo processor")); return -1; } nodeinfo->cpus++; # if defined(__x86_64__) || \ defined(__amd64__) || \ defined(__i386__) } else if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo cpu MHz")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } else if (STRPREFIX(buf, "cpu cores")) { /* aka cores */ char *p; unsigned int id; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, _("parsing cpuinfo cpu cores %c"), *buf); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &id) == 0 && (*p == '\0' || c_isspace(*p)) && id > nodeinfo->cores) nodeinfo->cores = id; # elif defined(__powerpc__) || \ defined(__powerpc64__) } else if (STRPREFIX(buf, "clock")) { char *p; unsigned int ui; buf += 5; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpuinfo cpu MHz")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; # elif defined(__s390__) || \ defined(__s390x__) } else if (STRPREFIX(buf, "# processors")) { char *p; unsigned int ui; buf += 12; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, _("parsing number of processors %c"), *buf); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && (*p == '\0' || c_isspace(*p))) nodeinfo->cpus = ui; /* No other interesting infos are available in /proc/cpuinfo. * However, there is a line identifying processor's version, * identification and machine, but we don't want it to be caught * and parsed in next iteration, because it is not in expected * format and thus lead to error. */ break; # else # warning Parser for /proc/cpuinfo needs to be adapted for your architecture # endif } } if (!nodeinfo->cpus) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no cpus found")); return -1; } if (!need_hyperthreads) return 0; /* OK, we've parsed what we can out of /proc/cpuinfo. Get the socket * and thread information from /sys */ remaining = nodeinfo->cpus; cpudir = opendir(CPU_SYS_PATH); if (cpudir == NULL) { virReportSystemError(errno, _("cannot opendir %s"), CPU_SYS_PATH); return -1; } while ((errno = 0), remaining && (cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; online = cpu_online(cpu); if (online < 0) { closedir(cpudir); return -1; } if (!online) continue; remaining--; socket = parse_socket(cpu); if (socket < 0) { closedir(cpudir); return -1; } if (!(socket_mask & (1 << socket))) { socket_mask |= (1 << socket); nodeinfo->sockets++; } cur_threads = count_thread_siblings(cpu); if (cur_threads == 0) { closedir(cpudir); return -1; } if (cur_threads > nodeinfo->threads) nodeinfo->threads = cur_threads; } if (errno) { virReportSystemError(errno, _("problem reading %s"), CPU_SYS_PATH); closedir(cpudir); return -1; } closedir(cpudir); /* there should always be at least one socket and one thread */ if (nodeinfo->sockets == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); return -1; } if (nodeinfo->threads == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); return -1; } /* nodeinfo->sockets is supposed to be a number of sockets per NUMA node, * however if NUMA nodes are not composed of whole sockets, we just lie * about the number of NUMA nodes and force apps to check capabilities XML * for the actual NUMA topology. */ if (nodeinfo->sockets % nodeinfo->nodes == 0) nodeinfo->sockets /= nodeinfo->nodes; else nodeinfo->nodes = 1; return 0; }