From 1c19d3e0720e2d1d14c7819557a5c62f7ac00726 Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Wed, 2 Jul 2014 11:15:45 +0200 Subject: [PATCH] qemu: pass numa node binding preferences to qemu 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 --- src/qemu/qemu_command.c | 59 ++++++++++++++++++- ...muxml2argv-numatune-memnode-no-memory.args | 8 +++ .../qemuxml2argv-numatune-memnode.args | 11 ++++ tests/qemuxml2argvtest.c | 7 +++ 4 files changed, 84 insertions(+), 1 deletion(-) 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 b6caaf7c8f..806251071e 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: @@ -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 index 0000000000..b0e274ca07 --- /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 0000000000..e4beb98084 --- /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/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 1fd106679e..28436f2e5d 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -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); -- GitLab