]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: pass numa node binding preferences to qemu
authorMartin Kletzander <mkletzan@redhat.com>
Wed, 2 Jul 2014 09:15:45 +0000 (11:15 +0200)
committerMartin Kletzander <mkletzan@redhat.com>
Wed, 16 Jul 2014 18:15:46 +0000 (20:15 +0200)
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@redhat.com>
src/qemu/qemu_command.c
tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args [new file with mode: 0644]
tests/qemuxml2argvtest.c

index b6caaf7c8f6d457a41a2552641ae24f3b68c2c73..806251071e10c175cd96cdbb085cc4cf9e05c736 100644 (file)
@@ -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:
@@ -6383,13 +6388,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;
@@ -6402,6 +6417,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);
 
@@ -6412,7 +6464,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);
     }
@@ -6420,6 +6476,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 (file)
index 0000000..b0e274c
--- /dev/null
@@ -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 (file)
index 0000000..e4beb98
--- /dev/null
@@ -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
index 1fd106679e3982e391e6a1aa5f67111e327b46f4..28436f2e5d75913dd2a090f8d4aa02ec90747850 100644 (file)
@@ -1197,7 +1197,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);