]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
* src/xend_internal.c: update to cpuset parsing code for NUMA
authorDaniel Veillard <veillard@redhat.com>
Mon, 22 Oct 2007 13:06:15 +0000 (13:06 +0000)
committerDaniel Veillard <veillard@redhat.com>
Mon, 22 Oct 2007 13:06:15 +0000 (13:06 +0000)
Daniel

ChangeLog
src/xend_internal.c

index 35128a36ad462f18aa3232fbe4e030b1ba00ea0c..af02d845da8cd5ba25da560e7e5df6a3e4aea4c5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Mon Oct 22 15:05:30 CEST 2007 Daniel Veillard <veillard@redhat.com>
+
+       * src/xend_internal.c: update to cpuset parsing code for NUMA
+
 Fri Oct 19 17:08:08 CEST 2007 Daniel Veillard <veillard@redhat.com>
 
        * src/Makefile.am: fix tst build rule
index 55dc9986a6186fb8a4544c0c656be40126bb68eb..142835fc4d9707913a87a1ac75f0f22d077c38ec 100644 (file)
@@ -1896,24 +1896,349 @@ sexpr_to_xend_node_info(struct sexpr *root, virNodeInfoPtr info)
 }
 
 /**
- * getNumber:
- * @pointer: pointer to string beginning with  numerical characters
- * @result: pointer to integer for storing the numerical result
+ * skipSpaces:
+ * @str: pointer to the char pointer used
  *
- * Internal routine extracting a number from the beginning of a string
+ * Skip potential blanks, this includes space tabs, line feed,
+ * carriage returns and also '\\' which can be erronously emitted
+ * by xend
+ */
+static void
+skipSpaces(const char **str) {
+    const char *cur = *str;
+
+    while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
+           (*cur == '\r') || (*cur == '\\')) cur++;
+    *str = cur;
+}
+
+/**
+ * parseNumber:
+ * @str: pointer to the char pointer used
  *
- * Returns the number of characters that were extracted as digits
- * or -1 if no digits were found.
+ * Parse a number
+ *
+ * Returns the CPU number or -1 in case of error. @str will be
+ *         updated to skip the number.
  */
 static int
-getNumber (const char * pointer, int * result) {
-    int len = 0;
-    while (isdigit(*(pointer + len)))
-        len++;
-    if (len == 0)
-        return -1;
-    *(result) = atoi(pointer);
-    return (len);
+parseNumber(const char **str) {
+    int ret = 0;
+    const char *cur = *str;
+
+    if ((*cur < '0') || (*cur > '9'))
+        return(-1);
+
+    while ((*cur >= '0') && (*cur <= '9')) {
+        ret = ret * 10 + (*cur - '0');
+       cur++;
+    }
+    *str = cur;
+    return(ret);
+}
+
+/**
+ * parseCpuNumber:
+ * @str: pointer to the char pointer used
+ * @maxcpu: maximum CPU number allowed
+ *
+ * Parse a CPU number
+ *
+ * Returns the CPU number or -1 in case of error. @str will be
+ *         updated to skip the number.
+ */
+static int
+parseCpuNumber(const char **str, int maxcpu) {
+    int ret = 0;
+    const char *cur = *str;
+
+    if ((*cur < '0') || (*cur > '9'))
+        return(-1);
+
+    while ((*cur >= '0') && (*cur <= '9')) {
+        ret = ret * 10 + (*cur - '0');
+       if (ret > maxcpu)
+           return(-1);
+       cur++;
+    }
+    *str = cur;
+    return(ret);
+}
+
+#if 0 /* Not used yet */
+/**
+ * saveCpuSet:
+ * @conn: connection
+ * @cpuset: pointer to a char array for the CPU set
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Serialize the cpuset to a string
+ *
+ * Returns the new string NULL in case of error. The string need to be
+ *         freed by the caller.
+ */
+static char *
+saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) 
+{
+    virBufferPtr buf;
+    char *ret;
+    int start, cur;
+    int first = 1;
+
+    if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000))
+        return(NULL);
+
+    buf = virBufferNew(1000);
+    if (buf == NULL) {
+       virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"));
+       return(NULL);
+    }
+    cur = 0;
+    start = -1;
+    while (cur < maxcpu) {
+        if (cpuset[cur]) {
+           if (start == -1)
+               start = cur;
+       } else if (start != -1) {
+           if (!first)
+               virBufferAdd(buf, ",", -1);
+            else
+               first = 0;
+           if (cur == start + 1) 
+               virBufferVSprintf(buf, "%d", start);
+           else if (cur == start + 2)
+               virBufferVSprintf(buf, "%d,%d", start, cur - 1);
+           else 
+               virBufferVSprintf(buf, "%d-%d", start, cur - 1);
+           start = -1;
+       }
+       cur++;
+    }
+    if (start != -1) {
+       if (!first)
+           virBufferAdd(buf, ",", -1);
+       if (maxcpu == start + 1) 
+           virBufferVSprintf(buf, "%d", start);
+       else if (maxcpu == start + 2)
+           virBufferVSprintf(buf, "%d,%d", start, maxcpu - 1);
+       else 
+           virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1);
+    }
+    ret = virBufferContentAndFree(buf);
+    return(ret);
+}
+#endif
+
+/**
+ * parseCpuSet:
+ * @str: pointer to a CPU set string pointer
+ * @sep: potential character used to mark the end of string if not 0
+ * @cpuset: pointer to a char array for the CPU set
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
+ * to 1, and 0 otherwise. The syntax allows coma separated entries each
+ * can be either a CPU number, ^N to unset that CPU or N-M for ranges.
+ *
+ * Returns the number of CPU found in that set, or -1 in case of error.
+ *         @cpuset is modified accordingly to the value parsed.
+ *         @str is updated to the end of the part parsed
+ */
+static int
+parseCpuSet(virConnectPtr conn, const char **str, char sep, char *cpuset,
+            int maxcpu)
+{
+    const char *cur;
+    int ret = 0;
+    int i, start, last;
+    int neg = 0;
+
+    if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000))
+        return(-1);
+
+    cur = *str;
+    skipSpaces(&cur);
+    if (*cur == 0)
+        goto parse_error;
+
+    /* initialize cpumap to all 0s */
+    for (i = 0;i < maxcpu;i++)
+       cpuset[i] = 0;
+    ret = 0;
+
+    while ((*cur != 0) && (*cur != sep)) {
+       /*
+        * 3 constructs are allowed:
+        *     - N   : a single CPU number
+        *     - N-M : a range of CPU numbers with N < M
+        *     - ^N  : remove a single CPU number from the current set
+        */
+       if (*cur == '^') {
+           cur++;
+           neg = 1;
+       }
+           
+       if ((*cur < '0') || (*cur > '9'))
+          goto parse_error;
+       start = parseCpuNumber(&cur, maxcpu);
+       if (start < 0)
+          goto parse_error;
+       skipSpaces(&cur);
+       if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
+           if (neg) {
+               if (cpuset[start] == 1) {
+                   cpuset[start] = 0;
+                   ret--;
+               }
+           } else {
+               if (cpuset[start] == 0) {
+                   cpuset[start] = 1;
+                   ret++;
+               }
+           }
+       } else if (*cur == '-') {
+           if (neg)
+               goto parse_error;
+           cur++;
+           skipSpaces(&cur);
+           last = parseCpuNumber(&cur, maxcpu);
+           if (last < start)
+               goto parse_error;
+            for (i = start;i <= last;i++) {
+               if (cpuset[i] == 0) {
+                   cpuset[i] = 1;
+                   ret++;
+               }
+           }
+           skipSpaces(&cur);
+       }
+       if (*cur == ',') {
+           cur++;
+           skipSpaces(&cur);
+           neg = 0;
+       } else if ((*cur == 0) || (*cur == sep)) {
+           break;
+       } else
+           goto parse_error;
+    }
+    *str = cur;
+    return(ret);
+
+parse_error:
+    virXendError(conn, VIR_ERR_XEN_CALL,
+                 _("topology cpuset syntax error"));
+    return(-1);
+}
+
+
+/**
+ * parseXenCpuTopology:
+ * @xml: XML output buffer
+ * @str: the topology string 
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Parse a Xend CPU topology string and build the associated XML
+ * format.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+parseTopology(virConnectPtr conn, virBufferPtr xml, const char *str,
+              int maxcpu)
+{
+    const char *cur;
+    char *cpuset = NULL;
+    int cell, cpu, nb_cpus;
+    int ret;
+
+    if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu >100000))
+        return(-1);
+
+    cpuset = malloc(maxcpu * sizeof(char));
+    if (cpuset == NULL)
+        goto memory_error;
+
+    cur = str;
+    while (*cur != 0) {
+        /*
+        * Find the next NUMA cell described in the xend output
+        */
+        cur = strstr(cur, "node");
+       if (cur == NULL)
+           break;
+       cur += 4;
+        cell = parseNumber(&cur);
+       if (cell < 0)
+           goto parse_error;
+       skipSpaces(&cur);
+       if (*cur != ':')
+           goto parse_error;
+       cur++;
+       skipSpaces(&cur);
+       if (!strncmp (cur, "no cpus", 7)) {
+           nb_cpus = 0;
+           for (cpu = 0;cpu < maxcpu;cpu++)
+               cpuset[cpu] = 0;
+       } else {
+           nb_cpus = parseCpuSet(conn, &cur, 'n', cpuset, maxcpu);
+           if (nb_cpus < 0)
+               goto error;
+       }
+
+       /*
+        * add xml for all cpus associated with that cell
+        */
+        ret = virBufferVSprintf (xml, "\
+      <cell id='%d'>\n\
+        <cpus num='%d'>\n", cell, nb_cpus);
+#ifdef STANDALONE
+        {
+           char *dump;
+
+           dump = saveCpuSet(conn, cpuset, maxcpu);
+           if (dump != NULL) {
+               virBufferVSprintf (xml, "           <dump>%s</dump>\n", dump);
+               free(dump);
+           } else {
+               virBufferVSprintf (xml, "           <error>%s</error>\n",
+                                  "Failed to dump CPU set");
+           }
+        }
+#endif
+       if (ret < 0)
+           goto memory_error;
+       for (cpu = 0;cpu < maxcpu;cpu++) {
+           if (cpuset[cpu] == 1) {
+               ret = virBufferVSprintf (xml, "\
+           <cpu id='%d'/>\n", cpu);
+               if (ret < 0)
+                   goto memory_error;
+           }
+       }
+       ret = virBufferAdd (xml, "\
+        </cpus>\n\
+      </cell>\n", -1);
+        if (ret < 0)
+           goto memory_error;
+        
+    }
+    free(cpuset);
+    return(0);
+
+parse_error:
+    virXendError(conn, VIR_ERR_XEN_CALL,
+                 _("topology syntax error"));
+error:
+    if (cpuset != NULL)
+        free(cpuset);
+
+    return(-1);
+
+memory_error:
+    if (cpuset != NULL)
+        free(cpuset);
+    virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"));
+    return(-1);
 }
 
 /**
@@ -1929,21 +2254,9 @@ static int
 sexpr_to_xend_topology_xml(virConnectPtr conn, struct sexpr *root, virBufferPtr xml)
 {
     const char *nodeToCpu;
-    const char *offset;
-    int cellNum;
     int numCells = 0;
     int numCpus;
-    int cellCpuCount = 0; 
-    int nodeCpuCount = 0; 
-    int start; 
-    int finish;
     int r;
-    int i;
-    int len; 
-    int cpuNum; 
-    int *cpuIdsPtr = NULL; 
-    int *iCpuIdsPtr = NULL;
-    char next;
 
     nodeToCpu = sexpr_node(root, "node/node_to_cpu");
     if (nodeToCpu == NULL) {
@@ -1955,134 +2268,21 @@ sexpr_to_xend_topology_xml(virConnectPtr conn, struct sexpr *root, virBufferPtr
     numCells = sexpr_int(root, "node/nr_nodes");
     numCpus = sexpr_int(root, "node/nr_cpus");
 
-    /* array for holding all cpu numbers associated with a single cell. 
-     * Should never need more than numCpus (which is total number of 
-     * cpus for the node) 
-     */
-    cpuIdsPtr = iCpuIdsPtr = malloc(numCpus * sizeof(int));
-    if (cpuIdsPtr == NULL) {
-        goto vir_buffer_failed;
-    }
-
     /* start filling in xml */
     r = virBufferVSprintf (xml,
                                "\
   <topology>\n\
     <cells num='%d'>\n",
                            numCells);
-    if (r == -1) goto vir_buffer_failed;
-
-    offset = nodeToCpu;
-    /* now iterate through all cells and find associated cpu ids */
-    /* example of string being parsed: "node0:0-3,7,9-10\n   node1:11-14\n" */
-    while ((offset = strstr(offset, "node")) != NULL) {
-        cpuIdsPtr = iCpuIdsPtr;
-        cellCpuCount = 0;
-        offset +=4;
-        if ((len = getNumber(offset, &cellNum)) < 0) {
-            virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
-            goto error;
-        }
-        offset += len;
-        if (*(offset) != ':') {
-            virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
-            goto error;
-        }
-        offset++;
-        /* get list of cpus associated w/ single cell */
-        while (1) {
-            len = getNumber(offset, &cpuNum);
-            if (len < 0) {
-                if (!strncmp (offset, "no cpus", 7)){
-                    *(cpuIdsPtr++) = -1;
-                    break;
-                } else {
-                    virXendError(conn, VIR_ERR_XEN_CALL, "topology string syntax error");
-                    goto error;
-                }
-            }
-            offset += len;
-            next = *(offset);
-            if (next == '-') {
-                offset++;
-                start = cpuNum;
-                if ((len = getNumber(offset, &finish)) < 0) {
-                    virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
-                    goto error;
-                }
-                if (start > finish) {
-                    virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
-                    goto error;
-
-                }
-                for (i=start; i<=finish; i++) {
-                    nodeCpuCount++;
-                    if (nodeCpuCount > numCpus) {
-                        virXendError(conn, VIR_ERR_XEN_CALL, 
-                                     "conflicting cpu counts");
-                        goto error;
-                    }
-                    *(cpuIdsPtr++) = i;
-                    cellCpuCount++;
-                }
-                offset += len;
-                next = *(offset);
-                offset++;
-                if (next == ',') {
-                    continue;
-                } else if ((next == '\\') || (next =='\0')) {
-                    break;
-                } else {
-                    virXendError(conn, VIR_ERR_XEN_CALL, 
-                                 " topology string syntax error");
-                    goto error;
-                }
-            } else {
-                /* add the single number */
-                if (nodeCpuCount >= numCpus) {
-                    virXendError(conn, VIR_ERR_XEN_CALL, 
-                                 "conflicting cpu counts");
-                    goto error;
-                }
-                *(cpuIdsPtr++) = cpuNum;
-                cellCpuCount++;
-                nodeCpuCount++;
-                if (next == ',') {
-                    offset++;
-                    continue;
-                } else if ((next == '\\') || (next =='\0')) {
-                    break;
-                } else {
-                    virXendError(conn, VIR_ERR_XEN_CALL, 
-                                 " topology string syntax error");
-                    goto error;
-                }
-            }
-        }    
+    if (r < 0) goto vir_buffer_failed;
 
-        /* add xml for all cpus associated with one cell */
-        r = virBufferVSprintf (xml, "\
-      <cell id='%d'>\n\
-        <cpus num='%d'>\n", cellNum, cellCpuCount);
-        if (r == -1) goto vir_buffer_failed;
+    r = parseTopology(conn, xml, nodeToCpu, numCpus);
+    if (r < 0) goto error;
 
-        for (i = 0; i < cellCpuCount; i++) {
-            if (*(iCpuIdsPtr + i) == -1)
-                break;
-            r = virBufferVSprintf (xml, "\
-           <cpu id='%d'/>\n", *(iCpuIdsPtr + i));
-        if (r == -1) goto vir_buffer_failed;
-        }
-        r = virBufferAdd (xml, "\
-        </cpus>\n\
-      </cell>\n", -1);
-        if (r == -1) goto vir_buffer_failed;
-    }            
     r = virBufferAdd (xml, "\
     </cells>\n\
   </topology>\n", -1);
-    if (r == -1) goto vir_buffer_failed;
-    free(iCpuIdsPtr);
+    if (r < 0) goto vir_buffer_failed;
     return (0);
     
 
@@ -2090,8 +2290,6 @@ vir_buffer_failed:
     virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate new buffer"));
         
 error:
-    if (iCpuIdsPtr)
-        free(iCpuIdsPtr);
     return (-1);
 }