[libvirt] [PATCH resend V10 03/12] Resctrl: Add new xml element to support cache tune

Martin Kletzander mkletzan at redhat.com
Wed Mar 15 14:11:26 UTC 2017


On Mon, Mar 06, 2017 at 06:06:32PM +0800, Eli Qiao wrote:
>This patch adds new xml element to support cache tune as:
>
><cputune>
>  ...
>  <cachetune id='1' host_id='0' type='l3' size='2816' unit='KiB'

Again, this was already discussed, probably, I just can't find the
source of it.  But host_id actually already selects what cache is
supposed to be used, so instead of type='l3' we only need scope='both'
(or data/instruction) there.  Or am I missing something?  What I'm
concerned about is that the host_id is mostly stable on one host (when
the previously mentioned problems are fixed), but it will make no sense
when the VM is migrated to another one.  Unfortunately, the only
solution I can think of is using multiple keys to precisely describe the
bank we want (e.g. host's cpu id, cache level and scope), but that seems
very unclean.

>  vcpus='1,2'/>
>  ...
></cputune>
>
>id: any non-minus number
>host_id: reference of the host's cache banks id, it's from capabilities
>type: cache bank type
>size: should be multiples of the min_size of the bank on host.
>vcpus: cache allocation on vcpu set, if empty, will apply the allocation
>on all vcpus
>---
> docs/schemas/domaincommon.rng |  46 +++++++++++++
> src/conf/domain_conf.c        | 152 ++++++++++++++++++++++++++++++++++++++++++
> src/conf/domain_conf.h        |  19 ++++++
> src/util/virresctrl.c         |  29 ++++++--
> src/util/virresctrl.h         |   4 +-
> 5 files changed, 244 insertions(+), 6 deletions(-)
>
>diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
>index c64544a..efc84c5 100644
>--- a/docs/schemas/domaincommon.rng
>+++ b/docs/schemas/domaincommon.rng
>@@ -825,6 +825,32 @@
>             </attribute>
>           </element>
>         </zeroOrMore>
>+        <zeroOrMore>
>+          <element name="cachetune">
>+            <attribute name="id">
>+              <ref name="cacheid"/>
>+            </attribute>

this should be optional when defining a domain, we can fill in the ids
after (or during) parsing.

>+            <attribute name="host_id">
>+              <ref name="hostid"/>
>+            </attribute>
>+            <attribute name="type">
>+              <ref name="cachetype"/>
>+            </attribute>
>+            <attribute name="size">
>+              <ref name="unsignedInt"/>
>+            </attribute>
>+            <optional>
>+              <attribute name="unit">
>+                <ref name="cacheunit"/>
>+              </attribute>
>+            </optional>
>+            <optional>
>+              <attribute name="vcpus">
>+                <ref name="cpuset"/>
>+              </attribute>
>+            </optional>
>+          </element>
>+        </zeroOrMore>
>         <optional>
>           <element name="emulatorpin">
>             <attribute name="cpuset">
>@@ -5490,6 +5516,26 @@
>       <param name="minInclusive">-1</param>
>     </data>
>   </define>
>+  <define name="cacheid">
>+    <data type="unsignedShort">
>+      <param name="pattern">[0-9]+</param>

unsignedShort doesn't need pattern, wherever you copied that from, it
should be cleaned up there as well (of course not needed to be part of
this series).  I'll include such things with other silly one-line fixes
in the series so that we get rid of it.

>+    </data>
>+  </define>
>+  <define name="hostid">
>+    <data type="unsignedShort">
>+      <param name="pattern">[0-9]+</param>
>+    </data>
>+  </define>
>+  <define name="cachetype">
>+    <data type="string">
>+      <param name="pattern">(l3)</param>
>+    </data>

What's the difference to <value>l3</value> ???

>+  </define>
>+  <define name="cacheunit">
>+    <data type="string">
>+      <param name="pattern">KiB</param>
>+    </data>
>+  </define>
>   <!-- weight currently is in range [100, 1000] -->
>   <define name="weight">
>     <data type="unsignedInt">
>diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
>index 97d42fe..652f4ca 100644
>--- a/src/conf/domain_conf.c
>+++ b/src/conf/domain_conf.c
>@@ -56,6 +56,7 @@
> #include "virstring.h"
> #include "virnetdev.h"
> #include "virhostdev.h"
>+#include "virresctrl.h"
>
> #define VIR_FROM_THIS VIR_FROM_DOMAIN
>
>@@ -15745,6 +15746,127 @@ virDomainVcpuPinDefParseXML(virDomainDefPtr def,
>     return ret;
> }
>
>+/* Parse the XML definition for cachetune
>+ * and a cachetune has the form
>+ * <cachetune id='0' host_id='0' type='l3' size='1024' unit='KiB'/>
>+ */
>+static int
>+virDomainCacheTuneDefParseXML(virDomainDefPtr def,
>+                              int n,
>+                              xmlNodePtr* nodes)
>+{
>+    char* tmp = NULL;
>+    size_t i, j;
>+    int type = -1;
>+    virDomainCacheBankPtr bank = NULL;
>+    virResCtrlPtr resctrl;
>+
>+    if (VIR_ALLOC_N(bank, n) < 0)
>+        goto cleanup;
>+
>+    for (i = 0; i < n; i++) {
>+        if (!(tmp = virXMLPropString(nodes[i], "id"))) {
>+            virReportError(VIR_ERR_XML_ERROR, "%s", _("missing id in cache tune"));
>+            goto cleanup;
>+        }
>+        if (virStrToLong_uip(tmp, NULL, 10, &(bank[i].id)) < 0) {
>+            virReportError(VIR_ERR_XML_ERROR,
>+                           _("invalid setting for cache id '%s'"), tmp);
>+            goto cleanup;
>+        }
>+

As said before, ids can be calculated later, we don't require
referencing them in the user's provided XML anywhere, or do we?

>+        VIR_FREE(tmp);
>+        if (!(tmp = virXMLPropString(nodes[i], "host_id"))) {
>+            virReportError(VIR_ERR_XML_ERROR, "%s", _("missing host id in cache tune"));
>+            goto cleanup;
>+        }
>+        if (virStrToLong_uip(tmp, NULL, 10, &(bank[i].host_id)) < 0) {
>+            virReportError(VIR_ERR_XML_ERROR,
>+                           _("invalid setting for cache host id '%s'"), tmp);
>+            goto cleanup;
>+        }
>+        VIR_FREE(tmp);
>+
>+        if (!(tmp = virXMLPropString(nodes[i], "size"))) {
>+            virReportError(VIR_ERR_XML_ERROR, "%s", _("missing size in cache tune"));
>+            goto cleanup;
>+        }
>+        if (virStrToLong_ull(tmp, NULL, 10, &(bank[i].size)) < 0) {
>+            virReportError(VIR_ERR_XML_ERROR,
>+                           _("invalid setting for cache size '%s'"), tmp);
>+            goto cleanup;
>+        }
>+        VIR_FREE(tmp);
>+
>+        if (!(tmp = virXMLPropString(nodes[i], "type"))) {
>+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>+                           _("missing cache type"));
>+            goto cleanup;
>+        }
>+
>+        if ((type = virResCtrlTypeFromString(tmp)) < 0) {
>+            virReportError(VIR_ERR_XML_ERROR,
>+                    _("'unsupported cache type '%s'"), tmp);
>+            goto cleanup;
>+        }
>+
>+        resctrl = virResCtrlGet(type);
>+
>+        if (resctrl == NULL || !resctrl->enabled) {
>+            virReportError(VIR_ERR_XML_ERROR,
>+                    _("'host doesn't enabled cache type '%s'"), tmp);

s/'host/host/, s/enabled/support/??

This should be in PostParse callback, though.  Or even better in
qemuProcessStartValidate() so that the domain doesn't disappear when the
host changes kernels or kernel config or anything else.

>+            goto cleanup;
>+        }
>+
>+        bool found_host_id = false;
>+        /* Loop for banks to search host_id */
>+        for (j = 0; j < resctrl->num_banks; j++) {
>+            if (resctrl->cache_banks[j].host_id == bank[i].host_id) {
>+                found_host_id = true;
>+                break;
>+            }
>+        }
>+
>+        if (! found_host_id) {

no spaces after exclamation mark, please

>+            virReportError(VIR_ERR_XML_ERROR,
>+                    _("'cache bank's host id %u not found on the host"),
>+                    bank[i].host_id);

Indentation, ...

>+            goto cleanup;
>+        }
>+
>+        if (bank[i].size == 0 ||
>+                bank[i].size % resctrl->cache_banks[j].cache_min != 0) {
>+            virReportError(VIR_ERR_XML_ERROR,
>+                           _("'the size should be multiples of '%llu'"),
>+                           resctrl->cache_banks[j].cache_min);

... indentation everywhere!

>@@ -23554,6 +23684,26 @@ virDomainSchedulerFormat(virBufferPtr buf,
>
> }
>
>+static void
>+virDomainCacheTuneDefFormat(virBufferPtr buf,
>+                            virDomainCachetunePtr cache)
>+{
>+    size_t i;
>+    for (i = 0; i < cache->n_banks; i ++) {
>+        virBufferAsprintf(buf, "<cachetune id='%u' host_id='%u' "
>+                               "type='%s' size='%llu' unit='KiB'",
>+                               cache->cache_banks[i].id,
>+                               cache->cache_banks[i].host_id,
>+                               cache->cache_banks[i].type,
>+                               cache->cache_banks[i].size);
>+
>+        if (cache->cache_banks[i].vcpus)
>+            virBufferAsprintf(buf, " vcpus='%s'/>\n",
>+                    virBitmapFormat(cache->cache_banks[i].vcpus));
>+        else
>+            virBufferAddLit(buf, "/>\n");
>+    }
>+}
>
> static int
> virDomainCputuneDefFormat(virBufferPtr buf,
>@@ -23617,6 +23767,8 @@ virDomainCputuneDefFormat(virBufferPtr buf,
>         VIR_FREE(cpumask);
>     }
>
>+    virDomainCacheTuneDefFormat(&childrenBuf, &def->cachetune);
>+
>     if (def->cputune.emulatorpin) {
>         char *cpumask;
>         virBufferAddLit(&childrenBuf, "<emulatorpin ");
>diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
>index 1e53cc3..3da5d61 100644
>--- a/src/conf/domain_conf.h
>+++ b/src/conf/domain_conf.h
>@@ -2153,6 +2153,23 @@ struct _virDomainMemtune {
>     int allocation; /* enum virDomainMemoryAllocation */
> };
>
>+typedef struct _virDomainCacheBank virDomainCacheBank;
>+typedef virDomainCacheBank *virDomainCacheBankPtr;
>+struct _virDomainCacheBank {
>+    unsigned int id;
>+    unsigned int host_id;
>+    unsigned long long size;
>+    char *type;
>+    virBitmapPtr vcpus;
>+};
>+
>+typedef struct _virDomainCachetune virDomainCachetune;
>+typedef virDomainCachetune *virDomainCachetunePtr;
>+struct _virDomainCachetune {
>+    size_t n_banks;
>+    virDomainCacheBankPtr cache_banks;
>+};
>+
> typedef struct _virDomainPowerManagement virDomainPowerManagement;
> typedef virDomainPowerManagement *virDomainPowerManagementPtr;
>
>@@ -2216,6 +2233,8 @@ struct _virDomainDef {
>
>     virDomainCputune cputune;
>
>+    virDomainCachetune cachetune;
>+
>     virDomainNumaPtr numa;
>     virDomainResourceDefPtr resource;
>     virDomainIdMapDef idmap;
>diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
>index 44a47cc..eee6675 100644
>--- a/src/util/virresctrl.c
>+++ b/src/util/virresctrl.c
>@@ -32,15 +32,34 @@
> VIR_LOG_INIT("util.resctrl");
>
> #define VIR_FROM_THIS VIR_FROM_RESCTRL
>-
>-#define RESCTRL_DIR "/sys/fs/resctrl"
>-#define RESCTRL_INFO_DIR "/sys/fs/resctrl/info"
>-#define SYSFS_SYSTEM_PATH "/sys/devices/system"
>-
> #define MAX_CPU_SOCKET_NUM 8
> #define MAX_CBM_BIT_LEN 32
> #define MAX_SCHEMATA_LEN 1024
> #define MAX_FILE_LEN (10 * 1024 * 1024)
>+#define RESCTRL_DIR "/sys/fs/resctrl"
>+#define RESCTRL_INFO_DIR "/sys/fs/resctrl/info"
>+#define SYSFS_SYSTEM_PATH "/sys/devices/system"
>+

your diffs are weird, why does it show like this?

>+VIR_ENUM_IMPL(virResCtrl, VIR_RDT_RESOURCE_LAST,
>+              "l3", "l3data", "l3code", "l2");
>+
>+#define CONSTRUCT_RESCTRL_PATH(domain_name, item_name) \
>+do { \
>+    if (NULL == domain_name) { \
>+        if (virAsprintf(&path, "%s/%s", RESCTRL_DIR, item_name) < 0)\
>+            return -1; \
>+    } else { \
>+        if (virAsprintf(&path, "%s/%s/%s", RESCTRL_DIR, \
>+                                        domain_name, \
>+                                        item_name) < 0) \
>+            return -1;  \
>+    } \

For macros like this, it's more readable when the backslashes are
aligned (your editor should be able to do that pretty automatically)

But for such function it's not very nice to use macro.  Just use
function (if needed after reworking the patches).

Also you'r enot using the macro here, but in later patch, so it doesn't
make sense to add it in this commit.  Each commit should be somehow one
isolated change with all things in one commit somehow related to each
other.

>+} while (0)
>+
>+#define VIR_RESCTRL_ENABLED(type) \
>+    resctrlall[type].enabled
>+
>+#define VIR_RESCTRL_GET_SCHEMATA(count) ((1 << count) - 1)
>

I thought we have BITS or something similar for this, but I can't find
it, but BITS feels more descriptive.

> static unsigned int host_id;
>
>diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
>index 5a6a344..074d307 100644
>--- a/src/util/virresctrl.h
>+++ b/src/util/virresctrl.h
>@@ -25,6 +25,7 @@
> # define __VIR_RESCTRL_H__
>
> # include "virbitmap.h"
>+# include "virutil.h"
>
> enum {
>     VIR_RDT_RESOURCE_L3,
>@@ -32,9 +33,10 @@ enum {
>     VIR_RDT_RESOURCE_L3CODE,
>     VIR_RDT_RESOURCE_L2,
>     /* Must be the last */
>-    VIR_RDT_RESOURCE_LAST,
>+    VIR_RDT_RESOURCE_LAST

What's the point of this being in this commit?

> };
>
>+VIR_ENUM_DECL(virResCtrl);
>
> typedef struct _virResCacheBank virResCacheBank;
> typedef virResCacheBank *virResCacheBankPtr;
>--
>1.9.1
>
>--
>libvir-list mailing list
>libvir-list at redhat.com
>https://www.redhat.com/mailman/listinfo/libvir-list
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20170315/f1ff0435/attachment-0001.sig>


More information about the libvir-list mailing list