[libvirt] [PATCHv8 13/17] conf: Introduce cache monitor element in cachetune

Wang Huaqiang huaqiang.wang at intel.com
Mon Nov 12 13:31:44 UTC 2018


Introducing <monitor> element under <cachetune> to represent
a cache monitor.

Signed-off-by: Wang Huaqiang <huaqiang.wang at intel.com>

Reviewed-by: John Ferlan <jferlan at redhat.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 8850a71..92ad4b2 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><span class="since">Since 4.10.0</span></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 the associated
+                allocation. The default monitor has the same vCPU list as the
+                associated allocation. For non-default monitors, overlapping
+                vCPUs are not permitted.
+              </dd>
+            </dl>
+          </dd>
         </dl>
       </dd>
 
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 2b465be..1296b7f 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 8433214..7696098 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);
 }
 
@@ -18948,6 +18966,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,
@@ -19054,7 +19243,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 (!resctrl->nmonitors && virResctrlAllocIsEmpty(alloc)) {
         ret = 0;
         goto cleanup;
     }
@@ -27091,12 +27287,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);
@@ -27105,6 +27330,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




More information about the libvir-list mailing list