NULL,
NULL);
+VIR_ENUM_DECL(qemuNumaPolicy)
+VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
+ "bind",
+ "preferred",
+ "interleave");
/**
* qemuPhysIfaceConnect:
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;
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);
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);
}
cleanup:
VIR_FREE(cpumask);
+ VIR_FREE(nodemask);
virBufferFreeAndReset(&buf);
return ret;
}
--- /dev/null
+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
--- /dev/null
+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
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);