]> xenbits.xensource.com Git - libvirt.git/commitdiff
conf: Parse and format HMAT
authorMichal Privoznik <mprivozn@redhat.com>
Wed, 27 May 2020 09:46:33 +0000 (11:46 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 8 Jul 2020 10:05:24 +0000 (12:05 +0200)
To cite ACPI specification:

  Heterogeneous Memory Attribute Table describes the memory
  attributes, such as memory side cache attributes and bandwidth
  and latency details, related to the System Physical Address
  (SPA) Memory Ranges. The software is expected to use this
  information as hint for optimization.

According to our upstream discussion [1] this is exposed under
<numa/> as <cache/> under NUMA <cell/> and <latency> or
<bandwidth/> under numa/latencies.

1: https://www.redhat.com/archives/libvir-list/2020-January/msg00422.html

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
docs/formatdomain.html.in
docs/schemas/cputypes.rng
src/conf/numa_conf.c
src/conf/numa_conf.h
src/libvirt_private.syms
tests/qemuxml2argvdata/numatune-hmat.xml [new file with mode: 0644]
tests/qemuxml2xmloutdata/numatune-hmat.xml [new symlink]
tests/qemuxml2xmltest.c

index d3f753c8d1027ea0b2992d8bc5dd27742c9d2adc..84eafe6cd20d305ddd2c94e4a188cf9c8ced884a 100644 (file)
       using 10 for local and 20 for remote distances.
     </p>
 
+    <h4><a id="hmat">ACPI Heterogeneous Memory Attribute Table</a></h4>
+
+<pre>
+...
+&lt;cpu&gt;
+  ...
+  &lt;numa&gt;
+    &lt;cell id='0' cpus='0-3' memory='512000' unit='KiB' discard='yes'/&gt;
+    &lt;cell id='1' cpus='4-7' memory='512000' unit='KiB' memAccess='shared'/&gt;
+    &lt;cell id='3' cpus='0-3' memory='2097152' unit='KiB'&gt;
+      &lt;cache level='1' associativity='direct' policy='writeback'&gt;
+        &lt;size value='10' unit='KiB'/&gt;
+        &lt;line value='8' unit='B'/&gt;
+      &lt;/cache&gt;
+    &lt;/cell&gt;
+    &lt;interconnects&gt;
+      &lt;latency initiator='0' target='0' type='access' value='5'/&gt;
+      &lt;latency initiator='0' target='0' cache='1' type='access' value='10'/&gt;
+      &lt;bandwidth initiator='0' target='0' type='access' value='204800' unit='KiB'/&gt;
+    &lt;/interconnects&gt;
+  &lt;/numa&gt;
+  ...
+&lt;/cpu&gt;
+...</pre>
+
+    <p>
+      <span class='since'>Since 6.6.0</span> the <code>cell</code> element can
+      have a <code>cache</code> child element which describes memory side cache
+      for memory proximity domains. The <code>cache</code> element has a
+      <code>level</code> attribute describing the cache level and thus the
+      element can be repeated multiple times to describe different levels of
+      the cache.
+    </p>
+
+    <p>
+      The <code>cache</code> element then has following mandatory attributes:
+    </p>
+
+    <dl>
+      <dt><code>level</code></dt>
+      <dd>
+        Level of the cache this description refers to.
+      </dd>
+
+      <dt><code>associativity</code></dt>
+      <dd>
+        Describes cache associativity (accepted values are <code>none</code>,
+        <code>direct</code> and <code>full</code>).
+      </dd>
+
+      <dt><code>policy</code></dt>
+      <dd>
+        Describes cache write associativity (accepted values are
+        <code>none</code>, <code>writeback</code> and
+        <code>writethrough</code>).
+      </dd>
+    </dl>
+
+    <p>
+      The <code>cache</code> element has two mandatory child elements then:
+      <code>size</code> and <code>line</code> which describe cache size and
+      cache line size. Both elements accept two attributes: <code>value</code>
+      and <code>unit</code> which set the value of corresponding cache
+      attribute.
+    </p>
+
+    <p>
+      The NUMA description has an optional <code>interconnects</code> element that
+      describes the normalized memory read/write latency, read/write bandwidth
+      between Initiator Proximity Domains (Processor or I/O) and Target
+      Proximity Domains (Memory).
+    </p>
+
+    <p>
+      The <code>interconnects</code> element can have zero or more
+      <code>latency</code> child elements to describe latency between two
+      memory nodes and zero or more <code>bandwidth</code> child elements to
+      describe bandwidth between two memory nodes. Both these have the
+      following mandatory attributes:
+    </p>
+
+    <dl>
+      <dt><code>initiator</code></dt>
+      <dd>Refers to the source NUMA node</dd>
+
+      <dt><code>target</code></dt>
+      <dd>Refers to the target NUMA node</dd>
+
+      <dt><code>type</code></dt>
+      <dd>The type of the access. Accepted values: <code>access</code>,
+      <code>read</code>, <code>write</code></dd>
+
+      <dt><code>value</code></dt>
+      <dd>The actual value. For latency this is delay in nanoseconds, for
+      bandwidth this value is in kibibytes per second. Use additional
+      <code>unit</code> attribute to change the units.</dd>
+    </dl>
+
+    <p>
+      To describe latency from one NUMA node to a cache of another NUMA node
+      the <code>latency</code> element has optional <code>cache</code>
+      attribute which in combination with <code>target</code> attribute creates
+      full reference to distant NUMA node's cache level. For instance,
+      <code>target='0' cache='1'</code> refers to the first level cache of NUMA
+      node 0.
+    </p>
+
     <h3><a id="elementsEvents">Events configuration</a></h3>
 
     <p>
index a1682a1003cda4a788dae2ba132ec0464e7bfa1b..ba30dbf9ff4666e452b6d471bf21376e6f3b7476 100644 (file)
 
   <define name="cpuNuma">
     <element name="numa">
-      <oneOrMore>
-        <ref name="numaCell"/>
-      </oneOrMore>
+      <interleave>
+        <oneOrMore>
+          <ref name="numaCell"/>
+        </oneOrMore>
+        <optional>
+          <ref name="numaInterconnects"/>
+        </optional>
+      </interleave>
     </element>
   </define>
 
           </oneOrMore>
         </element>
       </optional>
+      <zeroOrMore>
+        <ref name="numaCache"/>
+      </zeroOrMore>
     </element>
   </define>
 
     </element>
   </define>
 
+  <define name="numaCache">
+    <element name="cache">
+      <attribute name="level">
+        <ref name="unsignedInt"/>
+      </attribute>
+      <attribute name="associativity">
+        <choice>
+          <value>none</value>
+          <value>direct</value>
+          <value>full</value>
+        </choice>
+      </attribute>
+      <attribute name="policy">
+        <choice>
+          <value>none</value>
+          <value>writeback</value>
+          <value>writethrough</value>
+        </choice>
+      </attribute>
+      <interleave>
+        <element name="size">
+          <attribute name="value">
+            <ref name="unsignedInt"/>
+          </attribute>
+          <attribute name="unit">
+            <ref name="unit"/>
+          </attribute>
+        </element>
+        <element name="line">
+          <attribute name="value">
+            <ref name="unsignedInt"/>
+          </attribute>
+          <attribute name="unit">
+            <ref name="unit"/>
+          </attribute>
+        </element>
+      </interleave>
+    </element>
+  </define>
+
+  <define name="numaInterconnects">
+    <element name="interconnects">
+      <interleave>
+        <zeroOrMore>
+          <element name="latency">
+            <attribute name="initiator">
+              <ref name="unsignedInt"/>
+            </attribute>
+            <attribute name="target">
+              <ref name="unsignedInt"/>
+            </attribute>
+            <optional>
+              <attribute name="cache">
+                <ref name="unsignedInt"/>
+              </attribute>
+            </optional>
+            <attribute name="type">
+              <choice>
+                <value>access</value>
+                <value>read</value>
+                <value>write</value>
+              </choice>
+            </attribute>
+            <attribute name="value">
+              <ref name="unsignedInt"/>
+            </attribute>
+            <empty/>
+          </element>
+        </zeroOrMore>
+        <zeroOrMore>
+          <element name="bandwidth">
+            <attribute name="initiator">
+              <ref name="unsignedInt"/>
+            </attribute>
+            <attribute name="target">
+              <ref name="unsignedInt"/>
+            </attribute>
+            <attribute name="type">
+              <choice>
+                <value>access</value>
+                <value>read</value>
+                <value>write</value>
+              </choice>
+            </attribute>
+            <attribute name="value">
+              <ref name="unsignedInt"/>
+            </attribute>
+            <attribute name="unit">
+              <ref name="unit"/>
+            </attribute>
+          </element>
+        </zeroOrMore>
+      </interleave>
+    </element>
+  </define>
+
   <!-- Memory as an attribute is in KiB, no way to express a unit -->
   <define name="memoryKB">
     <data type="unsignedLong"/>
index 7cf62ce7dab5d71a847647b2d0c7b3e00d1c5b29..9d211d9415d9d85653624e852952f3f505866eb1 100644 (file)
@@ -59,9 +59,37 @@ VIR_ENUM_IMPL(virDomainMemoryAccess,
               "private",
 );
 
+VIR_ENUM_IMPL(virDomainCacheAssociativity,
+              VIR_DOMAIN_CACHE_ASSOCIATIVITY_LAST,
+              "none",
+              "direct",
+              "full",
+);
+
+VIR_ENUM_IMPL(virDomainCachePolicy,
+              VIR_DOMAIN_CACHE_POLICY_LAST,
+              "none",
+              "writeback",
+              "writethrough",
+);
+
+VIR_ENUM_IMPL(virDomainMemoryLatency,
+              VIR_DOMAIN_MEMORY_LATENCY_LAST,
+              "none",
+              "access",
+              "read",
+              "write"
+);
+
 typedef struct _virDomainNumaDistance virDomainNumaDistance;
 typedef virDomainNumaDistance *virDomainNumaDistancePtr;
 
+typedef struct _virDomainNumaCache virDomainNumaCache;
+typedef virDomainNumaCache *virDomainNumaCachePtr;
+
+typedef struct _virDomainNumaInterconnect virDomainNumaInterconnect;
+typedef virDomainNumaInterconnect *virDomainNumaInterconnectPtr;
+
 typedef struct _virDomainNumaNode virDomainNumaNode;
 typedef virDomainNumaNode *virDomainNumaNodePtr;
 
@@ -86,9 +114,30 @@ struct _virDomainNuma {
             unsigned int cellid;
         } *distances;           /* remote node distances */
         size_t ndistances;
+
+        struct _virDomainNumaCache {
+            unsigned int level; /* cache level */
+            unsigned int size;  /* cache size */
+            unsigned int line;  /* line size, !!! in bytes !!! */
+            virDomainCacheAssociativity associativity; /* cache associativity */
+            virDomainCachePolicy policy; /* cache policy */
+        } *caches;
+        size_t ncaches;
     } *mem_nodes;           /* guest node configuration */
     size_t nmem_nodes;
 
+    struct _virDomainNumaInterconnect {
+        virDomainNumaInterconnectType type;  /* whether structure describes latency
+                                                or bandwidth */
+        unsigned int initiator; /* the initiator NUMA node */
+        unsigned int target;    /* the target NUMA node */
+        unsigned int cache;     /* the target cache on @target; if 0 then the
+                                   memory on @target */
+        virDomainMemoryLatency accessType;  /* what type of access is defined */
+        unsigned long value;    /* value itself */
+    } *interconnects;
+    size_t ninterconnects;
+
     /* Future NUMA tuning related stuff should go here. */
 };
 
@@ -368,9 +417,13 @@ virDomainNumaFree(virDomainNumaPtr numa)
 
         if (numa->mem_nodes[i].ndistances > 0)
             VIR_FREE(numa->mem_nodes[i].distances);
+
+        VIR_FREE(numa->mem_nodes[i].caches);
     }
     VIR_FREE(numa->mem_nodes);
 
+    VIR_FREE(numa->interconnects);
+
     VIR_FREE(numa);
 }
 
@@ -841,12 +894,102 @@ virDomainNumaDefNodeDistanceParseXML(virDomainNumaPtr def,
     return ret;
 }
 
+
+static int
+virDomainNumaDefNodeCacheParseXML(virDomainNumaPtr def,
+                                  xmlXPathContextPtr ctxt,
+                                  unsigned int cur_cell)
+{
+    g_autofree xmlNodePtr *nodes = NULL;
+    int n;
+    size_t i;
+
+    if ((n = virXPathNodeSet("./cache", ctxt, &nodes)) < 0)
+        return -1;
+
+    def->mem_nodes[cur_cell].caches = g_new0(virDomainNumaCache, n);
+
+    for (i = 0; i < n; i++) {
+        VIR_XPATH_NODE_AUTORESTORE(ctxt);
+        virDomainNumaCachePtr cache = &def->mem_nodes[cur_cell].caches[i];
+        g_autofree char *tmp = NULL;
+        unsigned int level;
+        int associativity;
+        int policy;
+        unsigned long long size;
+        unsigned long long line;
+
+        if (!(tmp = virXMLPropString(nodes[i], "level"))) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Missing 'level' attribute in cache "
+                             "element for NUMA node %d"),
+                           cur_cell);
+            return -1;
+        }
+
+        if (virStrToLong_uip(tmp, NULL, 10, &level) < 0 ||
+            level == 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid 'level' attribute in cache "
+                             "element for NUMA node %d"),
+                           cur_cell);
+            return -1;
+        }
+        VIR_FREE(tmp);
+
+        if (!(tmp = virXMLPropString(nodes[i], "associativity"))) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Missing 'associativity' attribute in cache "
+                             "element for NUMA node %d"),
+                           cur_cell);
+            return -1;
+        }
+
+        if ((associativity = virDomainCacheAssociativityTypeFromString(tmp)) < 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid cache associativity '%s'"),
+                           tmp);
+            return -1;
+        }
+        VIR_FREE(tmp);
+
+        if (!(tmp = virXMLPropString(nodes[i], "policy"))) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Missing 'policy' attribute in cache "
+                             "element for NUMA node %d"),
+                           cur_cell);
+        }
+
+        if ((policy = virDomainCachePolicyTypeFromString(tmp)) < 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid cache policy '%s'"),
+                           tmp);
+            return -1;
+        }
+        VIR_FREE(tmp);
+
+        ctxt->node = nodes[i];
+        if (virDomainParseMemory("./size/@value", "./size/unit",
+                                 ctxt, &size, true, false) < 0)
+            return -1;
+
+        if (virParseScaledValue("./line/@value", "./line/unit",
+                                ctxt, &line, 1, ULLONG_MAX, true) < 0)
+            return -1;
+
+        *cache = (virDomainNumaCache){level, size, line, associativity, policy};
+        def->mem_nodes[cur_cell].ncaches++;
+    }
+
+    return 0;
+}
+
+
 int
 virDomainNumaDefParseXML(virDomainNumaPtr def,
                          xmlXPathContextPtr ctxt)
 {
     xmlNodePtr *nodes = NULL;
-    VIR_XPATH_NODE_AUTORESTORE(ctxt);
     char *tmp = NULL;
     int n;
     size_t i, j;
@@ -867,6 +1010,7 @@ virDomainNumaDefParseXML(virDomainNumaPtr def,
     def->nmem_nodes = n;
 
     for (i = 0; i < n; i++) {
+        VIR_XPATH_NODE_AUTORESTORE(ctxt);
         int rc;
         unsigned int cur_cell = i;
 
@@ -953,7 +1097,109 @@ virDomainNumaDefParseXML(virDomainNumaPtr def,
 
         /* Parse NUMA distances info */
         if (virDomainNumaDefNodeDistanceParseXML(def, ctxt, cur_cell) < 0)
+            goto cleanup;
+
+        /* Parse cache info */
+        if (virDomainNumaDefNodeCacheParseXML(def, ctxt, cur_cell) < 0)
+            goto cleanup;
+    }
+
+    VIR_FREE(nodes);
+    if ((n = virXPathNodeSet("./cpu/numa[1]/interconnects[1]/latency|"
+                             "./cpu/numa[1]/interconnects[1]/bandwidth", ctxt, &nodes)) < 0)
+        goto cleanup;
+
+    def->interconnects = g_new0(virDomainNumaInterconnect, n);
+    for (i = 0; i < n; i++) {
+        virDomainNumaInterconnectType type;
+        unsigned int initiator;
+        unsigned int target;
+        unsigned int cache = 0;
+        int accessType;
+        unsigned long long value;
+
+        if (virXMLNodeNameEqual(nodes[i], "latency")) {
+            type = VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_LATENCY;
+
+            if (!(tmp = virXMLPropString(nodes[i], "value"))) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("Missing 'value' attribute in NUMA interconnects"));
                 goto cleanup;
+            }
+
+            if (virStrToLong_ullp(tmp, NULL, 10, &value) < 0) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("Invalid 'value' attribute in NUMA interconnects"));
+                goto cleanup;
+            }
+            VIR_FREE(tmp);
+        } else if (virXMLNodeNameEqual(nodes[i], "bandwidth")) {
+            VIR_XPATH_NODE_AUTORESTORE(ctxt);
+            type = VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH;
+
+            ctxt->node = nodes[i];
+
+            if (virDomainParseMemory("./@value", "./@unit", ctxt, &value, true, false) < 0)
+                goto cleanup;
+        } else {
+            /* Ignore yet unknown child elements. */
+            continue;
+        }
+
+        if (!(tmp = virXMLPropString(nodes[i], "initiator"))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Missing 'initiator' attribute in NUMA interconnects"));
+            goto cleanup;
+        }
+
+        if (virStrToLong_uip(tmp, NULL, 10, &initiator) < 0) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Invalid 'initiator' attribute in NUMA interconnects"));
+            goto cleanup;
+        }
+        VIR_FREE(tmp);
+
+        if (!(tmp = virXMLPropString(nodes[i], "target"))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Missing 'target' attribute in NUMA interconnects"));
+            goto cleanup;
+        }
+
+        if (virStrToLong_uip(tmp, NULL, 10, &target) < 0) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Invalid 'target' attribute in NUMA interconnects"));
+            goto cleanup;
+        }
+        VIR_FREE(tmp);
+
+
+        /* cache attribute is optional */
+        if ((tmp = virXMLPropString(nodes[i], "cache"))) {
+            if (virStrToLong_uip(tmp, NULL, 10, &cache) < 0 ||
+                cache == 0) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("Invalid 'cache' attribute in NUMA interconnects"));
+                goto cleanup;
+            }
+        }
+        VIR_FREE(tmp);
+
+        if (!(tmp = virXMLPropString(nodes[i], "type"))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Missing 'type' attribute in NUMA interconnects"));
+            goto cleanup;
+        }
+
+        if ((accessType = virDomainMemoryLatencyTypeFromString(tmp)) <= 0) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Invalid 'type' attribute in NUMA interconnects"));
+            goto cleanup;
+        }
+        VIR_FREE(tmp);
+
+        def->interconnects[i] = (virDomainNumaInterconnect) {type, initiator, target,
+                                                             cache, accessType, value};
+        def->ninterconnects++;
     }
 
     ret = 0;
@@ -982,6 +1228,7 @@ virDomainNumaDefFormatXML(virBufferPtr buf,
     for (i = 0; i < ncells; i++) {
         virBitmapPtr cpumask = virDomainNumaGetNodeCpumask(def, i);
         int ndistances;
+        size_t ncaches;
 
         memAccess = virDomainNumaGetNodeMemoryAccessMode(def, i);
         discard = virDomainNumaGetNodeDiscard(def, i);
@@ -1008,30 +1255,107 @@ virDomainNumaDefFormatXML(virBufferPtr buf,
                               virTristateBoolTypeToString(discard));
 
         ndistances = def->mem_nodes[i].ndistances;
-        if (ndistances == 0) {
+        ncaches = def->mem_nodes[i].ncaches;
+        if (ndistances == 0 && ncaches == 0) {
             virBufferAddLit(buf, "/>\n");
         } else {
             size_t j;
-            virDomainNumaDistancePtr distances = def->mem_nodes[i].distances;
 
             virBufferAddLit(buf, ">\n");
             virBufferAdjustIndent(buf, 2);
-            virBufferAddLit(buf, "<distances>\n");
-            virBufferAdjustIndent(buf, 2);
-            for (j = 0; j < ndistances; j++) {
-                if (distances[j].value) {
-                    virBufferAddLit(buf, "<sibling");
-                    virBufferAsprintf(buf, " id='%d'", distances[j].cellid);
-                    virBufferAsprintf(buf, " value='%d'", distances[j].value);
-                    virBufferAddLit(buf, "/>\n");
+
+            if (ndistances) {
+                virDomainNumaDistancePtr distances = def->mem_nodes[i].distances;
+
+                virBufferAddLit(buf, "<distances>\n");
+                virBufferAdjustIndent(buf, 2);
+                for (j = 0; j < ndistances; j++) {
+                    if (distances[j].value) {
+                        virBufferAddLit(buf, "<sibling");
+                        virBufferAsprintf(buf, " id='%d'", distances[j].cellid);
+                        virBufferAsprintf(buf, " value='%d'", distances[j].value);
+                        virBufferAddLit(buf, "/>\n");
+                    }
                 }
+                virBufferAdjustIndent(buf, -2);
+                virBufferAddLit(buf, "</distances>\n");
+            }
+
+            for (j = 0; j < ncaches; j++) {
+                virDomainNumaCachePtr cache = &def->mem_nodes[i].caches[j];
+
+                virBufferAsprintf(buf, "<cache level='%u'", cache->level);
+                if (cache->associativity) {
+                    virBufferAsprintf(buf, " associativity='%s'",
+                                      virDomainCacheAssociativityTypeToString(cache->associativity));
+                }
+
+                if (cache->policy) {
+                    virBufferAsprintf(buf, " policy='%s'",
+                                      virDomainCachePolicyTypeToString(cache->policy));
+                }
+                virBufferAddLit(buf, ">\n");
+
+                virBufferAdjustIndent(buf, 2);
+                virBufferAsprintf(buf,
+                                  "<size value='%u' unit='KiB'/>\n",
+                                  cache->size);
+
+                if (cache->line) {
+                    virBufferAsprintf(buf,
+                                      "<line value='%u' unit='B'/>\n",
+                                      cache->line);
+                }
+
+                virBufferAdjustIndent(buf, -2);
+                virBufferAddLit(buf, "</cache>\n");
             }
-            virBufferAdjustIndent(buf, -2);
-            virBufferAddLit(buf, "</distances>\n");
             virBufferAdjustIndent(buf, -2);
             virBufferAddLit(buf, "</cell>\n");
         }
     }
+
+    if (def->ninterconnects) {
+        virBufferAddLit(buf, "<interconnects>\n");
+        virBufferAdjustIndent(buf, 2);
+    }
+
+    for (i = 0; i < def->ninterconnects; i++) {
+        virDomainNumaInterconnectPtr l = &def->interconnects[i];
+
+        switch (l->type) {
+        case VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_LATENCY:
+            virBufferAddLit(buf, "<latency");
+            break;
+        case VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH:
+            virBufferAddLit(buf, "<bandwidth");
+        }
+
+        virBufferAsprintf(buf,
+                          " initiator='%u' target='%u'",
+                          l->initiator, l->target);
+
+        if (l->cache > 0) {
+            virBufferAsprintf(buf,
+                              " cache='%u'",
+                              l->cache);
+        }
+
+        virBufferAsprintf(buf,
+                          " type='%s' value='%lu'",
+                          virDomainMemoryLatencyTypeToString(l->accessType),
+                          l->value);
+
+        if (l->type == VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH)
+            virBufferAddLit(buf, " unit='KiB'");
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    if (def->ninterconnects) {
+        virBufferAdjustIndent(buf, -2);
+        virBufferAddLit(buf, "</interconnects>\n");
+    }
+
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</numa>\n");
 
index 25e896826b18b5d0d54a9fbbe49cadf1cdc1f84e..7c12d73c5b84a493cdd902ee654ca1ed288cca0f 100644 (file)
@@ -51,6 +51,39 @@ typedef enum {
 } virDomainMemoryAccess;
 VIR_ENUM_DECL(virDomainMemoryAccess);
 
+typedef enum {
+    VIR_DOMAIN_CACHE_ASSOCIATIVITY_NONE,    /* No associativity */
+    VIR_DOMAIN_CACHE_ASSOCIATIVITY_DIRECT,  /* Direct mapped cache */
+    VIR_DOMAIN_CACHE_ASSOCIATIVITY_FULL,    /* Fully associative cache */
+
+    VIR_DOMAIN_CACHE_ASSOCIATIVITY_LAST
+} virDomainCacheAssociativity;
+VIR_ENUM_DECL(virDomainCacheAssociativity);
+
+typedef enum {
+    VIR_DOMAIN_CACHE_POLICY_NONE,           /* No policy */
+    VIR_DOMAIN_CACHE_POLICY_WRITEBACK,      /* Write-back policy */
+    VIR_DOMAIN_CACHE_POLICY_WRITETHROUGH,   /* Write-through policy */
+
+    VIR_DOMAIN_CACHE_POLICY_LAST
+} virDomainCachePolicy;
+VIR_ENUM_DECL(virDomainCachePolicy);
+
+typedef enum {
+    VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_LATENCY,
+    VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH,
+} virDomainNumaInterconnectType;
+
+typedef enum {
+    VIR_DOMAIN_MEMORY_LATENCY_NONE = 0, /* No memory latency defined */
+    VIR_DOMAIN_MEMORY_LATENCY_ACCESS,   /* Access latency */
+    VIR_DOMAIN_MEMORY_LATENCY_READ,     /* Read latency */
+    VIR_DOMAIN_MEMORY_LATENCY_WRITE,    /* Write latency */
+
+    VIR_DOMAIN_MEMORY_LATENCY_LAST
+} virDomainMemoryLatency;
+VIR_ENUM_DECL(virDomainMemoryLatency);
+
 
 virDomainNumaPtr virDomainNumaNew(void);
 void virDomainNumaFree(virDomainNumaPtr numa);
index f21b33a39db375fd5020dfbe30ef25f667028164..7a64b92f3544d541b2693ee304e407830f2000a3 100644 (file)
@@ -830,8 +830,14 @@ virNodeDeviceDeleteVport;
 virNodeDeviceGetParentName;
 
 # conf/numa_conf.h
+virDomainCacheAssociativityTypeFromString;
+virDomainCacheAssociativityTypeToString;
+virDomainCachePolicyTypeFromString;
+virDomainCachePolicyTypeToString;
 virDomainMemoryAccessTypeFromString;
 virDomainMemoryAccessTypeToString;
+virDomainMemoryLatencyTypeFromString;
+virDomainMemoryLatencyTypeToString;
 virDomainNumaCheckABIStability;
 virDomainNumaEquals;
 virDomainNumaFillCPUsInNode;
diff --git a/tests/qemuxml2argvdata/numatune-hmat.xml b/tests/qemuxml2argvdata/numatune-hmat.xml
new file mode 100644 (file)
index 0000000..83f0b56
--- /dev/null
@@ -0,0 +1,52 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>c7a5fdb2-cdaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>8388608</memory>
+  <currentMemory unit='KiB'>8388608</currentMemory>
+  <vcpu placement='static'>12</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0-3' memory='2097152' unit='KiB'>
+        <cache level='1' associativity='direct' policy='writeback'>
+          <size value='10' unit='KiB'/>
+          <line value='8' unit='B'/>
+        </cache>
+      </cell>
+      <cell id='1' cpus='4-7' memory='2097152' unit='KiB'/>
+      <cell id='2' cpus='8-11' memory='2097152' unit='KiB'/>
+      <cell id='3' memory='2097152' unit='KiB'/>
+      <cell id='4' memory='2097152' unit='KiB'/>
+      <cell id='5' memory='2097152' unit='KiB'/>
+      <interconnects>
+        <latency initiator='0' target='0' type='access' value='5'/>
+        <latency initiator='0' target='0' cache='1' type='access' value='10'/>
+        <bandwidth initiator='0' target='0' type='access' value='204800' unit='KiB'/>
+      </interconnects>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/numatune-hmat.xml b/tests/qemuxml2xmloutdata/numatune-hmat.xml
new file mode 120000 (symlink)
index 0000000..6903a80
--- /dev/null
@@ -0,0 +1 @@
+../qemuxml2argvdata/numatune-hmat.xml
\ No newline at end of file
index 6a604e2a058e6f9e7b14d66614cb1c95382839d9..735e3eded702abaed48d64c22322e18314f6f268 100644 (file)
@@ -1127,6 +1127,7 @@ mymain(void)
     DO_TEST("numatune-memnode-no-memory", QEMU_CAPS_OBJECT_MEMORY_FILE);
     DO_TEST("numatune-distances", QEMU_CAPS_NUMA, QEMU_CAPS_NUMA_DIST);
     DO_TEST("numatune-no-vcpu", QEMU_CAPS_NUMA);
+    DO_TEST("numatune-hmat", NONE);
 
     DO_TEST("bios-nvram", NONE);
     DO_TEST("bios-nvram-os-interleave", NONE);