[libvirt] [RFC v4 PATCH 1/5] PowerPC : Use sysfs to gather host topology, in place of /proc/cpuinfo

Prerna Saxena prerna at linux.vnet.ibm.com
Thu Dec 1 18:01:57 UTC 2011


From: Prerna Saxena <prerna at linux.vnet.ibm.com>
Date: Mon, 3 Oct 2011 05:45:30 -0700
Subject: [PATCH 1/5] Use sysfs to gather host topology, in place of /proc/cpuinfo

Libvirt at present depends on /proc/cpuinfo to gather host
details such as CPUs, cores, threads, etc. This is an architecture-
dependent approach. An alternative is to use 'Sysfs', which provides
a platform-agnostic interface to parse host CPU topology.

Signed-off-by: Prerna Saxena <prerna at linux.vnet.ibm.com>
---
 src/nodeinfo.c |  127 ++++++++++++++++++++++----------------------------------
 1 files changed, 50 insertions(+), 77 deletions(-)

diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 6448b79..3b2ecd1 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -30,6 +30,7 @@
 #include <errno.h>
 #include <dirent.h>
 #include <sys/utsname.h>
+#include <sched.h>
 
 #if HAVE_NUMACTL
 # define NUMA_VERSION1_COMPATIBILITY 1
@@ -67,8 +68,8 @@
 
 /* NB, this is not static as we need to call it from the testsuite */
 int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
-                             virNodeInfoPtr nodeinfo,
-                             bool need_hyperthreads);
+                             char *sysfs_cpudir,
+                             virNodeInfoPtr nodeinfo);
 
 static int linuxNodeGetCPUStats(FILE *procstat,
                                 int cpuNum,
@@ -191,23 +192,27 @@ static int parse_socket(unsigned int cpu)
     return ret;
 }
 
+static int parse_core(unsigned int cpu)
+{
+    return get_cpu_value(cpu, "topology/core_id", false);
+}
+
 int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
-                             virNodeInfoPtr nodeinfo,
-                             bool need_hyperthreads)
+                             char *sysfs_cpudir,
+                             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;
+    unsigned long core, socket, cur_threads;
+    cpu_set_t core_mask;
+    cpu_set_t socket_mask;
     int online;
 
     nodeinfo->cpus = 0;
     nodeinfo->mhz = 0;
-    nodeinfo->cores = 1;
+    nodeinfo->cores = 0;
 
     nodeinfo->nodes = 1;
 # if HAVE_NUMACTL
@@ -221,20 +226,10 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
     /* 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")) {
+        if (STRPREFIX(buf, "cpu MHz")) {
             char *p;
             unsigned int ui;
             buf += 9;
@@ -249,24 +244,9 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
                 /* 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")) {
+        if (STRPREFIX(buf, "clock")) {
             char *p;
             unsigned int ui;
             buf += 5;
@@ -281,53 +261,30 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
                 /* 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
+    /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the core, socket
+     * thread and topology information from /sys
      */
-    remaining = nodeinfo->cpus;
-    cpudir = opendir(CPU_SYS_PATH);
+    cpudir = opendir(sysfs_cpudir);
     if (cpudir == NULL) {
-        virReportSystemError(errno, _("cannot opendir %s"), CPU_SYS_PATH);
+        virReportSystemError(errno, _("cannot opendir %s"), sysfs_cpudir);
         return -1;
     }
-    while ((errno = 0), remaining && (cpudirent = readdir(cpudir))) {
+
+    CPU_ZERO(&core_mask);
+    CPU_ZERO(&socket_mask);
+
+    while ((cpudirent = readdir(cpudir))) {
         if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
             continue;
 
@@ -338,15 +295,19 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
         }
         if (!online)
             continue;
-        remaining--;
+        nodeinfo->cpus++;
 
-        socket = parse_socket(cpu);
-        if (socket < 0) {
-            closedir(cpudir);
-            return -1;
+        /* Parse core */
+        core = parse_core(cpu);
+        if (!CPU_ISSET(core, &core_mask)) {
+            CPU_SET(core, &core_mask);
+            nodeinfo->cores++;
         }
-        if (!(socket_mask & (1 << socket))) {
-            socket_mask |= (1 << socket);
+
+        /* Parse socket */
+        socket = parse_socket(cpu);
+        if (!CPU_ISSET(socket, &socket_mask)) {
+            CPU_SET(socket, &socket_mask);
             nodeinfo->sockets++;
         }
 
@@ -367,7 +328,12 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
 
     closedir(cpudir);
 
-    /* there should always be at least one socket and one thread */
+    /* 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"));
@@ -611,13 +577,20 @@ int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
 #ifdef __linux__
     {
     int ret;
+    char *sysfs_cpuinfo;
     FILE *cpuinfo = fopen(CPUINFO_PATH, "r");
     if (!cpuinfo) {
         virReportSystemError(errno,
                              _("cannot open %s"), CPUINFO_PATH);
         return -1;
     }
-    ret = linuxNodeInfoCPUPopulate(cpuinfo, nodeinfo, true);
+
+    if (virAsprintf(&sysfs_cpuinfo, CPU_SYS_PATH) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    ret = linuxNodeInfoCPUPopulate(cpuinfo, sysfs_cpuinfo, nodeinfo);
     VIR_FORCE_FCLOSE(cpuinfo);
     if (ret < 0)
         return -1;
-- 
1.7.3.4



-- 
Prerna Saxena

Linux Technology Centre,
IBM Systems and Technology Lab,
Bangalore, India




More information about the libvir-list mailing list