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@xxxxxxxxxxxxxxxxxx> > > 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@xxxxxxxxxxxxxxxxxx> > --- > > 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 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list