Introducing <monitor> element under <cachetune> to represent
a cache monitor.
Signed-off-by: Wang Huaqiang <huaqiang.wang(a)intel.com>
---
docs/formatdomain.html.in | 26 +++
docs/schemas/domaincommon.rng | 10 +
src/conf/domain_conf.c | 234 ++++++++++++++++++++-
src/conf/domain_conf.h | 11 +
tests/genericxml2xmlindata/cachetune-cdp.xml | 3 +
.../cachetune-colliding-monitor.xml | 30 +++
tests/genericxml2xmlindata/cachetune-small.xml | 7 +
tests/genericxml2xmltest.c | 2 +
8 files changed, 322 insertions(+), 1 deletion(-)
create mode 100644 tests/genericxml2xmlindata/cachetune-colliding-monitor.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index b1651e3..2fd665c 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -759,6 +759,12 @@
<cachetune vcpus='0-3'>
<cache id='0' level='3' type='both' size='3'
unit='MiB'/>
<cache id='1' level='3' type='both' size='3'
unit='MiB'/>
+ <monitor level='3' vcpus='1'/>
+ <monitor level='3' vcpus='0-3'/>
+ </cachetune>
+ <cachetune vcpus='4-5'>
+ <monitor level='3' vcpus='4'/>
+ <monitor level='3' vcpus='5'/>
</cachetune>
<memorytune vcpus='0-3'>
<node id='0' bandwidth='60'/>
@@ -978,6 +984,26 @@
</dd>
</dl>
</dd>
+ <dt><code>monitor</code></dt>
+ <dd>
+ The optional element <code>monitor</code> creates the cache
+ monitor(s) for current cache allocation and has the following
+ required attributes:
+ <dl>
+ <dt><code>level</code></dt>
+ <dd>
+ Host cache level the monitor belongs to.
+ </dd>
+ <dt><code>vcpus</code></dt>
+ <dd>
+ vCPU list the monitor applies to. A monitor's vCPU list
+ can only be the member(s) of the vCPU list of associating
+ allocation. The default monitor has the same vCPU list as the
+ associating allocation. For non-default monitors, there
+ are no vCPU overlap permitted.
+ </dd>
+ </dl>
+ </dd>
</dl>
</dd>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 5c533d6..7ce49d3 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -981,6 +981,16 @@
</optional>
</element>
</zeroOrMore>
+ <zeroOrMore>
+ <element name="monitor">
+ <attribute name="level">
+ <ref name='unsignedInt'/>
+ </attribute>
+ <attribute name="vcpus">
+ <ref name='cpuset'/>
+ </attribute>
+ </element>
+ </zeroOrMore>
</element>
</zeroOrMore>
<zeroOrMore>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index a068d4d..01f795f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2955,13 +2955,31 @@ virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
static void
+virDomainResctrlMonDefFree(virDomainResctrlMonDefPtr domresmon)
+{
+ if (!domresmon)
+ return;
+
+ virBitmapFree(domresmon->vcpus);
+ virObjectUnref(domresmon->instance);
+ VIR_FREE(domresmon);
+}
+
+
+static void
virDomainResctrlDefFree(virDomainResctrlDefPtr resctrl)
{
+ size_t i = 0;
+
if (!resctrl)
return;
+ for (i = 0; i < resctrl->nmonitors; i++)
+ virDomainResctrlMonDefFree(resctrl->monitors[i]);
+
virObjectUnref(resctrl->alloc);
virBitmapFree(resctrl->vcpus);
+ VIR_FREE(resctrl->monitors);
VIR_FREE(resctrl);
}
@@ -18920,6 +18938,177 @@ virDomainCachetuneDefParseCache(xmlXPathContextPtr ctxt,
}
+/* Checking if the monitor's vcpus is conflicted with existing allocation
+ * and monitors.
+ *
+ * Returns 1 if @vcpus equals to @resctrl->vcpus, then the monitor will
+ * share the underlying resctrl group with @resctrl->alloc. Returns - 1
+ * if any conflict found. Returns 0 if no conflict and @vcpus is not equal
+ * to @resctrl->vcpus.
+ */
+static int
+virDomainResctrlMonValidateVcpus(virDomainResctrlDefPtr resctrl,
+ virBitmapPtr vcpus)
+{
+ size_t i = 0;
+ int vcpu = -1;
+ size_t mons_same_alloc_vcpus = 0;
+
+ if (virBitmapIsAllClear(vcpus)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("vcpus is empty"));
+ return -1;
+ }
+
+ while ((vcpu = virBitmapNextSetBit(vcpus, vcpu)) >= 0) {
+ if (!virBitmapIsBitSet(resctrl->vcpus, vcpu)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Monitor vcpus conflicts with allocation"));
+ return -1;
+ }
+ }
+
+ if (virBitmapEqual(vcpus, resctrl->vcpus))
+ return 1;
+
+ for (i = 0; i < resctrl->nmonitors; i++) {
+ if (virBitmapEqual(resctrl->vcpus, resctrl->monitors[i]->vcpus)) {
+ mons_same_alloc_vcpus++;
+ continue;
+ }
+
+ if (virBitmapOverlaps(vcpus, resctrl->monitors[i]->vcpus)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Monitor vcpus conflicts with monitors"));
+
+ return -1;
+ }
+ }
+
+ if (mons_same_alloc_vcpus > 1) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Too many monitors have the same vcpu as
allocation"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#define VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL 3
+
+static int
+virDomainResctrlMonDefParse(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ virResctrlMonitorType tag,
+ virDomainResctrlDefPtr resctrl)
+{
+ virDomainResctrlMonDefPtr domresmon = NULL;
+ xmlNodePtr oldnode = ctxt->node;
+ xmlNodePtr *nodes = NULL;
+ unsigned int level = 0;
+ char *tmp = NULL;
+ char *id = NULL;
+ size_t i = 0;
+ int n = 0;
+ int rv = -1;
+ int ret = -1;
+
+ ctxt->node = node;
+
+ if ((n = virXPathNodeSet("./monitor", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot extract monitor nodes"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (VIR_ALLOC(domresmon) < 0)
+ goto cleanup;
+
+ domresmon->tag = tag;
+
+ domresmon->instance = virResctrlMonitorNew();
+ if (!domresmon->instance) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not create monitor"));
+ goto cleanup;
+ }
+
+ if (tag == VIR_RESCTRL_MONITOR_TYPE_CACHE) {
+ tmp = virXMLPropString(nodes[i], "level");
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing monitor attribute
'level'"));
+ goto cleanup;
+ }
+
+ if (virStrToLong_uip(tmp, NULL, 10, &level) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid monitor attribute 'level' value
'%s'"),
+ tmp);
+ goto cleanup;
+ }
+
+ if (level != VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid monitor cache level '%d'"),
+ level);
+ goto cleanup;
+ }
+
+ VIR_FREE(tmp);
+ }
+
+ if (virDomainResctrlParseVcpus(def, nodes[i], &domresmon->vcpus) < 0)
+ goto cleanup;
+
+ rv = virDomainResctrlMonValidateVcpus(resctrl, domresmon->vcpus);
+ if (rv < 0)
+ goto cleanup;
+
+ /* If monitor's vcpu list is identical to the vcpu list of the
+ * associated allocation, set monitor's id to the same value
+ * as the allocation. */
+ if (rv == 1) {
+ const char *alloc_id = virResctrlAllocGetID(resctrl->alloc);
+
+ if (VIR_STRDUP(id, alloc_id) < 0)
+ goto cleanup;
+ } else {
+ if (!(tmp = virBitmapFormat(domresmon->vcpus)))
+ goto cleanup;
+
+ if (virAsprintf(&id, "vcpus_%s", tmp) < 0)
+ goto cleanup;
+ }
+
+ virResctrlMonitorSetAlloc(domresmon->instance, resctrl->alloc);
+
+ if (virResctrlMonitorSetID(domresmon->instance, id) < 0)
+ goto cleanup;
+
+ if (VIR_APPEND_ELEMENT(resctrl->monitors,
+ resctrl->nmonitors,
+ domresmon) < 0)
+ goto cleanup;
+
+ VIR_FREE(id);
+ VIR_FREE(tmp);
+ }
+
+ ret = 0;
+ cleanup:
+ ctxt->node = oldnode;
+ VIR_FREE(id);
+ VIR_FREE(tmp);
+ VIR_FREE(nodes);
+ virDomainResctrlMonDefFree(domresmon);
+ return ret;
+}
+
+
static virDomainResctrlDefPtr
virDomainResctrlNew(xmlNodePtr node,
virResctrlAllocPtr *alloc,
@@ -19026,7 +19215,14 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
if (!resctrl)
goto cleanup;
- if (virResctrlAllocIsEmpty(alloc)) {
+ if (virDomainResctrlMonDefParse(def, ctxt, node,
+ VIR_RESCTRL_MONITOR_TYPE_CACHE,
+ resctrl) < 0)
+ goto cleanup;
+
+ /* If no <cache> element or <monitor> element in <cachetune>, do
not
+ * append any resctrl element */
+ if (virResctrlAllocIsEmpty(alloc) && !resctrl->nmonitors) {
ret = 0;
goto cleanup;
}
@@ -27063,12 +27259,41 @@ virDomainCachetuneDefFormatHelper(unsigned int level,
static int
+virDomainResctrlMonDefFormatHelper(virDomainResctrlMonDefPtr domresmon,
+ virResctrlMonitorType tag,
+ virBufferPtr buf)
+{
+ char *vcpus = NULL;
+
+ if (domresmon->tag != tag)
+ return 0;
+
+ virBufferAddLit(buf, "<monitor ");
+
+ if (tag == VIR_RESCTRL_MONITOR_TYPE_CACHE) {
+ virBufferAsprintf(buf, "level='%u' ",
+ VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL);
+ }
+
+ vcpus = virBitmapFormat(domresmon->vcpus);
+ if (!vcpus)
+ return -1;
+
+ virBufferAsprintf(buf, "vcpus='%s'/>\n", vcpus);
+
+ VIR_FREE(vcpus);
+ return 0;
+}
+
+
+static int
virDomainCachetuneDefFormat(virBufferPtr buf,
virDomainResctrlDefPtr resctrl,
unsigned int flags)
{
virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
char *vcpus = NULL;
+ size_t i = 0;
int ret = -1;
virBufferSetChildIndent(&childrenBuf, buf);
@@ -27077,6 +27302,13 @@ virDomainCachetuneDefFormat(virBufferPtr buf,
&childrenBuf) < 0)
goto cleanup;
+ for (i = 0; i < resctrl->nmonitors; i ++) {
+ if (virDomainResctrlMonDefFormatHelper(resctrl->monitors[i],
+ VIR_RESCTRL_MONITOR_TYPE_CACHE,
+ &childrenBuf) < 0)
+ goto cleanup;
+ }
+
if (virBufferCheckError(&childrenBuf) < 0)
goto cleanup;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e30a4b2..60f6464 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2236,12 +2236,23 @@ struct _virDomainCputune {
};
+typedef struct _virDomainResctrlMonDef virDomainResctrlMonDef;
+typedef virDomainResctrlMonDef *virDomainResctrlMonDefPtr;
+struct _virDomainResctrlMonDef {
+ virBitmapPtr vcpus;
+ virResctrlMonitorType tag;
+ virResctrlMonitorPtr instance;
+};
+
typedef struct _virDomainResctrlDef virDomainResctrlDef;
typedef virDomainResctrlDef *virDomainResctrlDefPtr;
struct _virDomainResctrlDef {
virBitmapPtr vcpus;
virResctrlAllocPtr alloc;
+
+ virDomainResctrlMonDefPtr *monitors;
+ size_t nmonitors;
};
diff --git a/tests/genericxml2xmlindata/cachetune-cdp.xml
b/tests/genericxml2xmlindata/cachetune-cdp.xml
index 9718f06..9f4c139 100644
--- a/tests/genericxml2xmlindata/cachetune-cdp.xml
+++ b/tests/genericxml2xmlindata/cachetune-cdp.xml
@@ -8,9 +8,12 @@
<cachetune vcpus='0-1'>
<cache id='0' level='3' type='code' size='7680'
unit='KiB'/>
<cache id='1' level='3' type='data' size='3840'
unit='KiB'/>
+ <monitor level='3' vcpus='0'/>
+ <monitor level='3' vcpus='1'/>
</cachetune>
<cachetune vcpus='2'>
<cache id='1' level='3' type='code' size='6'
unit='MiB'/>
+ <monitor level='3' vcpus='2'/>
</cachetune>
<cachetune vcpus='3'>
<cache id='1' level='3' type='data' size='6912'
unit='KiB'/>
diff --git a/tests/genericxml2xmlindata/cachetune-colliding-monitor.xml
b/tests/genericxml2xmlindata/cachetune-colliding-monitor.xml
new file mode 100644
index 0000000..d481fb5
--- /dev/null
+++ b/tests/genericxml2xmlindata/cachetune-colliding-monitor.xml
@@ -0,0 +1,30 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <cputune>
+ <cachetune vcpus='0-1'>
+ <cache id='0' level='3' type='both' size='768'
unit='KiB'/>
+ <monitor level='3' vcpus='2'/>
+ </cachetune>
+ </cputune>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/genericxml2xmlindata/cachetune-small.xml
b/tests/genericxml2xmlindata/cachetune-small.xml
index ab2d9cf..748be08 100644
--- a/tests/genericxml2xmlindata/cachetune-small.xml
+++ b/tests/genericxml2xmlindata/cachetune-small.xml
@@ -7,6 +7,13 @@
<cputune>
<cachetune vcpus='0-1'>
<cache id='0' level='3' type='both' size='768'
unit='KiB'/>
+ <monitor level='3' vcpus='0'/>
+ <monitor level='3' vcpus='1'/>
+ <monitor level='3' vcpus='0-1'/>
+ </cachetune>
+ <cachetune vcpus='2-3'>
+ <monitor level='3' vcpus='2'/>
+ <monitor level='3' vcpus='3'/>
</cachetune>
</cputune>
<os>
diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c
index fa941f0..4393d44 100644
--- a/tests/genericxml2xmltest.c
+++ b/tests/genericxml2xmltest.c
@@ -137,6 +137,8 @@ mymain(void)
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
DO_TEST_FULL("cachetune-colliding-types", false, true,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
+ DO_TEST_FULL("cachetune-colliding-monitor", false, true,
+ TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
DO_TEST("memorytune");
DO_TEST_FULL("memorytune-colliding-allocs", false, true,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
--
2.7.4