XML definitions for guest NUMA and parsing routines

This patch adds XML definitions for guest NUMA specification and contains
routines to parse the same. The guest NUMA specification looks like this:

<cpu>
        ...
        <topology sockets='2' cores='4' threads='2'/>
        <numa>
                <cell cpus='0-7' memory='512000'/>
                <cell cpus='8-15' memory='512000'/>
        </numa>
        ...
</cpu>

Signed-off-by: Bharata B Rao <bharata@linux.vnet.ibm.com>
This commit is contained in:
Bharata B Rao 2011-11-11 18:21:45 +05:30 committed by Eric Blake
parent c74b97156f
commit 5f7b71b413
6 changed files with 166 additions and 3 deletions

View File

@ -205,6 +205,7 @@ Patches have also been contributed by:
Patrice LACHANCE <patlachance@gmail.com>
Eli Qiao <taget@linux.vnet.ibm.com>
Michael Wood <esiotrot@gmail.com>
Bharata B Rao <bharata@linux.vnet.ibm.com>
[....send patches to get your name here....]

View File

@ -628,6 +628,35 @@
</dd>
</dl>
<p>
Guest NUMA topology can be specifed using the <code>numa</code> element.
<span class="since">Since 0.9.8</span>
</p>
<pre>
...
&lt;cpu&gt;
...
&lt;numa&gt;
&lt;cell cpus='0-3' memory='512000'/&gt;
&lt;cell cpus='4-7' memory='512000'/&gt;
&lt;/numa&gt;
...
&lt;/cpu&gt;
...</pre>
<p>
Each <code>cell</code> element specifies a NUMA cell or a NUMA node.
<code>cpus</code> specifies the CPU or range of CPUs that are part of
the node. <code>memory</code> specifies the node memory in kilobytes
(i.e. blocks of 1024 bytes). Each cell or node is assigned cellid
or nodeid in the increasing order starting from 0.
</p>
<p>
This guest NUMA specification is currently available only for QEMU/KVM.
</p>
<h3><a name="elementsLifecycle">Lifecycle control</a></h3>
<p>

View File

@ -2297,7 +2297,16 @@
<define name="cpu">
<element name="cpu">
<choice>
<ref name="cpuTopology"/>
<group>
<interleave>
<optional>
<ref name="cpuTopology"/>
</optional>
<optional>
<ref name="cpuNuma"/>
</optional>
</interleave>
</group>
<group>
<ref name="cpuMatch"/>
<interleave>
@ -2311,6 +2320,9 @@
<zeroOrMore>
<ref name="cpuFeature"/>
</zeroOrMore>
<optional>
<ref name="cpuNuma"/>
</optional>
</interleave>
</group>
</choice>
@ -2371,6 +2383,25 @@
</element>
</define>
<define name="cpuNuma">
<element name="numa">
<oneOrMore>
<ref name="numaCell"/>
</oneOrMore>
</element>
</define>
<define name="numaCell">
<element name="cell">
<attribute name="cpus">
<ref name="cpuset"/>
</attribute>
<attribute name="memory">
<ref name="memoryKB"/>
</attribute>
</element>
</define>
<!--
System information specification:
Placeholder for system specific informations likes the ones

View File

@ -28,6 +28,7 @@
#include "util.h"
#include "buf.h"
#include "cpu_conf.h"
#include "domain_conf.h"
#define VIR_FROM_THIS VIR_FROM_CPU
@ -67,6 +68,12 @@ virCPUDefFree(virCPUDefPtr def)
VIR_FREE(def->features[i].name);
VIR_FREE(def->features);
for (i = 0 ; i < def->ncells ; i++) {
VIR_FREE(def->cells[i].cpumask);
VIR_FREE(def->cells[i].cpustr);
}
VIR_FREE(def->cells);
VIR_FREE(def);
}
@ -109,7 +116,6 @@ no_memory:
return NULL;
}
virCPUDefPtr
virCPUDefParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt,
@ -289,9 +295,75 @@ virCPUDefParseXML(const xmlNodePtr node,
def->features[i].policy = policy;
}
if (virXPathNode("./numa[1]", ctxt)) {
VIR_FREE(nodes);
n = virXPathNodeSet("./numa[1]/cell", ctxt, &nodes);
if (n <= 0) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("NUMA topology defined without NUMA cells"));
goto error;
}
if (VIR_RESIZE_N(def->cells, def->ncells_max,
def->ncells, n) < 0)
goto no_memory;
def->ncells = n;
for (i = 0 ; i < n ; i++) {
char *cpus, *cpus_parse, *memory;
int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
int ret, ncpus = 0;
def->cells[i].cellid = i;
cpus = cpus_parse = virXMLPropString(nodes[i], "cpus");
if (!cpus) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Missing 'cpus' attribute in NUMA cell"));
goto error;
}
def->cells[i].cpustr = strdup(cpus);
if (!def->cells[i].cpustr) {
VIR_FREE(cpus);
goto no_memory;
}
if (VIR_ALLOC_N(def->cells[i].cpumask, cpumasklen) < 0) {
VIR_FREE(cpus);
goto no_memory;
}
ncpus = virDomainCpuSetParse((const char **)&cpus_parse,
0, def->cells[i].cpumask, cpumasklen);
if (ncpus <= 0) {
VIR_FREE(cpus);
goto error;
}
def->cells_cpus += ncpus;
memory = virXMLPropString(nodes[i], "memory");
if (!memory) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Missing 'memory' attribute in NUMA cell"));
VIR_FREE(cpus);
goto error;
}
ret = virStrToLong_ui(memory, NULL, 10, &def->cells[i].mem);
if (ret == -1) {
VIR_FREE(cpus);
VIR_FREE(memory);
goto error;
}
VIR_FREE(cpus);
VIR_FREE(memory);
}
}
cleanup:
VIR_FREE(nodes);
return def;
no_memory:
@ -414,6 +486,16 @@ virCPUDefFormatBuf(virBufferPtr buf,
}
}
if (def->ncells) {
virBufferAddLit(buf, "<numa>\n");
for (i = 0; i < def->ncells; i++) {
virBufferAddLit(buf, " <cell");
virBufferAsprintf(buf, " cpus='%s'", def->cells[i].cpustr);
virBufferAsprintf(buf, " memory='%d'", def->cells[i].mem);
virBufferAddLit(buf, "/>\n");
}
virBufferAddLit(buf, "</numa>\n");
}
return 0;
}

View File

@ -67,6 +67,15 @@ struct _virCPUFeatureDef {
int policy; /* enum virCPUFeaturePolicy */
};
typedef struct _virCellDef virCellDef;
typedef virCellDef *virCellDefPtr;
struct _virCellDef {
int cellid;
char *cpumask; /* CPUs that are part of this node */
char *cpustr; /* CPUs stored in string form for dumpxml */
unsigned int mem; /* Node memory in kB */
};
typedef struct _virCPUDef virCPUDef;
typedef virCPUDef *virCPUDefPtr;
struct _virCPUDef {
@ -81,6 +90,10 @@ struct _virCPUDef {
size_t nfeatures;
size_t nfeatures_max;
virCPUFeatureDefPtr features;
size_t ncells;
size_t ncells_max;
virCellDefPtr cells;
unsigned int cells_cpus;
};

View File

@ -7572,6 +7572,13 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
if (def->cpu == NULL)
goto error;
if (def->cpu->cells_cpus > def->maxvcpus) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Number of CPUs in <numa> exceeds the"
" <vcpu> count"));
goto error;
}
}
if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {