[libvirt] [PATCH v2 14/16] qemu: pass numa node binding preferences to qemu

Martin Kletzander mkletzan at redhat.com
Tue Jul 8 11:50:29 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-backend-ram' object,
so let's use that.

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 src/qemu/qemu_command.c                            | 59 +++++++++++++++++++++-
 .../qemuxml2argv-numatune-memnode-no-memory.args   |  8 +++
 .../qemuxml2argv-numatune-memnode.args             | 11 ++++
 .../qemuxml2argv-numatune-memnode.xml              | 14 ++---
 tests/qemuxml2argvtest.c                           |  7 +++
 5 files changed, 92 insertions(+), 7 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 284664b..fc3406e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -150,6 +150,11 @@ VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
               NULL,
               NULL);

+VIR_ENUM_DECL(qemuNumaPolicy)
+VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
+              "bind",
+              "preferred",
+              "interleave");

 /**
  * qemuPhysIfaceConnect:
@@ -6373,13 +6378,23 @@ qemuBuildNumaArgStr(const virDomainDef *def,
     size_t i;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     char *cpumask = NULL, *tmpmask = NULL, *next = NULL;
+    char *nodemask = NULL;
     int ret = -1;

+    if (virDomainNumatuneHasPerNodeBinding(def->numatune) &&
+        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Per-node memory binding is not supported "
+                         "with this QEMU"));
+        goto cleanup;
+    }
+
     for (i = 0; i < def->cpu->ncells; i++) {
         int cellmem = VIR_DIV_UP(def->cpu->cells[i].mem, 1024);
         def->cpu->cells[i].mem = cellmem * 1024;

         VIR_FREE(cpumask);
+        VIR_FREE(nodemask);

         if (!(cpumask = virBitmapFormat(def->cpu->cells[i].cpumask)))
             goto cleanup;
@@ -6392,6 +6407,43 @@ qemuBuildNumaArgStr(const virDomainDef *def,
             goto cleanup;
         }

+        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+            virDomainNumatuneMemMode mode;
+            const char *policy = NULL;
+
+            mode = virDomainNumatuneGetMode(def->numatune, i);
+            policy = qemuNumaPolicyTypeToString(mode);
+
+            virBufferAsprintf(&buf, "memory-backend-ram,size=%dM,id=ram-node%zu",
+                              cellmem, i);
+
+            if (virDomainNumatuneMaybeFormatNodeset(def->numatune, NULL,
+                                                    &nodemask, i) < 0)
+                goto cleanup;
+
+            if (nodemask) {
+                if (strchr(nodemask, ',') &&
+                    !virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA)) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                   _("disjoint NUMA node ranges are not supported "
+                                     "with this QEMU"));
+                    goto cleanup;
+                }
+
+                for (tmpmask = nodemask; tmpmask; tmpmask = next) {
+                    if ((next = strchr(tmpmask, ',')))
+                        *(next++) = '\0';
+                    virBufferAddLit(&buf, ",host-nodes=");
+                    virBufferAdd(&buf, tmpmask, -1);
+                }
+
+                virBufferAsprintf(&buf, ",policy=%s", policy);
+            }
+
+            virCommandAddArg(cmd, "-object");
+            virCommandAddArgBuffer(cmd, &buf);
+        }
+
         virCommandAddArg(cmd, "-numa");
         virBufferAsprintf(&buf, "node,nodeid=%zu", i);

@@ -6402,7 +6454,11 @@ qemuBuildNumaArgStr(const virDomainDef *def,
             virBufferAdd(&buf, tmpmask, -1);
         }

-        virBufferAsprintf(&buf, ",mem=%d", cellmem);
+        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+            virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+        } else {
+            virBufferAsprintf(&buf, ",mem=%d", cellmem);
+        }

         virCommandAddArgBuffer(cmd, &buf);
     }
@@ -6410,6 +6466,7 @@ qemuBuildNumaArgStr(const virDomainDef *def,

  cleanup:
     VIR_FREE(cpumask);
+    VIR_FREE(nodemask);
     virBufferFreeAndReset(&buf);
     return ret;
 }
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args
new file mode 100644
index 0000000..b0e274c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.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-backend-ram,size=32M,id=ram-node0,host-nodes=3,policy=preferred \
+-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
+-object memory-backend-ram,size=32M,id=ram-node1 \
+-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-memnode.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args
new file mode 100644
index 0000000..e4beb98
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args
@@ -0,0 +1,11 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/kvm -S -M pc -m 24104 -smp 32 \
+-object memory-backend-ram,size=20M,id=ram-node0,host-nodes=3,policy=preferred \
+-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
+-object memory-backend-ram,size=645M,id=ram-node1,host-nodes=0-7,policy=bind \
+-numa node,nodeid=1,cpus=1-27,cpus=29,memdev=ram-node1 \
+-object memory-backend-ram,size=23440M,id=ram-node2,\
+host-nodes=1-2,host-nodes=5,host-nodes=7,policy=bind \
+-numa node,nodeid=2,cpus=28,cpus=30-31,memdev=ram-node2 \
+-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-memnode.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.xml
index 18b00d8..49b328c 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.xml
@@ -1,12 +1,13 @@
 <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>
+  <memory unit='KiB'>24682468</memory>
+  <currentMemory unit='KiB'>24682468</currentMemory>
+  <vcpu placement='static'>32</vcpu>
   <numatune>
-    <memory mode='strict' nodeset='0-3'/>
+    <memory mode='strict' nodeset='0-7'/>
     <memnode cellid='0' mode='preferred' nodeset='3'/>
+    <memnode cellid='2' mode='strict' nodeset='1-2,5-7,^6'/>
   </numatune>
   <os>
     <type arch='x86_64' machine='pc'>hvm</type>
@@ -14,8 +15,9 @@
   </os>
   <cpu>
     <numa>
-      <cell id='0' cpus='0' memory='32768'/>
-      <cell id='1' cpus='1' memory='32768'/>
+      <cell id='0' cpus='0' memory='20002'/>
+      <cell id='1' cpus='1-27,29' memory='660066'/>
+      <cell id='2' cpus='28-31,^29' memory='24002400'/>
     </numa>
   </cpu>
   <clock offset='utc'/>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index a2d27cb..baeeefd 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1196,7 +1196,14 @@ mymain(void)
     DO_TEST("blkiotune-device", QEMU_CAPS_NAME);
     DO_TEST("cputune", QEMU_CAPS_NAME);
     DO_TEST("cputune-zero-shares", QEMU_CAPS_NAME);
+
     DO_TEST("numatune-memory", NONE);
+    DO_TEST("numatune-memnode", QEMU_CAPS_NUMA, QEMU_CAPS_OBJECT_MEMORY_RAM);
+    DO_TEST_FAILURE("numatune-memnode", NONE);
+
+    DO_TEST("numatune-memnode-no-memory", QEMU_CAPS_NUMA, QEMU_CAPS_OBJECT_MEMORY_RAM);
+    DO_TEST_FAILURE("numatune-memnode-no-memory", NONE);
+
     DO_TEST("numatune-auto-nodeset-invalid", NONE);
     DO_TEST_PARSE_ERROR("numatune-memnode-nocpu", NONE);
     DO_TEST_PARSE_ERROR("numatune-memnodes-problematic", NONE);
-- 
2.0.0




More information about the libvir-list mailing list