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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

Version 2 changes:
- -smp argument build split into a separate function
- always add ",sockets=S,cores=C,threads=T" to -smp if qemu supports it
- use qemuParseCommandLineKeywords for command line parsing

Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx>
---
 src/qemu/qemu_conf.c |  159 +++++++++++++++++++++++++++++++++++++++++++++-----
 src/qemu/qemu_conf.h |    3 +-
 2 files changed, 145 insertions(+), 17 deletions(-)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 9f35217..09bbf7a 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;
@@ -1865,6 +1869,39 @@ no_memory:
     goto cleanup;
 }
 
+static char *
+qemudBuildCommandLineSmp(virConnectPtr conn,
+                         const virDomainDefPtr def,
+                         int qemuCmdFlags)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferVSprintf(&buf, "%lu", def->vcpus);
+
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
+        /* sockets, cores, and threads are either all zero
+         * or all non-zero, thus checking one of them is enough */
+        if (def->cpu && def->cpu->sockets) {
+            virBufferVSprintf(&buf, ",sockets=%u", def->cpu->sockets);
+            virBufferVSprintf(&buf, ",cores=%u", def->cpu->cores);
+            virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
+        }
+        else {
+            virBufferVSprintf(&buf, ",sockets=%lu", def->vcpus);
+            virBufferVSprintf(&buf, ",cores=%u", 1);
+            virBufferVSprintf(&buf, ",threads=%u", 1);
+        }
+    }
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError(conn);
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
 
 #define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
@@ -1900,7 +1937,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;
@@ -1914,6 +1950,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
     char uuid[VIR_UUID_STRING_BUFLEN];
     char domid[50];
     char *cpu;
+    char *smp;
 
     uname_normalize(&ut);
 
@@ -2049,7 +2086,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 +2148,13 @@ int qemudBuildCommandLine(virConnectPtr conn,
         ADD_ARG_LIT("-mem-path");
         ADD_ARG_LIT(driver->hugepage_path);
     }
+
+    if (!(smp = qemudBuildCommandLineSmp(conn, def, qemuCmdFlags)))
+        goto error;
+
     ADD_ARG_LIT("-smp");
-    ADD_ARG_LIT(vcpus);
+    ADD_ARG_LIT(smp);
+    VIR_FREE(smp);
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
         ADD_ARG_LIT("-name");
@@ -3740,6 +3781,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,
@@ -3749,10 +3811,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 == ',')
@@ -3796,7 +3856,6 @@ qemuParseCommandLineCPU(virConnectPtr conn,
         }
     } while ((p = next));
 
-    dom->cpu = cpu;
     return 0;
 
 syntax:
@@ -3807,11 +3866,84 @@ syntax:
 no_memory:
     virReportOOMError(conn);
 error:
-    virCPUDefFree(cpu);
     return -1;
 }
 
 
+static int
+qemuParseCommandLineSmp(virConnectPtr conn,
+                        virDomainDefPtr dom,
+                        const char *val)
+{
+    unsigned int sockets = 0;
+    unsigned int cores = 0;
+    unsigned int threads = 0;
+    int i;
+    int nkws;
+    char **kws;
+    char **vals;
+    int n;
+    char *end;
+    int ret;
+
+    nkws = qemuParseCommandLineKeywords(conn, val, &kws, &vals, 1);
+    if (nkws < 0)
+        return -1;
+
+    for (i = 0; i < nkws; i++) {
+        if (vals[i] == NULL) {
+            if (i > 0 ||
+                virStrToLong_i(kws[i], &end, 10, &n) < 0 ||
+                !end || *end != '\0')
+                goto syntax;
+            dom->vcpus = n;
+        } else {
+            if (virStrToLong_i(vals[i], &end, 10, &n) < 0 ||
+                !end || *end != '\0')
+                goto syntax;
+            if (STREQ(kws[i], "sockets"))
+                sockets = n;
+            else if (STREQ(kws[i], "cores"))
+                cores = n;
+            else if (STREQ(kws[i], "threads"))
+                threads = n;
+            else
+                goto syntax;
+        }
+    }
+
+    if (sockets && cores && threads) {
+        virCPUDefPtr cpu;
+
+        if (!(cpu = qemuInitGuestCPU(conn, dom)))
+            goto error;
+        cpu->sockets = sockets;
+        cpu->cores = cores;
+        cpu->threads = threads;
+    } else if (sockets || cores || threads)
+        goto syntax;
+
+    ret = 0;
+
+cleanup:
+    for (i = 0; i < nkws; i++) {
+        VIR_FREE(kws[i]);
+        VIR_FREE(vals[i]);
+    }
+    VIR_FREE(kws);
+    VIR_FREE(vals);
+
+    return ret;
+
+syntax:
+    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("cannot parse CPU topology '%s'"), val);
+error:
+    ret = -1;
+    goto cleanup;
+}
+
+
 /*
  * Analyse the env and argv settings and reconstruct a
  * virDomainDefPtr representing these settings as closely
@@ -3959,14 +4091,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

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]