[libvirt] [PATCH] Implement CPU topology support for QEMU driver

Jiri Denemark jdenemar at redhat.com
Tue Jan 12 14:25:42 UTC 2010


QEMU's command line equivalent for the following domain XML fragment
    <vcpus>2</vcpus>
    <cpu ...>
        ...
        <topology sockets='1' cores='2', threads='1'/>
    </cpu>

is

    -smp 2,sockets=1,cores=2,threads=1

This syntax was introduced in QEMU-0.12.

Signed-off-by: Jiri Denemark <jdenemar at redhat.com>
---
 src/qemu/qemu_conf.c |  137 ++++++++++++++++++++++++++++++++++++++++++++------
 src/qemu/qemu_conf.h |    3 +-
 2 files changed, 123 insertions(+), 17 deletions(-)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index d3da776..bc4736a 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1,7 +1,7 @@
 /*
  * qemu_conf.c: QEMU configuration management
  *
- * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -1115,6 +1115,10 @@ static unsigned int qemudComputeCmdFlags(const char *help,
         flags |= QEMUD_CMD_FLAG_CHARDEV;
     if (strstr(help, "-balloon"))
         flags |= QEMUD_CMD_FLAG_BALLOON;
+    if (strstr(help, "cores=") &&
+        strstr(help, "threads=") &&
+        strstr(help, "sockets="))
+        flags |= QEMUD_CMD_FLAG_SMP_TOPOLOGY;
 
     if (version >= 9000)
         flags |= QEMUD_CMD_FLAG_VNC_COLON;
@@ -1900,7 +1904,6 @@ int qemudBuildCommandLine(virConnectPtr conn,
                           const char *migrateFrom) {
     int i;
     char memory[50];
-    char vcpus[50];
     char boot[VIR_DOMAIN_BOOT_LAST];
     struct utsname ut;
     int disableKQEMU = 0;
@@ -2049,7 +2052,6 @@ int qemudBuildCommandLine(virConnectPtr conn,
      * is not supported, then they're out of luck anyway
      */
     snprintf(memory, sizeof(memory), "%lu", def->maxmem/1024);
-    snprintf(vcpus, sizeof(vcpus), "%lu", def->vcpus);
     snprintf(domid, sizeof(domid), "%d", def->id);
 
     ADD_ENV_LIT("LC_ALL=C");
@@ -2112,8 +2114,34 @@ int qemudBuildCommandLine(virConnectPtr conn,
         ADD_ARG_LIT("-mem-path");
         ADD_ARG_LIT(driver->hugepage_path);
     }
+
     ADD_ARG_LIT("-smp");
-    ADD_ARG_LIT(vcpus);
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY) && def->cpu) {
+        virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+        virBufferVSprintf(&buf, "%lu", def->vcpus);
+
+        if (def->cpu->sockets > 0)
+            virBufferVSprintf(&buf, ",sockets=%u", def->cpu->sockets);
+
+        if (def->cpu->cores > 0)
+            virBufferVSprintf(&buf, ",cores=%u", def->cpu->cores);
+
+        if (def->cpu->threads > 0)
+            virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
+
+        if (virBufferError(&buf)) {
+            virBufferFreeAndReset(&buf);
+            goto no_memory;
+        }
+
+        ADD_ARG(virBufferContentAndReset(&buf));
+    }
+    else {
+        char vcpus[50];
+        snprintf(vcpus, sizeof(vcpus), "%lu", def->vcpus);
+        ADD_ARG_LIT(vcpus);
+    }
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
         ADD_ARG_LIT("-name");
@@ -3729,6 +3757,27 @@ error:
 }
 
 
+static virCPUDefPtr
+qemuInitGuestCPU(virConnectPtr conn,
+                 virDomainDefPtr dom)
+{
+    if (!dom->cpu) {
+        virCPUDefPtr cpu;
+
+        if (VIR_ALLOC(cpu) < 0) {
+            virReportOOMError(conn);
+            return NULL;
+        }
+
+        cpu->type = VIR_CPU_TYPE_GUEST;
+        cpu->match = VIR_CPU_MATCH_EXACT;
+        dom->cpu = cpu;
+    }
+
+    return dom->cpu;
+}
+
+
 static int
 qemuParseCommandLineCPU(virConnectPtr conn,
                         virDomainDefPtr dom,
@@ -3738,10 +3787,8 @@ qemuParseCommandLineCPU(virConnectPtr conn,
     const char *p = val;
     const char *next;
 
-    if (VIR_ALLOC(cpu) < 0)
-        goto no_memory;
-
-    cpu->type = VIR_CPU_TYPE_GUEST;
+    if (!(cpu = qemuInitGuestCPU(conn, dom)))
+        goto error;
 
     do {
         if (*p == '\0' || *p == ',')
@@ -3785,7 +3832,6 @@ qemuParseCommandLineCPU(virConnectPtr conn,
         }
     } while ((p = next));
 
-    dom->cpu = cpu;
     return 0;
 
 syntax:
@@ -3796,7 +3842,71 @@ syntax:
 no_memory:
     virReportOOMError(conn);
 error:
-    virCPUDefFree(cpu);
+    return -1;
+}
+
+
+static int
+qemuParseCommandLineSmp(virConnectPtr conn,
+                        virDomainDefPtr dom,
+                        const char *val)
+{
+    const char *p = val;
+    const char *next;
+    const char *const options[] = { "sockets=", "cores=", "threads=" };
+    unsigned int topology[] = { 0, 0, 0 };
+    char *end;
+
+    do {
+        if (*p == '\0' || *p == ',')
+            goto syntax;
+
+        if ((next = strchr(p, ',')))
+            next++;
+
+        if (c_isdigit(*p)) {
+            int n;
+            if (virStrToLong_i(p, &end, 10, &n) < 0 ||
+                !end || (*end != ',' && *end != '\0'))
+                goto syntax;
+            dom->vcpus = n;
+        } else {
+            int i;
+            int n = -1;
+            for (i = 0; i < ARRAY_CARDINALITY(options); i++) {
+                if (STRPREFIX(p, options[i])) {
+                    p += strlen(options[i]);
+                    if (virStrToLong_i(p, &end, 10, &n) < 0 ||
+                        !end || (*end != ',' && *end != '\0'))
+                        goto syntax;
+                    topology[i] = n;
+                    break;
+                }
+            }
+
+            if (n < 0)
+                goto syntax;
+        }
+    } while ((p = next));
+
+    if (topology[0] && topology[1] && topology[2]) {
+        virCPUDefPtr cpu;
+
+        if (!(cpu = qemuInitGuestCPU(conn, dom)))
+            goto error;
+
+        cpu->sockets = topology[0];
+        cpu->cores = topology[1];
+        cpu->threads = topology[2];
+    } else if (topology[0] || topology[1] || topology[2])
+        goto syntax;
+
+    return 0;
+
+syntax:
+    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("cannot parse CPU topology '%s'"), val);
+error:
     return -1;
 }
 
@@ -3948,14 +4058,9 @@ virDomainDefPtr qemuParseCommandLine(virConnectPtr conn,
             }
             def->memory = def->maxmem = mem * 1024;
         } else if (STREQ(arg, "-smp")) {
-            int vcpus;
             WANT_VALUE();
-            if (virStrToLong_i(val, NULL, 10, &vcpus) < 0) {
-                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \
-                                 _("cannot parse CPU count '%s'"), val);
+            if (qemuParseCommandLineSmp(conn, def, val) < 0)
                 goto error;
-            }
-            def->vcpus = vcpus;
         } else if (STREQ(arg, "-uuid")) {
             WANT_VALUE();
             if (virUUIDParse(val, def->uuid) < 0) {
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 82254ca..3f74cc9 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -1,7 +1,7 @@
 /*
  * qemu_conf.h: QEMU configuration management
  *
- * Copyright (C) 2006, 2007, 2009 Red Hat, Inc.
+ * Copyright (C) 2006, 2007, 2009, 2010 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -78,6 +78,7 @@ enum qemud_cmd_flags {
     QEMUD_CMD_FLAG_ENABLE_KVM    = (1 << 23), /* Is the -enable-kvm flag available to "enable KVM full virtualization support" */
     QEMUD_CMD_FLAG_MONITOR_JSON  = (1 << 24), /* JSON mode for monitor */
     QEMUD_CMD_FLAG_BALLOON       = (1 << 25), /* -balloon available */
+    QEMUD_CMD_FLAG_SMP_TOPOLOGY  = (1 << 26), /* Is sockets=s,cores=c,threads=t available for -smp? */
 };
 
 /* Main driver state */
-- 
1.6.6




More information about the libvir-list mailing list