[libvirt] [PATCH 6/6] qemu: pass numa node binding preferences to qemu

Martin Kletzander mkletzan at redhat.com
Wed Jun 4 14:56:32 UTC 2014


Currently, we only bind the whole QEMU domain to memory nodes
specified in nodemask altogether.  That, however, doesn't make much
sense when one wants to control from where the memory for particular
guest nodes should be allocated.  QEMU allows us to do that by
specifying 'host-nodes' parameter for the 'memory-ram' object, so
let's use that.

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 src/qemu/qemu_cgroup.c                             |  18 ++-
 src/qemu/qemu_command.c                            | 141 +++++++++++++++++++--
 src/qemu/qemu_command.h                            |   3 +-
 src/qemu/qemu_driver.c                             |  12 +-
 src/qemu/qemu_process.c                            |   3 +-
 .../qemuxml2argv-numatune-auto-prefer.xml          |  29 +++++
 .../qemuxml2argv-numatune-auto.args                |   6 +
 .../qemuxml2argv-numatune-auto.xml                 |  26 ++++
 .../qemuxml2argv-numatune-memnode-nocpu.xml        |  25 ++++
 .../qemuxml2argv-numatune-memnodes-problematic.xml |  31 +++++
 .../qemuxml2argv-numatune-memnodes.args            |   8 ++
 .../qemuxml2argv-numatune-memnodes.xml             |  31 +++++
 .../qemuxml2argv-numatune-prefer.args              |   6 +
 .../qemuxml2argv-numatune-prefer.xml               |  29 +++++
 tests/qemuxml2argvtest.c                           |  50 +++++---
 tests/qemuxml2xmltest.c                            |   1 +
 tests/qemuxmlnstest.c                              |   2 +-
 17 files changed, 389 insertions(+), 32 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-nocpu.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes-problematic.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.xml

diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index b1bfb5a..6415a6d 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -23,6 +23,8 @@

 #include <config.h>

+#include "domain_audit.h"
+#include "domain_conf.h"
 #include "qemu_cgroup.h"
 #include "qemu_domain.h"
 #include "qemu_process.h"
@@ -30,7 +32,6 @@
 #include "virlog.h"
 #include "viralloc.h"
 #include "virerror.h"
-#include "domain_audit.h"
 #include "virscsi.h"
 #include "virstring.h"
 #include "virfile.h"
@@ -895,6 +896,7 @@ qemuSetupCgroupForVcpu(virDomainObjPtr vm)
     size_t i, j;
     unsigned long long period = vm->def->cputune.period;
     long long quota = vm->def->cputune.quota;
+    char *mem_mask = NULL;

     if ((period || quota) &&
         !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
@@ -930,8 +932,15 @@ qemuSetupCgroupForVcpu(virDomainObjPtr vm)
                 goto cleanup;
         }

+        if (virDomainGetMemsForGuestCpu(def, i, &mem_mask) < 0)
+            goto cleanup;
+
         /* Set vcpupin in cgroup if vcpupin xml is provided */
         if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
+
+            if (mem_mask && virCgroupSetCpusetMems(cgroup_vcpu, mem_mask) < 0)
+                goto cleanup;
+
             /* find the right CPU to pin, otherwise
              * qemuSetupCgroupVcpuPin will fail. */
             for (j = 0; j < def->cputune.nvcpupin; j++) {
@@ -946,14 +955,21 @@ qemuSetupCgroupForVcpu(virDomainObjPtr vm)

                 break;
             }
+        } else if (mem_mask) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("cgroup cpuset is required for "
+                             "per-node memory binding"));
+            goto cleanup;
         }

+        VIR_FREE(mem_mask);
         virCgroupFree(&cgroup_vcpu);
     }

     return 0;

  cleanup:
+    VIR_FREE(mem_mask);
     if (cgroup_vcpu) {
         virCgroupRemove(cgroup_vcpu);
         virCgroupFree(&cgroup_vcpu);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index cc6023d..8699eea 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6531,21 +6531,99 @@ qemuBuildSmpArgStr(const virDomainDef *def,
     return virBufferContentAndReset(&buf);
 }

+static const char *
+qemuNumaPolicyToString(virDomainNumatuneMemMode mode)
+{
+    const char *policy = NULL;
+
+    switch (mode) {
+    case VIR_DOMAIN_NUMATUNE_MEM_STRICT:
+        policy = "bind";
+        break;
+
+    case VIR_DOMAIN_NUMATUNE_MEM_PREFERRED:
+        policy = "preferred";
+        break;
+
+    case VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE:
+        policy = "interleave";
+        break;
+
+    case VIR_DOMAIN_NUMATUNE_MEM_LAST:
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot translate memory policy"));
+        break;
+    }
+
+    return policy;
+}
+
 static int
-qemuBuildNumaArgStr(const virDomainDef *def, virCommandPtr cmd)
+qemuBuildNumaArgStr(const virDomainDef *def,
+                    virCommandPtr cmd,
+                    virQEMUDriverPtr driver,
+                    virQEMUCapsPtr qemuCaps,
+                    virBitmapPtr autoNodemask)
 {
+    int ret = -1;
     size_t i;
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
     char *cpumask = NULL;
-    int ret = -1;
+    virCapsPtr caps = virQEMUDriverGetCapabilities(driver, false);
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *nodemask = NULL;
+    char *globalNodemask = NULL;
+    const char *globalPolicy = qemuNumaPolicyToString(def->numatune.memory.mode);
+
+    if (!globalPolicy)
+        goto cleanup;
+
+    /*
+     * The @autoNodemask parameter means there is numa placement advise we
+     * should use if possible.  If it's NULL, then we ought to format our
+     * own nodemask from the numatune specification.  Let's hide it from
+     * most of the code in this function for the sake of simplification.
+     */
+    if (autoNodemask || def->numatune.memory.nodemask) {
+
+        if (autoNodemask)
+            globalNodemask = virBitmapFormat(autoNodemask);
+        else
+            globalNodemask = virBitmapFormat(def->numatune.memory.nodemask);
+
+        if (!globalNodemask) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Unable to format nodemask"));
+            goto cleanup;
+        }
+    }

     for (i = 0; i < def->cpu->ncells; i++) {
-        VIR_FREE(cpumask);
+        const char *policy = NULL;
         int cellmem = VIR_DIV_UP(def->cpu->cells[i].mem, 1024);
         def->cpu->cells[i].mem = cellmem * 1024;

-        if (!(cpumask = virBitmapFormat(def->cpu->cells[i].cpumask)))
+        VIR_FREE(nodemask);
+        if (def->numatune.mem_nodes &&
+            def->numatune.mem_nodes[i].specified) {
+            policy = qemuNumaPolicyToString(def->numatune.mem_nodes[i].mode);
+            if (!policy)
+                goto cleanup;
+
+            nodemask = virBitmapFormat(def->numatune.mem_nodes[i].nodemask);
+            if (!nodemask) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("Unable to format nodemask"));
+                goto cleanup;
+            }
+        }
+
+        VIR_FREE(cpumask);
+
+        if (!(cpumask = virBitmapFormat(def->cpu->cells[i].cpumask))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Unable to format nodemask"));
             goto cleanup;
+        }

         if (strchr(cpumask, ',')) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -6554,6 +6632,38 @@ qemuBuildNumaArgStr(const virDomainDef *def, virCommandPtr cmd)
             goto cleanup;
         }

+        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+            virBufferAsprintf(&buf, "memory-ram,size=%dM,id=ram-node%d",
+                              cellmem, def->cpu->cells[i].cellid);
+
+            if (nodemask) {
+                if (strchr(nodemask, ',')) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                   _("disjoint NUMA node ranges are not supported "
+                                     "with this QEMU"));
+                    goto cleanup;
+                }
+
+                virBufferEscape(&buf, ',', ",", ",host-nodes=%s", nodemask);
+                virBufferAsprintf(&buf, ",policy=%s", policy);
+
+            } else if (globalNodemask) {
+
+                if (strchr(globalNodemask, ',')) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                   _("disjoint NUMA node ranges are not supported "
+                                     "with this QEMU"));
+                    goto cleanup;
+                }
+
+                virBufferEscape(&buf, ',', ",", ",host-nodes=%s", globalNodemask);
+                virBufferAsprintf(&buf, ",policy=%s", globalPolicy);
+            }
+
+            virCommandAddArg(cmd, "-object");
+            virCommandAddArgBuffer(cmd, &buf);
+        }
+
         virCommandAddArg(cmd, "-numa");
         virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid);
         virBufferAddLit(&buf, ",cpus=");
@@ -6565,7 +6675,13 @@ qemuBuildNumaArgStr(const virDomainDef *def, virCommandPtr cmd)
          * but when it is, we need a capability bit and
          * translation of our cpumask into the qemu syntax.  */
         virBufferAdd(&buf, cpumask, -1);
-        virBufferAsprintf(&buf, ",mem=%d", cellmem);
+
+        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+            virBufferAsprintf(&buf, ",memdev=ram-node%d",
+                              def->cpu->cells[i].cellid);
+        } else {
+            virBufferAsprintf(&buf, ",mem=%d", cellmem);
+        }

         if (virBufferError(&buf)) {
             virReportOOMError();
@@ -6577,6 +6693,10 @@ qemuBuildNumaArgStr(const virDomainDef *def, virCommandPtr cmd)
     ret = 0;

  cleanup:
+    if (!autoNodemask)
+        VIR_FREE(globalNodemask);
+    VIR_FREE(nodemask);
+    virObjectUnref(caps);
     VIR_FREE(cpumask);
     virBufferFreeAndReset(&buf);
     return ret;
@@ -7215,7 +7335,8 @@ qemuBuildCommandLine(virConnectPtr conn,
                      virDomainSnapshotObjPtr snapshot,
                      virNetDevVPortProfileOp vmop,
                      qemuBuildCommandLineCallbacksPtr callbacks,
-                     bool standalone)
+                     bool standalone,
+                     virBitmapPtr nodemask)
 {
     virErrorPtr originalError = NULL;
     size_t i, j;
@@ -7399,9 +7520,9 @@ qemuBuildCommandLine(virConnectPtr conn,
     virCommandAddArg(cmd, smp);
     VIR_FREE(smp);

-    if (def->cpu && def->cpu->ncells)
-        if (qemuBuildNumaArgStr(def, cmd) < 0)
-            goto error;
+    if (def->cpu && def->cpu->ncells &&
+        qemuBuildNumaArgStr(def, cmd, driver, qemuCaps, nodemask) < 0)
+        goto error;

     if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_UUID))
         virCommandAddArgList(cmd, "-uuid", uuid, NULL);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index afbd6ff..4856d74 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -78,7 +78,8 @@ virCommandPtr qemuBuildCommandLine(virConnectPtr conn,
                                    virDomainSnapshotObjPtr current_snapshot,
                                    virNetDevVPortProfileOp vmop,
                                    qemuBuildCommandLineCallbacksPtr callbacks,
-                                   bool forXMLToArgv)
+                                   bool standalone,
+                                   virBitmapPtr nodemask)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(11);

 /* Generate '-device' string for chardev device */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 545516e..6f138de 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4038,6 +4038,7 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
     pid_t *cpupids = NULL;
     int ncpupids;
     virCgroupPtr cgroup_vcpu = NULL;
+    char *mem_mask = NULL;

     qemuDomainObjEnterMonitor(driver, vm);

@@ -4151,6 +4152,15 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
                         ret = -1;
                         goto cleanup;
                     }
+
+                    if (virDomainGetMemsForGuestCpu(vm->def, i, &mem_mask) < 0)
+                        goto cleanup;
+
+                    if (mem_mask && virCgroupSetCpusetMems(cgroup_vcpu,
+                                                           mem_mask) < 0)
+                        goto cleanup;
+                    VIR_FREE(mem_mask);
+
                 } else {
                     if (virProcessSetAffinity(cpupids[i],
                                               vcpupin->cpumask) < 0) {
@@ -6031,7 +6041,7 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
                                      NULL, -1, NULL,
                                      VIR_NETDEV_VPORT_PROFILE_OP_NO_OP,
                                      &buildCommandLineCallbacks,
-                                     true)))
+                                     true, NULL)))
         goto cleanup;

     ret = virCommandToString(cmd);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d719716..1db9177 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3922,7 +3922,8 @@ int qemuProcessStart(virConnectPtr conn,
     if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig,
                                      priv->monJSON, priv->qemuCaps,
                                      migrateFrom, stdin_fd, snapshot, vmop,
-                                     &buildCommandLineCallbacks, false)))
+                                     &buildCommandLineCallbacks, false,
+                                     nodemask)))
         goto cleanup;

     /* now that we know it is about to start call the hook if present */
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml
new file mode 100644
index 0000000..63f0d1f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml
@@ -0,0 +1,29 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='auto'>1</vcpu>
+  <numatune>
+    <memory mode='preferred'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='65536'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.args
new file mode 100644
index 0000000..7287f4f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.args
@@ -0,0 +1,6 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+QEMU_AUDIO_DRV=none /usr/bin/kvm -S -M pc -m 64 -smp 1 -object \
+memory-ram,size=64M,id=ram-node0,host-nodes=4-5,policy=bind -numa \
+node,nodeid=0,cpus=0,memdev=ram-node0 -nographic -monitor \
+unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -net none \
+-serial none -parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.xml
new file mode 100644
index 0000000..8b9c90d
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto.xml
@@ -0,0 +1,26 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='auto'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='65536'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-nocpu.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-nocpu.xml
new file mode 100644
index 0000000..7b0e248
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-nocpu.xml
@@ -0,0 +1,25 @@
+<domain type='kvm'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <numatune>
+    <memory mode='strict' nodeset='0,2'/>
+    <memnode cellid='0' mode='interleave' nodeset='3'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes-problematic.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes-problematic.xml
new file mode 100644
index 0000000..390f6af
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes-problematic.xml
@@ -0,0 +1,31 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='static'>2</vcpu>
+  <numatune>
+    <memory mode='strict' nodeset='0-2'/>
+    <memnode cellid='0' mode='preferred' nodeset='3'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='32768'/>
+      <cell id='1' cpus='1' memory='32768'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.args
new file mode 100644
index 0000000..47db091
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.args
@@ -0,0 +1,8 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+QEMU_AUDIO_DRV=none /usr/bin/kvm -S -M pc -m 64 -smp 2 -object \
+memory-ram,size=32M,id=ram-node0,host-nodes=3,policy=preferred -numa \
+node,nodeid=0,cpus=0,memdev=ram-node0 -object \
+memory-ram,size=32M,id=ram-node1,host-nodes=0-3,policy=bind -numa \
+node,nodeid=1,cpus=1,memdev=ram-node1 -nographic -monitor \
+unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -net none \
+-serial none -parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.xml
new file mode 100644
index 0000000..18b00d8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnodes.xml
@@ -0,0 +1,31 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='static'>2</vcpu>
+  <numatune>
+    <memory mode='strict' nodeset='0-3'/>
+    <memnode cellid='0' mode='preferred' nodeset='3'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='32768'/>
+      <cell id='1' cpus='1' memory='32768'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.args
new file mode 100644
index 0000000..079930a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.args
@@ -0,0 +1,6 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+QEMU_AUDIO_DRV=none /usr/bin/kvm -S -M pc -m 64 -smp 1 -object \
+memory-ram,size=64M,id=ram-node0,host-nodes=1-2,policy=preferred -numa \
+node,nodeid=0,cpus=0,memdev=ram-node0 -nographic -monitor \
+unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -net none \
+-serial none -parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.xml
new file mode 100644
index 0000000..58cd12c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-prefer.xml
@@ -0,0 +1,29 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <numatune>
+    <memory mode='preferred'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='65536'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index bdea8b0..e851115 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -263,7 +263,8 @@ static int testCompareXMLToArgvFiles(const char *xml,
                                      virQEMUCapsPtr extraFlags,
                                      const char *migrateFrom,
                                      int migrateFd,
-                                     virQemuXML2ArgvTestFlags flags)
+                                     virQemuXML2ArgvTestFlags flags,
+                                     const char *nodemaskStr)
 {
     char *expectargv = NULL;
     int len;
@@ -271,10 +272,15 @@ static int testCompareXMLToArgvFiles(const char *xml,
     int ret = -1;
     virDomainDefPtr vmdef = NULL;
     virDomainChrSourceDef monitor_chr;
-    virConnectPtr conn;
+    virConnectPtr conn = NULL;
     char *log = NULL;
     virCommandPtr cmd = NULL;
     size_t i;
+    virBitmapPtr nodemask = NULL;
+
+    if (nodemaskStr &&
+        virBitmapParse(nodemaskStr, 0, &nodemask, VIR_DOMAIN_CPUMASK_LEN) < 0)
+        goto out;

     if (!(conn = virGetConnect()))
         goto out;
@@ -357,7 +363,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
                                      (flags & FLAG_JSON), extraFlags,
                                      migrateFrom, migrateFd, NULL,
                                      VIR_NETDEV_VPORT_PROFILE_OP_NO_OP,
-                                     &testCallbacks, false))) {
+                                     &testCallbacks, false, nodemask))) {
         if (!virtTestOOMActive() &&
             (flags & FLAG_EXPECT_FAILURE)) {
             ret = 0;
@@ -404,6 +410,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
     ret = 0;

  out:
+    virBitmapFree(nodemask);
     VIR_FREE(log);
     VIR_FREE(expectargv);
     VIR_FREE(actualargv);
@@ -420,6 +427,7 @@ struct testInfo {
     const char *migrateFrom;
     int migrateFd;
     unsigned int flags;
+    const char *nodemask;
 };

 static int
@@ -442,7 +450,7 @@ testCompareXMLToArgvHelper(const void *data)

     result = testCompareXMLToArgvFiles(xml, args, info->extraFlags,
                                        info->migrateFrom, info->migrateFd,
-                                       flags);
+                                       flags, info->nodemask);

  cleanup:
     VIR_FREE(xml);
@@ -532,10 +540,10 @@ mymain(void)
     if (VIR_STRDUP_QUIET(driver.config->spicePassword, "123456") < 0)
         return EXIT_FAILURE;

-# define DO_TEST_FULL(name, migrateFrom, migrateFd, flags, ...)         \
+# define DO_TEST_FULL(name, migrateFrom, migrateFd, flags, nodemask, ...) \
     do {                                                                \
         static struct testInfo info = {                                 \
-            name, NULL, migrateFrom, migrateFd, (flags)                 \
+            name, NULL, migrateFrom, migrateFd, (flags), nodemask       \
         };                                                              \
         if (!(info.extraFlags = virQEMUCapsNew()))                      \
             return EXIT_FAILURE;                                        \
@@ -549,18 +557,18 @@ mymain(void)
     } while (0)

 # define DO_TEST(name, ...)                                             \
-    DO_TEST_FULL(name, NULL, -1, 0, __VA_ARGS__)
+    DO_TEST_FULL(name, NULL, -1, 0, NULL, __VA_ARGS__)

 # define DO_TEST_ERROR(name, ...)                                       \
-    DO_TEST_FULL(name, NULL, -1, FLAG_EXPECT_ERROR, __VA_ARGS__)
+    DO_TEST_FULL(name, NULL, -1, FLAG_EXPECT_ERROR, NULL, __VA_ARGS__)

 # define DO_TEST_FAILURE(name, ...)                                     \
-    DO_TEST_FULL(name, NULL, -1, FLAG_EXPECT_FAILURE, __VA_ARGS__)
+    DO_TEST_FULL(name, NULL, -1, FLAG_EXPECT_FAILURE, NULL, __VA_ARGS__)

 # define DO_TEST_PARSE_ERROR(name, ...)                                 \
     DO_TEST_FULL(name, NULL, -1,                                        \
                  FLAG_EXPECT_PARSE_ERROR | FLAG_EXPECT_ERROR,           \
-                 __VA_ARGS__)
+                 NULL, __VA_ARGS__)

 # define NONE QEMU_CAPS_LAST

@@ -1144,13 +1152,13 @@ mymain(void)
             QEMU_CAPS_PCIDEVICE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
             QEMU_CAPS_PCI_ROMBAR);

-    DO_TEST_FULL("restore-v1", "stdio", 7, 0, QEMU_CAPS_MIGRATE_KVM_STDIO);
-    DO_TEST_FULL("restore-v2", "stdio", 7, 0, QEMU_CAPS_MIGRATE_QEMU_EXEC);
-    DO_TEST_FULL("restore-v2", "exec:cat", 7, 0, QEMU_CAPS_MIGRATE_QEMU_EXEC);
-    DO_TEST_FULL("restore-v2-fd", "stdio", 7, 0, QEMU_CAPS_MIGRATE_QEMU_FD);
-    DO_TEST_FULL("restore-v2-fd", "fd:7", 7, 0, QEMU_CAPS_MIGRATE_QEMU_FD);
-    DO_TEST_FULL("migrate", "tcp:10.0.0.1:5000", -1, 0,
-            QEMU_CAPS_MIGRATE_QEMU_TCP);
+    DO_TEST_FULL("restore-v1", "stdio", 7, 0, NULL, QEMU_CAPS_MIGRATE_KVM_STDIO);
+    DO_TEST_FULL("restore-v2", "stdio", 7, 0, NULL, QEMU_CAPS_MIGRATE_QEMU_EXEC);
+    DO_TEST_FULL("restore-v2", "exec:cat", 7, 0, NULL, QEMU_CAPS_MIGRATE_QEMU_EXEC);
+    DO_TEST_FULL("restore-v2-fd", "stdio", 7, 0, NULL, QEMU_CAPS_MIGRATE_QEMU_FD);
+    DO_TEST_FULL("restore-v2-fd", "fd:7", 7, 0, NULL, QEMU_CAPS_MIGRATE_QEMU_FD);
+    DO_TEST_FULL("migrate", "tcp:10.0.0.1:5000", -1, 0, NULL,
+                 QEMU_CAPS_MIGRATE_QEMU_TCP);

     DO_TEST("qemu-ns", NONE);

@@ -1187,7 +1195,12 @@ mymain(void)
     DO_TEST("cputune", QEMU_CAPS_NAME);
     DO_TEST("cputune-zero-shares", QEMU_CAPS_NAME);
     DO_TEST("numatune-memory", NONE);
+    DO_TEST("numatune-memnodes", QEMU_CAPS_OBJECT_MEMORY_RAM);
+    DO_TEST_PARSE_ERROR("numatune-memnodes-problematic", QEMU_CAPS_OBJECT_MEMORY_RAM);
+    DO_TEST_PARSE_ERROR("numatune-memnode-nocpu", QEMU_CAPS_OBJECT_MEMORY_RAM);
+    DO_TEST_PARSE_ERROR("numatune-auto-prefer", QEMU_CAPS_OBJECT_MEMORY_RAM);
     DO_TEST("numatune-auto-nodeset-invalid", NONE);
+    DO_TEST_FULL("numatune-auto", NULL, -1, 0, "4-5", QEMU_CAPS_OBJECT_MEMORY_RAM);
     DO_TEST("numad", NONE);
     DO_TEST("numad-auto-vcpu-static-numatune", NONE);
     DO_TEST("numad-auto-memory-vcpu-cpuset", NONE);
@@ -1378,6 +1391,9 @@ mymain(void)
     DO_TEST("panic", QEMU_CAPS_DEVICE_PANIC,
             QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);

+    DO_TEST("panic", QEMU_CAPS_DEVICE_PANIC,
+            QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+
     virObjectUnref(driver.config);
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index a446ea1..f1f419a 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -366,6 +366,7 @@ mymain(void)

     DO_TEST_DIFFERENT("cpu-numa1");
     DO_TEST_DIFFERENT("cpu-numa2");
+    DO_TEST("numatune-memnodes");

     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);
diff --git a/tests/qemuxmlnstest.c b/tests/qemuxmlnstest.c
index e8f70d6..ec5eec5 100644
--- a/tests/qemuxmlnstest.c
+++ b/tests/qemuxmlnstest.c
@@ -119,7 +119,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
                                      vmdef, &monitor_chr, json, extraFlags,
                                      migrateFrom, migrateFd, NULL,
                                      VIR_NETDEV_VPORT_PROFILE_OP_NO_OP,
-                                     &testCallbacks, false)))
+                                     &testCallbacks, false, NULL)))
         goto fail;

     if (!virtTestOOMActive()) {
-- 
2.0.0




More information about the libvir-list mailing list