[libvirt] [PATCH 3/6] util: Introduce virHostCPUGetInfoParseCPUFrequency()

Bjoern Walk bwalk at linux.vnet.ibm.com
Wed Dec 13 07:42:47 UTC 2017


Andrea Bolognani <abologna at redhat.com> [2017-12-11, 05:40PM +0100]:
> The algorithm used to extract the CPU frequency from /proc/cpuinfo
> is the same regardless of architecture, the only difference being
> the label used to identify the relevant field.
> 
> Factor the parsing code out to a new helper and use it to implement
> virHostCPUGetInfoParseCPUInfo(), thus removing some duplication.
> 
> Signed-off-by: Andrea Bolognani <abologna at redhat.com>
> ---
>  src/util/virhostcpu.c | 105 +++++++++++++++++++-------------------------------
>  1 file changed, 40 insertions(+), 65 deletions(-)
> 
> diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
> index 4d5c56659..85803d527 100644
> --- a/src/util/virhostcpu.c
> +++ b/src/util/virhostcpu.c
> @@ -509,6 +509,40 @@ virHostCPUHasValidSubcoreConfiguration(int threads_per_subcore)
>  }
> 
> 
> +static int
> +virHostCPUGetInfoParseCPUFrequency(const char *buf,
> +                                   const char *label,
> +                                   unsigned int *mhz)
> +{
> +    int ret = -1;
> +
> +    if (STRPREFIX(buf, label)) {

I'd prefer negation and early exit to get rid of one indentation level.
I also moved this conditional into the loop below. Save function calls.

> +        char *p;
> +        unsigned int ui;
> +
> +        buf += strlen(label);
> +        while (*buf && c_isspace(*buf))
> +            buf++;
> +
> +        if (*buf != ':' || !buf[1]) {
> +            virReportError(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)))
> +            *mhz = ui;
> +    }
> +
> +    ret = 0;
> +
> + cleanup:
> +    return ret;
> +}
> +
> +
>  static int
>  virHostCPUGetInfoParseCPUInfo(FILE *cpuinfo,
>                                virArch arch,
> @@ -521,73 +555,14 @@ virHostCPUGetInfoParseCPUInfo(FILE *cpuinfo,
> 
>      while (fgets(line, sizeof(line), cpuinfo) != NULL) {
>          if (ARCH_IS_X86(arch)) {

Probably (hopefully?) the compiler can optimize, but I get a bit iffy if
I see a loop invariant conditional inside a loop. I find this also
harder to read.

> -            char *buf = line;
> -            if (STRPREFIX(buf, "cpu MHz")) {
> -                char *p;
> -                unsigned int ui;
> -
> -                buf += 7;
> -                while (*buf && c_isspace(*buf))
> -                    buf++;
> -
> -                if (*buf != ':' || !buf[1]) {
> -                    virReportError(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)))
> -                    *mhz = ui;
> -            }
> +            if (virHostCPUGetInfoParseCPUFrequency(line, "cpu MHz", mhz) < 0)
> +                goto cleanup;
>          } else if (ARCH_IS_PPC(arch)) {
> -            char *buf = line;
> -            if (STRPREFIX(buf, "clock")) {
> -                char *p;
> -                unsigned int ui;
> -
> -                buf += 5;
> -                while (*buf && c_isspace(*buf))
> -                    buf++;
> -
> -                if (*buf != ':' || !buf[1]) {
> -                    virReportError(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)))
> -                    *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. */
> -            }
> +            if (virHostCPUGetInfoParseCPUFrequency(line, "clock", mhz) < 0)
> +                goto cleanup;
>          } else if (ARCH_IS_ARM(arch)) {
> -            char *buf = line;
> -            if (STRPREFIX(buf, "BogoMIPS")) {
> -                char *p;
> -                unsigned int ui;
> -
> -                buf += 8;
> -                while (*buf && c_isspace(*buf))
> -                    buf++;
> -
> -                if (*buf != ':' || !buf[1]) {
> -                    virReportError(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)))
> -                    *mhz = ui;
> -            }
> +            if (virHostCPUGetInfoParseCPUFrequency(line, "BogoMIPS", mhz) < 0)
> +                goto cleanup;
>          } else if (ARCH_IS_S390(arch)) {
>              /* s390x has no realistic value for CPU speed,
>               * assign a value of zero to signify this */
> -- 
> 2.14.3
> 
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
> 

I attach my take on this refactorization for comparison. Feel free to
take stuff you like. Or don't :)

-- 
IBM Systems
Linux on z Systems & Virtualization Development
------------------------------------------------------------------------
IBM Deutschland
Schönaicher Str. 220
71032 Böblingen
Phone: +49 7031 16 1819
E-Mail: bwalk at de.ibm.com
------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzende des Aufsichtsrats: Martina Koederitz
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294 
-------------- next part --------------
From 0a6cda1c0ff218585df811c952b149793f00ca17 Mon Sep 17 00:00:00 2001
From: Bjoern Walk <bwalk at linux.vnet.ibm.com>
Date: Thu, 30 Nov 2017 12:50:47 +0100
Subject: [PATCH 1/4] util: virhostcpu: factor out frequency parsing

All different architectures use the same copy-pasted code to parse
processor frequency information from /proc/cpuinfo. Let's extract that
code into a function to avoid repetition.

We now also tolerate if the parsing of /proc/cpuinfo is not successful
and just report a warning instead of bailing out and abandoning the rest
of the CPU information.

Reviewed-by: Marc Hartmayer <mhartmay at linux.vnet.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy at linux.vnet.ibm.com>
Signed-off-by: Bjoern Walk <bwalk at linux.vnet.ibm.com>
---
 src/util/virhostcpu.c | 136 +++++++++++++++++++++-----------------------------
 1 file changed, 57 insertions(+), 79 deletions(-)

diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index c485a972..0a4b241d 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -508,6 +508,61 @@ virHostCPUHasValidSubcoreConfiguration(int threads_per_subcore)
     return ret;
 }
 
+static int
+virHostCPUParseFrequencyLine(const char *str,
+                             unsigned int *mhz)
+{
+    char *p;
+    unsigned int ui;
+
+    while (*str && c_isspace(*str))
+        str++;
+
+    if (*str != ':' || !str[1]) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("parsing cpu MHz from cpuinfo"));
+        return -1;
+    }
+
+    if (virStrToLong_ui(str + 1, &p, 10, &ui) == 0 &&
+        /* Accept trailing fractional part. */
+        (*p == '\0' || *p == '.' || c_isspace(*p)))
+        *mhz = ui;
+
+    return 0;
+}
+
+static int
+virHostCPUParseFrequency(FILE *cpuinfo,
+                         virArch arch,
+                         unsigned int *mhz)
+{
+    const char *prefix = NULL;
+    char line[1024];
+
+    if (ARCH_IS_X86(arch))
+        prefix = "cpu MHz";
+    else if (ARCH_IS_PPC(arch))
+        prefix = "clock";
+    else if (ARCH_IS_ARM(arch))
+        prefix = "BogoMIPS";
+
+    if (!prefix) {
+        VIR_WARN("Parser for /proc/cpuinfo needs to be adapted for your architecture");
+        return 1;
+    }
+
+    while (fgets(line, sizeof(line), cpuinfo) != NULL) {
+        if (!STRPREFIX(line, prefix))
+            continue;
+
+        if (virHostCPUParseFrequencyLine(line + strlen(prefix), mhz) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
 int
 virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
                                virArch arch,
@@ -520,7 +575,6 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
 {
     virBitmapPtr present_cpus_map = NULL;
     virBitmapPtr online_cpus_map = NULL;
-    char line[1024];
     DIR *nodedir = NULL;
     struct dirent *nodedirent = NULL;
     int nodecpus, nodecores, nodesockets, nodethreads, offline = 0;
@@ -535,84 +589,8 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
     *cpus = *nodes = *sockets = *cores = *threads = 0;
 
     /* Start with parsing CPU clock speed from /proc/cpuinfo */
-    while (fgets(line, sizeof(line), cpuinfo) != NULL) {
-        if (ARCH_IS_X86(arch)) {
-            char *buf = line;
-            if (STRPREFIX(buf, "cpu MHz")) {
-                char *p;
-                unsigned int ui;
-
-                buf += 7;
-                while (*buf && c_isspace(*buf))
-                    buf++;
-
-                if (*buf != ':' || !buf[1]) {
-                    virReportError(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)))
-                    *mhz = ui;
-            }
-        } else if (ARCH_IS_PPC(arch)) {
-            char *buf = line;
-            if (STRPREFIX(buf, "clock")) {
-                char *p;
-                unsigned int ui;
-
-                buf += 5;
-                while (*buf && c_isspace(*buf))
-                    buf++;
-
-                if (*buf != ':' || !buf[1]) {
-                    virReportError(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)))
-                    *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 if (ARCH_IS_ARM(arch)) {
-            char *buf = line;
-            if (STRPREFIX(buf, "BogoMIPS")) {
-                char *p;
-                unsigned int ui;
-
-                buf += 8;
-                while (*buf && c_isspace(*buf))
-                    buf++;
-
-                if (*buf != ':' || !buf[1]) {
-                    virReportError(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)))
-                    *mhz = ui;
-            }
-        } else if (ARCH_IS_S390(arch)) {
-            /* s390x has no realistic value for CPU speed,
-             * assign a value of zero to signify this */
-            *mhz = 0;
-        } else {
-            VIR_WARN("Parser for /proc/cpuinfo needs to be adapted for your architecture");
-            break;
-        }
-    }
+    if (virHostCPUParseFrequency(cpuinfo, arch, mhz) < 0)
+        VIR_WARN("Unable to parse processor frequency information from /proc/cpuinfo");
 
     /* Get information about what CPUs are present in the host and what
      * CPUs are online, so that we don't have to so for each node */
-- 
2.14.3

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 906 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20171213/17f8a7f7/attachment-0001.sig>


More information about the libvir-list mailing list