diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index d8144ea22c..fcf598428e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -550,6 +550,8 @@ <quota>-1</quota> <emulator_period>1000000</emulator_period> <emulator_quota>-1</emulator_quota> + <vcpusched vcpus='0-4,^3' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='2' scheduler='batch'/> </cputune> ... </domain> @@ -652,6 +654,19 @@ Only QEMU driver support since 0.10.0 +
vcpusched and iothreadsched
+
+ The optional vcpusched elements specifies the scheduler + type (values batch, idle, fifo, + rr) for particular vCPU/IOThread threads (based on + vcpus and iothreads, leaving out + vcpus/iothreads sets the default). For + real-time schedulers (fifo, rr), priority must + be specified as well (and is ignored for non-real-time ones). The value + range for the priority depends on the host kernel (usually 1-99). + Since 1.2.12 +
+ diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index b1f4eaac06..7a1d299b55 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -815,10 +815,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + batch + idle + + + + + + + fifo + rr + + + + + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7d28314e77..fd3606379c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -772,6 +772,13 @@ VIR_ENUM_IMPL(virDomainLoader, "rom", "pflash") +VIR_ENUM_IMPL(virDomainThreadSched, VIR_DOMAIN_THREAD_SCHED_LAST, + "other", /* default */ + "batch", + "idle", + "fifo", + "rr") + /* Internal mapping: subset of block job types that can be present in * XML (remaining types are not two-phase). */ VIR_ENUM_DECL(virDomainBlockJob) @@ -2234,6 +2241,14 @@ void virDomainDefFree(virDomainDefPtr def) virDomainVcpuPinDefArrayFree(def->cputune.iothreadspin, def->cputune.niothreadspin); + for (i = 0; i < def->cputune.nvcpusched; i++) + virBitmapFree(def->cputune.vcpusched[i].ids); + VIR_FREE(def->cputune.vcpusched); + + for (i = 0; i < def->cputune.niothreadsched; i++) + virBitmapFree(def->cputune.iothreadsched[i].ids); + VIR_FREE(def->cputune.iothreadsched); + virDomainNumatuneFree(def->numatune); virSysinfoDefFree(def->sysinfo); @@ -12772,6 +12787,70 @@ virDomainLoaderDefParseXML(xmlNodePtr node, return ret; } +static int +virDomainThreadSchedParse(xmlNodePtr node, + unsigned int minid, + unsigned int maxid, + const char *name, + virDomainThreadSchedParamPtr sp) +{ + char *tmp = NULL; + int sched = 0; + + tmp = virXMLPropString(node, name); + if (!tmp) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing attribute '%s' in element '%sched'"), + name, name); + goto error; + } + + if (!virBitmapParse(tmp, 0, &sp->ids, + VIR_DOMAIN_CPUMASK_LEN) || + virBitmapIsAllClear(sp->ids) || + virBitmapNextSetBit(sp->ids, -1) < minid || + virBitmapLastSetBit(sp->ids) > maxid) { + + virReportError(VIR_ERR_XML_ERROR, + _("Invalid value of '%s': %s"), + name, tmp); + goto error; + } + VIR_FREE(tmp); + + tmp = virXMLPropString(node, "scheduler"); + if (tmp) { + if ((sched = virDomainThreadSchedTypeFromString(tmp)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid scheduler attribute: '%s'"), + tmp); + goto error; + } + sp->scheduler = sched; + + VIR_FREE(tmp); + if (sp->scheduler >= VIR_DOMAIN_THREAD_SCHED_FIFO) { + tmp = virXMLPropString(node, "priority"); + if (!tmp) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing scheduler priority")); + goto error; + } + if (virStrToLong_i(tmp, NULL, 10, &sp->priority) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Invalid value for element priority")); + goto error; + } + VIR_FREE(tmp); + } + } + + return 0; + + error: + VIR_FREE(tmp); + return -1; +} static virDomainDefPtr virDomainDefParseXML(xmlDocPtr xml, @@ -13316,6 +13395,77 @@ virDomainDefParseXML(xmlDocPtr xml, } VIR_FREE(nodes); + if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract vcpusched nodes")); + goto error; + } + if (n) { + if (n > def->maxvcpus) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many vcpusched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.vcpusched, n) < 0) + goto error; + def->cputune.nvcpusched = n; + + for (i = 0; i < def->cputune.nvcpusched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 0, def->maxvcpus - 1, + "vcpus", + &def->cputune.vcpusched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.vcpusched[i].ids, + def->cputune.vcpusched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("vcpusched attributes 'vcpus' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes); + + if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract iothreadsched nodes")); + goto error; + } + if (n) { + if (n > def->iothreads) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many iothreadsched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.iothreadsched, n) < 0) + goto error; + def->cputune.niothreadsched = n; + + for (i = 0; i < def->cputune.niothreadsched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 1, def->iothreads, + "iothreads", + &def->cputune.iothreadsched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.iothreadsched[i].ids, + def->cputune.iothreadsched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("iothreadsched attributes 'iothreads' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes); /* analysis of cpu handling */ if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) { @@ -19621,7 +19771,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, def->cputune.period || def->cputune.quota || def->cputune.emulatorpin || def->cputune.emulator_period || def->cputune.emulator_quota || - def->cputune.niothreadspin) { + def->cputune.niothreadspin || + def->cputune.vcpusched || def->cputune.iothreadsched) { virBufferAddLit(buf, "\n"); cputune = true; } @@ -19690,6 +19841,36 @@ virDomainDefFormatInternal(virDomainDefPtr def, VIR_FREE(cpumask); } + for (i = 0; i < def->cputune.nvcpusched; i++) { + virDomainThreadSchedParamPtr sp = &def->cputune.vcpusched[i]; + char *ids = NULL; + + if (!(ids = virBitmapFormat(sp->ids))) + goto error; + virBufferAsprintf(buf, "scheduler)); + VIR_FREE(ids); + + if (sp->priority) + virBufferAsprintf(buf, " priority='%d'", sp->priority); + virBufferAddLit(buf, "/>\n"); + } + + for (i = 0; i < def->cputune.niothreadsched; i++) { + virDomainThreadSchedParamPtr sp = &def->cputune.iothreadsched[i]; + char *ids = NULL; + + if (!(ids = virBitmapFormat(sp->ids))) + goto error; + virBufferAsprintf(buf, "scheduler)); + VIR_FREE(ids); + + if (sp->priority) + virBufferAsprintf(buf, " priority='%d'", sp->priority); + virBufferAddLit(buf, "/>\n"); + } + virBufferAdjustIndent(buf, -2); if (cputune) virBufferAddLit(buf, "\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e96d2e311d..da21bcefe1 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1810,6 +1810,24 @@ typedef enum { VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST } virDomainCpuPlacementMode; +typedef enum { + VIR_DOMAIN_THREAD_SCHED_OTHER = 0, + VIR_DOMAIN_THREAD_SCHED_BATCH, + VIR_DOMAIN_THREAD_SCHED_IDLE, + VIR_DOMAIN_THREAD_SCHED_FIFO, + VIR_DOMAIN_THREAD_SCHED_RR, + + VIR_DOMAIN_THREAD_SCHED_LAST +} virDomainThreadSched; + +typedef struct _virDomainThreadSchedParam virDomainThreadSchedParam; +typedef virDomainThreadSchedParam *virDomainThreadSchedParamPtr; +struct _virDomainThreadSchedParam { + virBitmapPtr ids; + virDomainThreadSched scheduler; + int priority; +}; + typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef; typedef virDomainTimerCatchupDef *virDomainTimerCatchupDefPtr; struct _virDomainTimerCatchupDef { @@ -1997,6 +2015,11 @@ struct _virDomainCputune { virDomainVcpuPinDefPtr emulatorpin; size_t niothreadspin; virDomainVcpuPinDefPtr *iothreadspin; + + size_t nvcpusched; + virDomainThreadSchedParamPtr vcpusched; + size_t niothreadsched; + virDomainThreadSchedParamPtr iothreadsched; }; typedef struct _virDomainBlkiotune virDomainBlkiotune; @@ -2854,6 +2877,7 @@ VIR_ENUM_DECL(virDomainRNGModel) VIR_ENUM_DECL(virDomainRNGBackend) VIR_ENUM_DECL(virDomainTPMModel) VIR_ENUM_DECL(virDomainTPMBackend) +VIR_ENUM_DECL(virDomainThreadSched) /* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainNostateReason) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bff9a0bf38..645aef14cb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -413,6 +413,8 @@ virDomainStateTypeFromString; virDomainStateTypeToString; virDomainTaintTypeFromString; virDomainTaintTypeToString; +virDomainThreadSchedTypeFromString; +virDomainThreadSchedTypeToString; virDomainTimerModeTypeFromString; virDomainTimerModeTypeToString; virDomainTimerNameTypeFromString; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml new file mode 100644 index 0000000000..1540969a3b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml @@ -0,0 +1,38 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 2 + 1 + + 2048 + 1000000 + -1 + + + + + + + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml new file mode 100644 index 0000000000..0a3ffc7c71 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml @@ -0,0 +1,39 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 2 + 4 + + 2048 + 1000000 + -1 + + + + + + + + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml b/tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml new file mode 100644 index 0000000000..cbbe7dc18b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml @@ -0,0 +1,38 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 4 + 1 + + 2048 + 1000000 + -1 + + + + + + + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 395cab3d91..316f4793a6 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1253,6 +1253,8 @@ 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_PARSE_ERROR("cputune-iothreadsched-toomuch", QEMU_CAPS_NAME); + DO_TEST_PARSE_ERROR("cputune-vcpusched-overlap", QEMU_CAPS_NAME); DO_TEST("numatune-memory", NONE); DO_TEST_PARSE_ERROR("numatune-memory-invalid-nodeset", NONE); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml new file mode 100644 index 0000000000..9f61336b8d --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml @@ -0,0 +1,39 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 2 + 4 + + 2048 + 1000000 + -1 + + + + + + + + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + + diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index cc29083a44..99d46299af 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -310,6 +310,7 @@ mymain(void) DO_TEST("blkiotune-device"); DO_TEST("cputune"); DO_TEST("cputune-zero-shares"); + DO_TEST_DIFFERENT("cputune-iothreadsched"); DO_TEST("cputune-numatune"); DO_TEST("vcpu-placement-static");