0a7476
From a7292e2be3fef0c14d5393120471b1dc5d7a5adb Mon Sep 17 00:00:00 2001
0a7476
Message-Id: <a7292e2be3fef0c14d5393120471b1dc5d7a5adb@dist-git>
0a7476
From: Bing Niu <bing.niu@intel.com>
0a7476
Date: Mon, 15 Apr 2019 17:33:00 +0200
0a7476
Subject: [PATCH] conf: Add memory bandwidth allocation capability of host
0a7476
MIME-Version: 1.0
0a7476
Content-Type: text/plain; charset=UTF-8
0a7476
Content-Transfer-Encoding: 8bit
0a7476
0a7476
Add new XML section to report host's memory bandwidth allocation
0a7476
capability. The format as below example:
0a7476
0a7476
 <host>
0a7476
 .....
0a7476
   <memory_bandwidth>
0a7476
     <node id='0' cpus='0-19'>
0a7476
       <control granularity='10' min ='10' maxAllocs='8'/>
0a7476
     </node>
0a7476
   </memory_bandwidth>
0a7476
</host>
0a7476
0a7476
granularity   ---- granularity of memory bandwidth, unit percentage.
0a7476
min           ---- minimum memory bandwidth allowed, unit percentage.
0a7476
maxAllocs     ---- maximum memory bandwidth allocation group supported.
0a7476
0a7476
Signed-off-by: Bing Niu <bing.niu@intel.com>
0a7476
Reviewed-by: John Ferlan <jferlan@redhat.com>
0a7476
(cherry picked from commit 7995fecc25c6bc8d0ebb243ea2c8765b076c8974)
0a7476
0a7476
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1468650
0a7476
0a7476
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
0a7476
Message-Id: <eda433c39cf6e5462b3076fa3049ac5a042af0c1.1555342313.git.phrdina@redhat.com>
0a7476
Reviewed-by: Ján Tomko <jtomko@redhat.com>
0a7476
---
0a7476
 docs/schemas/capability.rng                   |  33 ++++++
0a7476
 src/conf/capabilities.c                       | 107 ++++++++++++++++++
0a7476
 src/conf/capabilities.h                       |  11 ++
0a7476
 src/util/virresctrl.c                         |  20 ++++
0a7476
 src/util/virresctrl.h                         |  15 +++
0a7476
 .../resctrl/info/MB/bandwidth_gran            |   1 +
0a7476
 .../resctrl/info/MB/min_bandwidth             |   1 +
0a7476
 .../linux-resctrl/resctrl/info/MB/num_closids |   1 +
0a7476
 .../vircaps-x86_64-resctrl.xml                |   8 ++
0a7476
 tests/virresctrldata/resctrl.schemata         |   1 +
0a7476
 10 files changed, 198 insertions(+)
0a7476
 create mode 100644 tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/bandwidth_gran
0a7476
 create mode 100644 tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/min_bandwidth
0a7476
 create mode 100644 tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/num_closids
0a7476
0a7476
diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng
0a7476
index 52164d5ecb..d61515ccbe 100644
0a7476
--- a/docs/schemas/capability.rng
0a7476
+++ b/docs/schemas/capability.rng
0a7476
@@ -51,6 +51,9 @@
0a7476
       <optional>
0a7476
         <ref name='cache'/>
0a7476
       </optional>
0a7476
+      <optional>
0a7476
+        <ref name='memory_bandwidth'/>
0a7476
+      </optional>
0a7476
       <zeroOrMore>
0a7476
         <ref name='secmodel'/>
0a7476
       </zeroOrMore>
0a7476
@@ -326,6 +329,36 @@
0a7476
     </attribute>
0a7476
   </define>
0a7476
 
0a7476
+  <define name='memory_bandwidth'>
0a7476
+    <element name='memory_bandwidth'>
0a7476
+      <oneOrMore>
0a7476
+        <element name='node'>
0a7476
+          <attribute name='id'>
0a7476
+            <ref name='unsignedInt'/>
0a7476
+          </attribute>
0a7476
+          <attribute name='cpus'>
0a7476
+            <ref name='cpuset'/>
0a7476
+          </attribute>
0a7476
+          <zeroOrMore>
0a7476
+            <element name='control'>
0a7476
+              <attribute name='granularity'>
0a7476
+                <ref name='unsignedInt'/>
0a7476
+              </attribute>
0a7476
+            <optional>
0a7476
+              <attribute name='min'>
0a7476
+                <ref name='unsignedInt'/>
0a7476
+            </attribute>
0a7476
+            </optional>
0a7476
+              <attribute name='maxAllocs'>
0a7476
+                <ref name='unsignedInt'/>
0a7476
+              </attribute>
0a7476
+            </element>
0a7476
+          </zeroOrMore>
0a7476
+        </element>
0a7476
+      </oneOrMore>
0a7476
+    </element>
0a7476
+  </define>
0a7476
+
0a7476
   <define name='guestcaps'>
0a7476
     <element name='guest'>
0a7476
       <ref name='ostype'/>
0a7476
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
0a7476
index 7a810efa66..3d893447cb 100644
0a7476
--- a/src/conf/capabilities.c
0a7476
+++ b/src/conf/capabilities.c
0a7476
@@ -197,6 +197,16 @@ virCapabilitiesFreeNUMAInfo(virCapsPtr caps)
0a7476
     caps->host.nnumaCell = 0;
0a7476
 }
0a7476
 
0a7476
+static void
0a7476
+virCapsHostMemBWNodeFree(virCapsHostMemBWNodePtr ptr)
0a7476
+{
0a7476
+    if (!ptr)
0a7476
+        return;
0a7476
+
0a7476
+    virBitmapFree(ptr->cpus);
0a7476
+    VIR_FREE(ptr);
0a7476
+}
0a7476
+
0a7476
 static void
0a7476
 virCapabilitiesClearSecModel(virCapsHostSecModelPtr secmodel)
0a7476
 {
0a7476
@@ -239,6 +249,10 @@ virCapsDispose(void *object)
0a7476
         virCapsHostCacheBankFree(caps->host.caches[i]);
0a7476
     VIR_FREE(caps->host.caches);
0a7476
 
0a7476
+    for (i = 0; i < caps->host.nnodes; i++)
0a7476
+        virCapsHostMemBWNodeFree(caps->host.nodes[i]);
0a7476
+    VIR_FREE(caps->host.nodes);
0a7476
+
0a7476
     VIR_FREE(caps->host.netprefix);
0a7476
     VIR_FREE(caps->host.pagesSize);
0a7476
     virCPUDefFree(caps->host.cpu);
0a7476
@@ -957,6 +971,58 @@ virCapabilitiesFormatCaches(virBufferPtr buf,
0a7476
     return 0;
0a7476
 }
0a7476
 
0a7476
+static int
0a7476
+virCapabilitiesFormatMemoryBandwidth(virBufferPtr buf,
0a7476
+                                     size_t nnodes,
0a7476
+                                     virCapsHostMemBWNodePtr *nodes)
0a7476
+{
0a7476
+    size_t i = 0;
0a7476
+    virBuffer controlBuf = VIR_BUFFER_INITIALIZER;
0a7476
+
0a7476
+    if (!nnodes)
0a7476
+        return 0;
0a7476
+
0a7476
+    virBufferAddLit(buf, "<memory_bandwidth>\n");
0a7476
+    virBufferAdjustIndent(buf, 2);
0a7476
+
0a7476
+    for (i = 0; i < nnodes; i++) {
0a7476
+        virCapsHostMemBWNodePtr node = nodes[i];
0a7476
+        virResctrlInfoMemBWPerNodePtr control = &node->control;
0a7476
+        char *cpus_str = virBitmapFormat(node->cpus);
0a7476
+
0a7476
+        if (!cpus_str)
0a7476
+            return -1;
0a7476
+
0a7476
+        virBufferAsprintf(buf,
0a7476
+                          "
0a7476
+                          node->id, cpus_str);
0a7476
+        VIR_FREE(cpus_str);
0a7476
+
0a7476
+        virBufferSetChildIndent(&controlBuf, buf);
0a7476
+        virBufferAsprintf(&controlBuf,
0a7476
+                          "
0a7476
+                          "maxAllocs='%u'/>\n",
0a7476
+                          control->granularity, control->min,
0a7476
+                          control->max_allocation);
0a7476
+
0a7476
+        if (virBufferCheckError(&controlBuf) < 0)
0a7476
+            return -1;
0a7476
+
0a7476
+        if (virBufferUse(&controlBuf)) {
0a7476
+            virBufferAddLit(buf, ">\n");
0a7476
+            virBufferAddBuffer(buf, &controlBuf);
0a7476
+            virBufferAddLit(buf, "</node>\n");
0a7476
+        } else {
0a7476
+            virBufferAddLit(buf, "/>\n");
0a7476
+        }
0a7476
+    }
0a7476
+
0a7476
+    virBufferAdjustIndent(buf, -2);
0a7476
+    virBufferAddLit(buf, "</memory_bandwidth>\n");
0a7476
+
0a7476
+    return 0;
0a7476
+}
0a7476
+
0a7476
 /**
0a7476
  * virCapabilitiesFormatXML:
0a7476
  * @caps: capabilities to format
0a7476
@@ -1060,6 +1126,10 @@ virCapabilitiesFormatXML(virCapsPtr caps)
0a7476
                                     caps->host.caches) < 0)
0a7476
         goto error;
0a7476
 
0a7476
+    if (virCapabilitiesFormatMemoryBandwidth(&buf, caps->host.nnodes,
0a7476
+                                             caps->host.nodes) < 0)
0a7476
+        goto error;
0a7476
+
0a7476
     for (i = 0; i < caps->host.nsecModels; i++) {
0a7476
         virBufferAddLit(&buf, "<secmodel>\n");
0a7476
         virBufferAdjustIndent(&buf, 2);
0a7476
@@ -1602,6 +1672,40 @@ virCapabilitiesInitResctrl(virCapsPtr caps)
0a7476
 }
0a7476
 
0a7476
 
0a7476
+static int
0a7476
+virCapabilitiesInitResctrlMemory(virCapsPtr caps)
0a7476
+{
0a7476
+    virCapsHostMemBWNodePtr node = NULL;
0a7476
+    size_t i = 0;
0a7476
+    int ret = -1;
0a7476
+
0a7476
+    for (i = 0; i < caps->host.ncaches; i++) {
0a7476
+        virCapsHostCacheBankPtr bank = caps->host.caches[i];
0a7476
+        if (VIR_ALLOC(node) < 0)
0a7476
+            goto cleanup;
0a7476
+
0a7476
+        if (virResctrlInfoGetMemoryBandwidth(caps->host.resctrl,
0a7476
+                                             bank->level, &node->control) > 0) {
0a7476
+            node->id = bank->id;
0a7476
+            if (!(node->cpus = virBitmapNewCopy(bank->cpus)))
0a7476
+                goto cleanup;
0a7476
+
0a7476
+            if (VIR_APPEND_ELEMENT(caps->host.nodes,
0a7476
+                                   caps->host.nnodes, node) < 0) {
0a7476
+                goto cleanup;
0a7476
+            }
0a7476
+        }
0a7476
+        virCapsHostMemBWNodeFree(node);
0a7476
+        node = NULL;
0a7476
+    }
0a7476
+
0a7476
+    ret = 0;
0a7476
+ cleanup:
0a7476
+    virCapsHostMemBWNodeFree(node);
0a7476
+    return ret;
0a7476
+}
0a7476
+
0a7476
+
0a7476
 int
0a7476
 virCapabilitiesInitCaches(virCapsPtr caps)
0a7476
 {
0a7476
@@ -1731,6 +1835,9 @@ virCapabilitiesInitCaches(virCapsPtr caps)
0a7476
     qsort(caps->host.caches, caps->host.ncaches,
0a7476
           sizeof(*caps->host.caches), virCapsHostCacheBankSorter);
0a7476
 
0a7476
+    if (virCapabilitiesInitResctrlMemory(caps) < 0)
0a7476
+        goto cleanup;
0a7476
+
0a7476
     ret = 0;
0a7476
  cleanup:
0a7476
     VIR_FREE(type);
0a7476
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
0a7476
index fe1b9ea455..046e275ac6 100644
0a7476
--- a/src/conf/capabilities.h
0a7476
+++ b/src/conf/capabilities.h
0a7476
@@ -151,6 +151,14 @@ struct _virCapsHostCacheBank {
0a7476
     virResctrlInfoPerCachePtr *controls;
0a7476
 };
0a7476
 
0a7476
+typedef struct _virCapsHostMemBWNode virCapsHostMemBWNode;
0a7476
+typedef virCapsHostMemBWNode *virCapsHostMemBWNodePtr;
0a7476
+struct _virCapsHostMemBWNode {
0a7476
+    unsigned int id;
0a7476
+    virBitmapPtr cpus;  /* All CPUs that belong to this node*/
0a7476
+    virResctrlInfoMemBWPerNode control;
0a7476
+};
0a7476
+
0a7476
 typedef struct _virCapsHost virCapsHost;
0a7476
 typedef virCapsHost *virCapsHostPtr;
0a7476
 struct _virCapsHost {
0a7476
@@ -175,6 +183,9 @@ struct _virCapsHost {
0a7476
     size_t ncaches;
0a7476
     virCapsHostCacheBankPtr *caches;
0a7476
 
0a7476
+    size_t nnodes;
0a7476
+    virCapsHostMemBWNodePtr *nodes;
0a7476
+
0a7476
     size_t nsecModels;
0a7476
     virCapsHostSecModelPtr secModels;
0a7476
 
0a7476
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
0a7476
index adf36a7c0a..4b5442f879 100644
0a7476
--- a/src/util/virresctrl.c
0a7476
+++ b/src/util/virresctrl.c
0a7476
@@ -629,6 +629,26 @@ virResctrlInfoIsEmpty(virResctrlInfoPtr resctrl)
0a7476
 }
0a7476
 
0a7476
 
0a7476
+int
0a7476
+virResctrlInfoGetMemoryBandwidth(virResctrlInfoPtr resctrl,
0a7476
+                                 unsigned int level,
0a7476
+                                 virResctrlInfoMemBWPerNodePtr control)
0a7476
+{
0a7476
+    virResctrlInfoMemBWPtr membw_info = resctrl->membw_info;
0a7476
+
0a7476
+    if (!membw_info)
0a7476
+        return 0;
0a7476
+
0a7476
+    if (membw_info->last_level_cache != level)
0a7476
+        return 0;
0a7476
+
0a7476
+    control->granularity = membw_info->bandwidth_granularity;
0a7476
+    control->min = membw_info->min_bandwidth;
0a7476
+    control->max_allocation = membw_info->max_allocation;
0a7476
+    return 1;
0a7476
+}
0a7476
+
0a7476
+
0a7476
 int
0a7476
 virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
0a7476
                        unsigned int level,
0a7476
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
0a7476
index 8d62517aa1..cfd56ddd06 100644
0a7476
--- a/src/util/virresctrl.h
0a7476
+++ b/src/util/virresctrl.h
0a7476
@@ -50,6 +50,17 @@ struct _virResctrlInfoPerCache {
0a7476
     unsigned int max_allocation;
0a7476
 };
0a7476
 
0a7476
+typedef struct _virResctrlInfoMemBWPerNode virResctrlInfoMemBWPerNode;
0a7476
+typedef virResctrlInfoMemBWPerNode *virResctrlInfoMemBWPerNodePtr;
0a7476
+struct _virResctrlInfoMemBWPerNode {
0a7476
+    /* Smallest possible increase of the allocation bandwidth in percentage */
0a7476
+    unsigned int granularity;
0a7476
+    /* Minimal allocatable bandwidth in percentage */
0a7476
+    unsigned int min;
0a7476
+    /* Maximum number of simultaneous allocations */
0a7476
+    unsigned int max_allocation;
0a7476
+};
0a7476
+
0a7476
 typedef struct _virResctrlInfo virResctrlInfo;
0a7476
 typedef virResctrlInfo *virResctrlInfoPtr;
0a7476
 
0a7476
@@ -63,6 +74,10 @@ virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
0a7476
                        size_t *ncontrols,
0a7476
                        virResctrlInfoPerCachePtr **controls);
0a7476
 
0a7476
+int
0a7476
+virResctrlInfoGetMemoryBandwidth(virResctrlInfoPtr resctrl,
0a7476
+                                 unsigned int level,
0a7476
+                                 virResctrlInfoMemBWPerNodePtr control);
0a7476
 /* Alloc-related things */
0a7476
 typedef struct _virResctrlAlloc virResctrlAlloc;
0a7476
 typedef virResctrlAlloc *virResctrlAllocPtr;
0a7476
diff --git a/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/bandwidth_gran b/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/bandwidth_gran
0a7476
new file mode 100644
0a7476
index 0000000000..f599e28b8a
0a7476
--- /dev/null
0a7476
+++ b/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/bandwidth_gran
0a7476
@@ -0,0 +1 @@
0a7476
+10
0a7476
diff --git a/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/min_bandwidth b/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/min_bandwidth
0a7476
new file mode 100644
0a7476
index 0000000000..f599e28b8a
0a7476
--- /dev/null
0a7476
+++ b/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/min_bandwidth
0a7476
@@ -0,0 +1 @@
0a7476
+10
0a7476
diff --git a/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/num_closids b/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/num_closids
0a7476
new file mode 100644
0a7476
index 0000000000..b8626c4cff
0a7476
--- /dev/null
0a7476
+++ b/tests/vircaps2xmldata/linux-resctrl/resctrl/info/MB/num_closids
0a7476
@@ -0,0 +1 @@
0a7476
+4
0a7476
diff --git a/tests/vircaps2xmldata/vircaps-x86_64-resctrl.xml b/tests/vircaps2xmldata/vircaps-x86_64-resctrl.xml
0a7476
index 4840614e86..9b00cf0995 100644
0a7476
--- a/tests/vircaps2xmldata/vircaps-x86_64-resctrl.xml
0a7476
+++ b/tests/vircaps2xmldata/vircaps-x86_64-resctrl.xml
0a7476
@@ -49,6 +49,14 @@
0a7476
         <control granularity='768' min='1536' unit='KiB' type='both' maxAllocs='4'/>
0a7476
       </bank>
0a7476
     </cache>
0a7476
+    <memory_bandwidth>
0a7476
+      <node id='0' cpus='0-5'>
0a7476
+        <control granularity='10' min ='10' maxAllocs='4'/>
0a7476
+      </node>
0a7476
+      <node id='1' cpus='6-11'>
0a7476
+        <control granularity='10' min ='10' maxAllocs='4'/>
0a7476
+      </node>
0a7476
+    </memory_bandwidth>
0a7476
   </host>
0a7476
 
0a7476
 </capabilities>
0a7476
diff --git a/tests/virresctrldata/resctrl.schemata b/tests/virresctrldata/resctrl.schemata
0a7476
index fa980e58c9..2578822b70 100644
0a7476
--- a/tests/virresctrldata/resctrl.schemata
0a7476
+++ b/tests/virresctrldata/resctrl.schemata
0a7476
@@ -1 +1,2 @@
0a7476
 L3:0=000ff;1=000f0
0a7476
+MB:0=100;1=100
0a7476
-- 
0a7476
2.21.0
0a7476