]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf: Introduce cache monitor element in cachetune
authorWang Huaqiang <huaqiang.wang@intel.com>
Mon, 12 Nov 2018 13:31:44 +0000 (21:31 +0800)
committerJohn Ferlan <jferlan@redhat.com>
Wed, 14 Nov 2018 17:18:46 +0000 (12:18 -0500)
Introducing <monitor> element under <cachetune> to represent
a cache monitor.

Signed-off-by: Wang Huaqiang <huaqiang.wang@intel.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
tests/genericxml2xmlindata/cachetune-cdp.xml
tests/genericxml2xmlindata/cachetune-colliding-monitor.xml [new file with mode: 0644]
tests/genericxml2xmlindata/cachetune-small.xml
tests/genericxml2xmltest.c

index 8850a71d94c00d081ebfb366763ebf2162ec7794..92ad4b25421977f472a1f79734cc3f761837d940 100644 (file)
     &lt;cachetune vcpus='0-3'&gt;
       &lt;cache id='0' level='3' type='both' size='3' unit='MiB'/&gt;
       &lt;cache id='1' level='3' type='both' size='3' unit='MiB'/&gt;
+      &lt;monitor level='3' vcpus='1'/&gt;
+      &lt;monitor level='3' vcpus='0-3'/&gt;
+    &lt;/cachetune&gt;
+    &lt;cachetune vcpus='4-5'&gt;
+      &lt;monitor level='3' vcpus='4'/&gt;
+      &lt;monitor level='3' vcpus='5'/&gt;
     &lt;/cachetune&gt;
     &lt;memorytune vcpus='0-3'&gt;
       &lt;node id='0' bandwidth='60'/&gt;
               </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>
 
index 2b465be01d07a8fe20e61573c16fc0d0a9453a5b..1296b7f3f5c7b4b9d945ed35003b2937bb764675 100644 (file)
                 </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>
index a6db4c4f9fb35d74dd39bc5501ce9f050372dce2..98ecd6d83e9c029d9810569d8617ab0fd03cd127 100644 (file)
@@ -2955,14 +2955,32 @@ 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);
 }
 
@@ -18921,6 +18939,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,
@@ -19027,7 +19216,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;
     }
@@ -27063,6 +27259,34 @@ 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,
@@ -27070,6 +27294,7 @@ virDomainCachetuneDefFormat(virBufferPtr buf,
 {
     virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
     char *vcpus = NULL;
+    size_t i = 0;
     int ret = -1;
 
     virBufferSetChildIndent(&childrenBuf, buf);
@@ -27078,6 +27303,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;
 
index e30a4b2fe7b97a8f7902af2fe8a87742ad5114fa..60f64645be62d5b21a29b7a2ac7c059c5c6ce008 100644 (file)
@@ -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;
 };
 
 
index 9718f060987a5b088f75edfe0628506542a6ac05..9f4c13906efa619306b1cb9845f02180c258070e 100644 (file)
@@ -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 (file)
index 0000000..d481fb5
--- /dev/null
@@ -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>
index ab2d9cf8856a5c2cc4dd1e0c11ed2238d234c65a..748be086c3fd045e5fd265e835ea3dee3a2e7f73 100644 (file)
@@ -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>
index fa941f00912129a94dd403e85c02d9ecc96287ba..4393d444641df0a610ea4a0b9d7727a9af4afc93 100644 (file)
@@ -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);