[libvirt] [PATCHv2 02/10] conf: introduce <resmongroup> element

Wang Huaqiang huaqiang.wang at intel.com
Mon Jul 9 07:00:50 UTC 2018


resmongroup element is used for feature of resctrl monitoring
group, and keeps the information for how resctrl monitoring
groups is arranged.
---
 docs/formatdomain.html.in     |  17 +++
 docs/schemas/domaincommon.rng |  14 ++
 src/conf/domain_conf.c        | 318 ++++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h        |  25 ++++
 src/libvirt_private.syms      |   3 +
 5 files changed, 377 insertions(+)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index a3afe13..cfb10c4 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -757,6 +757,8 @@
       <cache id='0' level='3' type='both' size='3' unit='MiB'/>
       <cache id='1' level='3' type='both' size='3' unit='MiB'/>
     </cachetune>
+    <resmongroup vcpus="0-3"/>
+    <resmongroup vcpus="4"/>
   </cputune>
   ...
 </domain>
@@ -952,6 +954,21 @@
         </dl>
 
       </dd>
+      <dt><code>resmongroup</code><span class="since">Since 4.6.0</span></dt>
+      <dd>
+        Optional <code>resmongroup</code> element can be used to create resctrl
+        monitoring group for purpose of reporting cache occupancy informatoin.
+        The attribute <code>vcpus</code> specifies vCPUs this monitoring group
+        applies and which is impacted by the <code>cachetune</code>
+        <code>vcpus</code> attribute. A <code>resmongroup</code>
+        <code>vcpus</code> is valid if it has the same setting with that of
+        <code>cachetune</code> element, but any other kind of overlap between
+        <code>vcpus</code> of <code>rdtmongroup</code> and
+        <code>cachetune</code> <code>vcpus</code> is not permitted. Further,
+        any other kind of vCPUs overlap between monitoring groups is allowed.
+        Optional attribute <code>id</code> specifies the group name.
+
+      </dd>
     </dl>
 
 
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index bd687ce..a8057b1 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -952,6 +952,20 @@
           </element>
         </zeroOrMore>
         <zeroOrMore>
+          <element name="resmongroup">
+            <attribute name="vcpus">
+              <ref name='cpuset'/>
+            </attribute>
+            <optional>
+              <attribute name="id">
+                <data type="string">
+                  <param name='pattern'>[a-zA-Z0-9,-_]+</param>
+                </data>
+              </attribute>
+            </optional>
+          </element>
+        </zeroOrMore>
+        <zeroOrMore>
           <element name="cachetune">
             <attribute name="vcpus">
               <ref name='cpuset'/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f4e59f6..0cdad79 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2975,6 +2975,18 @@ virDomainSEVDefFree(virDomainSEVDefPtr def)
 }
 
 
+static void
+virDomainCpuResmonDefFree(virDomainCpuResmonDefPtr resmon)
+{
+    if (!resmon)
+        return;
+
+    virObjectUnref(resmon->mon);
+    virBitmapFree(resmon->vcpus);
+    VIR_FREE(resmon);
+}
+
+
 void virDomainDefFree(virDomainDefPtr def)
 {
     size_t i;
@@ -3152,6 +3164,10 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainCachetuneDefFree(def->cachetunes[i]);
     VIR_FREE(def->cachetunes);
 
+    for (i = 0; i < def->nresmons; i++)
+        virDomainCpuResmonDefFree(def->resmons[i]);
+    VIR_FREE(def->resmons);
+
     VIR_FREE(def->keywrap);
 
     if (def->namespaceData && def->ns.free)
@@ -19055,6 +19071,264 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
 }
 
 
+bool
+virDomainCpuResmonDefValidate(virDomainDefPtr def,
+                              const char *id,
+                              virBitmapPtr vcpus,
+                              virResctrlAllocPtr *alloc)
+{
+    ssize_t i = -1;
+
+    /* vcpu should exist in current domain */
+    while ((i = virBitmapNextSetBit(vcpus, i)) > -1) {
+        if (!virDomainDefGetVcpu(def, i))
+            return false;
+    }
+
+    if (alloc)
+        *alloc = NULL;
+
+    /* if 'vcpus' equals to vcpus of any existing allocation group, means, mon
+     * group is sharing same resctrl resource group with allocation group, this
+     * is a legal case. Otherwise, no vcpu overlap is allowed between mon group
+     * and any aollocation group.
+     * if a mon group is sharing the same resource group with one allocation
+     * group, we hope the mon group and the allocation group have a same 'id',
+     * and the 'alloc' pointer points to the allocation group. */
+    for (i = 0; i < def->ncachetunes; i++) {
+        if (virBitmapOverlaps(vcpus, def->cachetunes[i]->vcpus)) {
+            if (virBitmapEqual(vcpus, def->cachetunes[i]->vcpus)) {
+                const char *allocid =
+                    virResctrlAllocGetID(def->cachetunes[i]->alloc);
+                if (!allocid || (id && STRNEQ(id, allocid)))
+                    return false;
+
+                if (alloc)
+                    *alloc = def->cachetunes[i]->alloc;
+                return true;
+            }
+
+            return false;
+        }
+    }
+
+    /* if vcpus equals to vcpus of existing mon group vcpus,
+     * a mon group already created, return True.
+     * for new mon group no overlap for vcpus */
+    for (i = 0; i < def->nresmons; i++) {
+        if (virBitmapEqual(vcpus, def->resmons[i]->vcpus) &&
+            (!id ||
+            STREQ(id, virResctrlMonGetID(def->resmons[i]->mon))))
+            return true;
+
+        if (virBitmapOverlaps(vcpus, def->resmons[i]->vcpus))
+            return false;
+    }
+
+    return true;
+}
+
+
+virDomainCpuResmonDefPtr
+virDomainCpuResmonDefAdd(virDomainDefPtr def,
+                         virBitmapPtr vcpuslist,
+                         const char *monid)
+{
+    virDomainCpuResmonDefPtr resmon = NULL;
+    virResctrlMonPtr mon = NULL;
+    char *id = NULL;
+    char *vcpus_str = NULL;
+    size_t i = -1;
+    virDomainCpuResmonDefPtr ret = NULL;
+    virBitmapPtr vcpus = virBitmapNewCopy(vcpuslist);
+
+    if (VIR_STRDUP(id, monid) < 0)
+        goto cleanup;
+
+    for (i = 0; i < def->nresmons; i++) {
+        if (virBitmapEqual(vcpus, def->resmons[i]->vcpus)) {
+            if (!id ||
+                STREQ(id, virResctrlMonGetID(def->resmons[i]->mon))) {
+                ret = def->resmons[i];
+                goto cleanup;
+            }
+            virReportError(VIR_ERR_INVALID_ARG,
+                    "%s", _("resource monitoring group id mismatch"));
+            goto cleanup;
+        }
+    }
+
+    /* resouce group created by cachtune also has a mon group, if matched
+     * copying the group id and no sub-directory under resctrl fs will be
+     * created */
+    for (i = 0; i < def->ncachetunes; i++) {
+        if (virBitmapEqual(vcpus, def->cachetunes[i]->vcpus)) {
+            const char *allocid
+                = virResctrlAllocGetID(def->cachetunes[i]->alloc);
+            /* for mon group matched in cachetunes list should never
+             * be disabled because we cannot disable an allocation
+             * group in runtime */
+            if (!id) {
+                if (VIR_STRDUP(id, allocid) < 0)
+                    goto cleanup;
+
+            }
+            break;
+        }
+    }
+
+    if (!id) {
+        vcpus_str = virBitmapFormat(vcpus);
+        if (virAsprintf(&id, "vcpus_%s", vcpus_str) < 0)
+            goto cleanup;
+    }
+
+    if (VIR_ALLOC(resmon) < 0)
+        goto cleanup;
+
+    mon = virResctrlMonNew();
+    if (!mon)
+        goto cleanup;
+
+    if (virResctrlMonSetID(mon, id) < 0)
+        goto cleanup;
+
+    VIR_STEAL_PTR(resmon->vcpus, vcpus);
+    VIR_STEAL_PTR(resmon->mon, mon);
+
+    if (VIR_APPEND_ELEMENT(def->resmons, def->nresmons, resmon) < 0)
+        goto cleanup;
+
+    ret = def->resmons[def->nresmons - 1];
+ cleanup:
+    virBitmapFree(vcpus);
+    VIR_FREE(id);
+    virDomainCpuResmonDefFree(resmon);
+    virObjectUnref(mon);
+    return ret;
+}
+
+
+virResctrlMonPtr
+virDomainCpuResmonDefRemove(virDomainDefPtr def,
+                            const char *monid)
+{
+    virDomainCpuResmonDefPtr resmon = NULL;
+    virResctrlMonPtr mon = NULL;
+    size_t i = -1;
+
+    if (!monid) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("Cannot remove resource monitoring group: "
+                         "group name is NULL"));
+        goto error;
+    }
+
+    for (i = 0; i < def->nresmons; i++) {
+        const char *id = virResctrlMonGetID(def->resmons[i]->mon);
+        if (!id) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Cannot remove resource monitoring group: "
+                             "error in get monitoring group name"));
+        goto error;
+        }
+
+        if (STREQ(monid, id))
+            break;
+    }
+
+    if (i == def->nresmons) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Cannot remove resource monitoring group: "
+                         "no monitoring group '%s' found"),
+                      monid);
+        goto error;
+    }
+
+    resmon = def->resmons[i];
+    VIR_DELETE_ELEMENT(def->resmons, i, def->nresmons);
+
+    mon = resmon->mon;
+    virBitmapFree(resmon->vcpus);
+    VIR_FREE(resmon);
+ error:
+    return mon;
+}
+
+
+static int
+virDomainCpuResmonDefParse(virDomainDefPtr def,
+                           xmlXPathContextPtr ctxt,
+                           unsigned int flags)
+{
+    xmlNodePtr oldnode = ctxt->node;
+    xmlNodePtr *nodes = NULL;
+    virBitmapPtr vcpus = NULL;
+    char *vcpus_str = NULL;
+    char *monid = NULL;
+    size_t i = 0;
+    int n = 0;
+    int ret = -1;
+
+    if ((n = virXPathNodeSet("./cputune/resmongroup", ctxt, &nodes)) < 0)
+        goto cleanup;
+
+    for (i = 0; i < n; i++) {
+
+        if (!(vcpus_str = virXMLPropString(nodes[i], "vcpus"))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                    _("Missing resmongroup attribute 'vcpus'"));
+            goto cleanup;
+        }
+
+        if (virBitmapParse(vcpus_str, &vcpus, VIR_DOMAIN_CPUMASK_LEN) < 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                    _("Invalid resmongroup attribute 'vcpus' value '%s'"),
+                    vcpus_str);
+            goto cleanup;
+        }
+
+        virBitmapShrink(vcpus, def->maxvcpus);
+
+        if (virBitmapIsAllClear(vcpus)) {
+            ret = 0;
+            goto cleanup;
+        }
+
+        if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
+            monid = virXMLPropString(nodes[i], "id");
+
+        if (!virDomainCpuResmonDefValidate(def, monid, vcpus, NULL)) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                    "%s", _("vcpus or group name conflicts with domain "
+                            "settings"));
+            goto cleanup;
+        }
+
+        if (!virDomainCpuResmonDefAdd(def, vcpus, monid)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                    "%s", _("Error in add resource monitoring group settings "
+                            "to configuration file"));
+            goto cleanup;
+        }
+
+        virBitmapFree(vcpus);
+        vcpus = NULL;
+        VIR_FREE(monid);
+        monid = NULL;
+    }
+
+    ret = 0;
+ cleanup:
+    ctxt->node = oldnode;
+    virBitmapFree(vcpus);
+    VIR_FREE(monid);
+    VIR_FREE(vcpus_str);
+    VIR_FREE(nodes);
+    return ret;
+}
+
+
 static virDomainDefPtr
 virDomainDefParseXML(xmlDocPtr xml,
                      xmlNodePtr root,
@@ -19648,8 +19922,15 @@ virDomainDefParseXML(xmlDocPtr xml,
         if (virDomainCachetuneDefParse(def, ctxt, nodes[i], flags) < 0)
             goto error;
     }
+
     VIR_FREE(nodes);
 
+    if (virDomainCpuResmonDefParse(def, ctxt, flags) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                _("cannot extract CPU resource monitoring group setting"));
+        goto error;
+    }
+
     if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
         goto error;
 
@@ -26943,6 +27224,41 @@ virDomainCachetuneDefFormat(virBufferPtr buf,
 
 
 static int
+virDomainCpuResmonDefFormat(virBufferPtr buf,
+                            virDomainDefPtr def,
+                            unsigned int flags)
+{
+    char *vcpus = NULL;
+    size_t i = 0;
+    int ret = -1;
+
+    for (i = 0; i < def->nresmons; i++) {
+        vcpus = virBitmapFormat(def->resmons[i]->vcpus);
+        if (!vcpus)
+            goto cleanup;
+
+        virBufferAsprintf(buf, "<resmongroup vcpus='%s'", vcpus);
+
+        if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
+            const char *mon_id = virResctrlMonGetID(def->resmons[i]->mon);
+            if (!mon_id)
+                goto cleanup;
+
+            virBufferAsprintf(buf, " id='%s'", mon_id);
+        }
+        virBufferAddLit(buf, "/>\n");
+
+        VIR_FREE(vcpus);
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(vcpus);
+    return ret;
+}
+
+
+static int
 virDomainCputuneDefFormat(virBufferPtr buf,
                           virDomainDefPtr def,
                           unsigned int flags)
@@ -27047,6 +27363,8 @@ virDomainCputuneDefFormat(virBufferPtr buf,
     for (i = 0; i < def->ncachetunes; i++)
         virDomainCachetuneDefFormat(&childrenBuf, def->cachetunes[i], flags);
 
+    virDomainCpuResmonDefFormat(&childrenBuf, def, flags);
+
     if (virBufferCheckError(&childrenBuf) < 0)
         return -1;
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 41d2748..7d31254 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2237,6 +2237,13 @@ struct _virDomainCachetuneDef {
     virResctrlAllocPtr alloc;
 };
 
+typedef struct _virDomainCpuResmonDef virDomainCpuResmonDef;
+typedef virDomainCpuResmonDef *virDomainCpuResmonDefPtr;
+
+struct _virDomainCpuResmonDef {
+    virBitmapPtr vcpus;
+    virResctrlMonPtr mon;
+};
 
 typedef struct _virDomainVcpuDef virDomainVcpuDef;
 typedef virDomainVcpuDef *virDomainVcpuDefPtr;
@@ -2413,6 +2420,9 @@ struct _virDomainDef {
     virDomainCachetuneDefPtr *cachetunes;
     size_t ncachetunes;
 
+    virDomainCpuResmonDefPtr *resmons;
+    size_t nresmons;
+
     virDomainNumaPtr numa;
     virDomainResourceDefPtr resource;
     virDomainIdMapDef idmap;
@@ -3640,4 +3650,19 @@ virDomainDiskGetDetectZeroesMode(virDomainDiskDiscard discard,
 bool
 virDomainDefHasManagedPR(const virDomainDef *def);
 
+bool
+virDomainCpuResmonDefValidate(virDomainDefPtr def,
+                              const char *id,
+                              virBitmapPtr vcpus,
+                              virResctrlAllocPtr *pairedalloc);
+
+virDomainCpuResmonDefPtr
+virDomainCpuResmonDefAdd(virDomainDefPtr def,
+                         virBitmapPtr vcpus,
+                         const char *monid);
+
+virResctrlMonPtr
+virDomainCpuResmonDefRemove(virDomainDefPtr def,
+                            const char *monid);
+
 #endif /* __DOMAIN_CONF_H */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b10a3a5..9c2b2f0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -243,6 +243,9 @@ virDomainControllerRemove;
 virDomainControllerTypeToString;
 virDomainCpuPlacementModeTypeFromString;
 virDomainCpuPlacementModeTypeToString;
+virDomainCpuResmonDefAdd;
+virDomainCpuResmonDefRemove;
+virDomainCpuResmonDefValidate;
 virDomainDefAddController;
 virDomainDefAddImplicitDevices;
 virDomainDefAddUSBController;
-- 
2.7.4




More information about the libvir-list mailing list