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

Martin Kletzander mkletzan at redhat.com
Wed May 28 09:48:36 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/conf/domain_conf.c                             |   2 +-
 src/qemu/qemu_cgroup.c                             |   2 +
 src/qemu/qemu_command.c                            | 141 +++++++++++++++++++--
 src/qemu/qemu_command.h                            |   3 +-
 src/qemu/qemu_driver.c                             |   6 +-
 src/qemu/qemu_process.c                            |   3 +-
 .../qemuxml2argv-numatune-auto-prefer.args         |   6 +
 .../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 +-
 19 files changed, 373 insertions(+), 34 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.args
 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/conf/domain_conf.c b/src/conf/domain_conf.c
index 4818cfb..b77914e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -17524,7 +17524,7 @@ virDomainDefFormatInternal(virDomainDefPtr def,
                 goto error;
             }
             virBufferAsprintf(buf,
-                              "<memnode nodeid='%zu' mode='%s' nodeset='%s'/>\n",
+                              "<memnode cellid='%zu' mode='%s' nodeset='%s'/>\n",
                               i, mode, nodemask);
             VIR_FREE(nodemask);
         }
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index b1bfb5a..ce03a4f 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -588,6 +588,8 @@ qemuSetupCpusetCgroup(virDomainObjPtr vm,
     if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET))
         return 0;

+    /* ASDF: per-node pinnings are not reflected here */
+
     if ((vm->def->numatune.memory.nodemask ||
          (vm->def->numatune.memory.placement_mode ==
           VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO)) &&
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9e674a2..a913101 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++) {
+        const char *policy = NULL;
+        int cellmem = VIR_DIV_UP(def->cpu->cells[i].mem, 1024);
+
+        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);
-        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)))
+        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)) {
+            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)) {
+            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 d838ad2..197f13c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5987,7 +5987,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);
@@ -8613,8 +8613,8 @@ qemuDomainSetNumaParamsLive(virDomainObjPtr vm,
         goto cleanup;
     }

-    for (i = 0; i < def->numatune->nmem_nodes; i++) {
-        if (def->numatune->mem_nodes[i].specified) {
+    for (i = 0; i < vm->def->numatune.nmem_nodes; i++) {
+        if (vm->def->numatune.mem_nodes[i].specified) {
             virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("change of nodeset for running domain "
                              "with per guest NUMA node numatune settings "
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 124fe28..46d0010 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3910,7 +3910,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.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.args
new file mode 100644
index 0000000..d797088
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-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 -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-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..ecc0b43 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);
+    DO_TEST_PARSE_ERROR("numatune-memnodes-problematic", QEMU_CAPS_OBJECT_MEMORY);
+    DO_TEST_PARSE_ERROR("numatune-memnode-nocpu", QEMU_CAPS_OBJECT_MEMORY);
+    DO_TEST("numatune-auto-prefer", QEMU_CAPS_OBJECT_MEMORY);
     DO_TEST("numatune-auto-nodeset-invalid", NONE);
+    DO_TEST_FULL("numatune-auto", NULL, -1, 0, "4-5", QEMU_CAPS_OBJECT_MEMORY);
     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()) {
--
1.9.3




More information about the libvir-list mailing list