[libvirt] [PATCH v2 1/2] XML definitions for guest NUMA and parsing routines
Daniel P. Berrange
berrange at redhat.com
Tue Nov 15 11:48:53 UTC 2011
On Fri, Nov 11, 2011 at 06:21:45PM +0530, Bharata B Rao wrote:
> XML definitions for guest NUMA and parsing routines.
>
> From: Bharata B Rao <bharata at linux.vnet.ibm.com>
>
> 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 at linux.vnet.ibm.com>
> ---
>
> docs/formatdomain.html.in | 29 ++++++++++++++
> docs/schemas/domaincommon.rng | 31 ++++++++++++++-
> src/conf/cpu_conf.c | 86 ++++++++++++++++++++++++++++++++++++++++-
> src/conf/cpu_conf.h | 13 ++++++
> src/conf/domain_conf.c | 7 +++
> 5 files changed, 163 insertions(+), 3 deletions(-)
>
>
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index cbad196..28a4edc 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -628,6 +628,35 @@
> </dd>
> </dl>
>
> + <p>
> + Guest NUMA topology can be specifed using <code>numa</code> element.
> + <span class="since">Since 0.9.8</span>
> + </p>
> +
> +<pre>
> + ...
> + <cpu>
> + ...
> + <numa>
> + <cell cpus='0-3' memory='512000'/>
> + <cell cpus='4-7' memory='512000'/>
> + </numa>
> + ...
> + </cpu>
> + ...</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>
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index b6f858e..afcaccc 100644
> --- a/docs/schemas/domaincommon.rng
> +++ b/docs/schemas/domaincommon.rng
> @@ -2297,7 +2297,14 @@
> <define name="cpu">
> <element name="cpu">
> <choice>
> - <ref name="cpuTopology"/>
> + <group>
> + <optional>
> + <ref name="cpuTopology"/>
> + </optional>
> + <optional>
> + <ref name="cpuNuma"/>
> + </optional>
> + </group>
> <group>
> <ref name="cpuMatch"/>
> <interleave>
> @@ -2311,6 +2318,9 @@
> <zeroOrMore>
> <ref name="cpuFeature"/>
> </zeroOrMore>
> + <optional>
> + <ref name="cpuNuma"/>
> + </optional>
> </interleave>
> </group>
> </choice>
> @@ -2371,6 +2381,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
> diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
> index 41e997e..4aabe98 100644
> --- a/src/conf/cpu_conf.c
> +++ b/src/conf/cpu_conf.c
> @@ -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;
> }
>
> diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
> index 4406cba..efff473 100644
> --- a/src/conf/cpu_conf.h
> +++ b/src/conf/cpu_conf.h
> @@ -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;
> };
>
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index a85f837..1203119 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -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) {
ACK
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list