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");