[libvirt] [RFC PATCH 1/4] powerpc: Use Sysfs to gather host info

Daniel P. Berrange berrange at redhat.com
Mon Oct 10 09:55:46 UTC 2011


On Sat, Oct 08, 2011 at 12:07:08AM +0530, Prerna Saxena wrote:
> Libvirt presently depends on /proc/cpuinfo to gather information about
> the x86 host. Parsing of /proc/cpuinfo is arch-specific; the
> information fields are also not consistent.
> A cleaner way would be to use Sysfs. Both x86 and PowerPC specific
> information can be obtained from sysfs with different arch specific
> parsing routines.
> 
> ---
>  src/nodeinfo.c |  106 +++++++++++++++++++-------------------------------------
>  1 files changed, 36 insertions(+), 70 deletions(-)
> 
> diff --git a/src/nodeinfo.c b/src/nodeinfo.c
> index 6448b79..cdd339d 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
> @@ -191,6 +192,11 @@ 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)
> @@ -199,15 +205,14 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
>      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);
>      if (cpudir == NULL) {
>          virReportSystemError(errno, _("cannot opendir %s"), CPU_SYS_PATH);
>          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"));


I checked the output of 'virsh nodeinfo' before and after this patch on
RHEL5 and RHEL-6 hosts, and it did not change.

When building, however, you get a compiele warning about the unused
parameter 'need_hyperthreads'.  How come this was needed before, but
is not used anymore ?  If it is redundant, you should remove the
parameter entirely.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list