</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>
+ ...
+ <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>
#include "util.h"
#include "buf.h"
#include "cpu_conf.h"
+#include "domain_conf.h"
#define VIR_FROM_THIS VIR_FROM_CPU
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);
}
return NULL;
}
-
virCPUDefPtr
virCPUDefParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt,
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:
}
}
+ 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;
}
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 {
size_t nfeatures;
size_t nfeatures_max;
virCPUFeatureDefPtr features;
+ size_t ncells;
+ size_t ncells_max;
+ virCellDefPtr cells;
+ unsigned int cells_cpus;
};