AC_SUBST([NUMACTL_CFLAGS])
AC_SUBST([NUMACTL_LIBS])
+dnl Do we have numad?
+if test "$with_qemu" = "yes"; then
+ AC_PATH_PROG([NUMAD], [numad], [], [/bin:/usr/bin:/usr/local/bin:$PATH])
+
+ if test -n "$NUMAD"; then
+ AC_DEFINE_UNQUOTED([NUMAD],["$NUMAD"], [Location or name of the numad program])
+ fi
+fi
dnl pcap lib
LIBPCAP_CONFIG="pcap-config"
<pre>
<domain>
...
- <vcpu cpuset="1-4,^3,6" current="1">2</vcpu>
+ <vcpu placement='static' cpuset="1-4,^3,6" current="1">2</vcpu>
...
</domain>
</pre>
be excluded from a previous range. <span class="since">Since
0.8.5</span>, the optional attribute <code>current</code> can
be used to specify whether fewer than the maximum number of
- virtual CPUs should be enabled.
+ virtual CPUs should be enabled. <span class="since">Since
+ 0.9.11 (QEMU and KVM only), the optional attribute
+ <code>placement</code> can be used to indicate the CPU placement
+ mode for domain process, its value can be either "static" or
+ "auto", defaults to "static" if <code>cpuset</code> is specified,
+ "auto" indicates the domain process will be pinned to the advisory
+ nodeset from querying numad, and the value of attribute
+ <code>cpuset</code> will be overridden by the advisory nodeset
+ from numad if it's specified. If both <code>cpuset</code> and
+ <code>placement</code> are not specified, or if <code>placement</code>
+ is "static", but no <code>cpuset</code> is specified, the domain
+ process will be pinned to all the available physical CPUs.
</dd>
</dl>
<span class='since'>Since 0.9.3</span>
<dt><code>memory</code></dt>
<dd>
- The optional <code>memory</code> element specify how to allocate memory
+ The optional <code>memory</code> element specifies how to allocate memory
for the domain process on a NUMA host. It contains two attributes,
attribute <code>mode</code> is either 'interleave', 'strict',
or 'preferred',
<optional>
<element name="vcpu">
+ <optional>
+ <attribute name="placement">
+ <choice>
+ <value>static</value>
+ <value>auto</value>
+ </choice>
+ </attribute>
+ </optional>
<optional>
<attribute name="cpuset">
<ref name="cpuset"/>
"requisite",
"optional");
+VIR_ENUM_IMPL(virDomainCpuPlacementMode, VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST,
+ "default",
+ "static",
+ "auto");
+
#define virDomainReportError(code, ...) \
virReportErrorHelper(VIR_FROM_DOMAIN, code, __FILE__, \
__FUNCTION__, __LINE__, __VA_ARGS__)
goto cleanup;
}
-
static int virDomainDefMaybeAddController(virDomainDefPtr def,
int type,
int idx)
bool uuid_generated = false;
virBitmapPtr bootMap = NULL;
unsigned long bootMapSize = 0;
+ xmlNodePtr cur;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
VIR_FREE(tmp);
}
+ tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
+ if (tmp) {
+ if ((def->placement_mode =
+ virDomainCpuPlacementModeTypeFromString(tmp)) < 0) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("Unsupported CPU placement mode '%s'"),
+ tmp);
+ VIR_FREE(tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ } else {
+ if (def->cpumasklen)
+ def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
+ }
+
/* Extract cpu tunables. */
if (virXPathULong("string(./cputune/shares[1])", ctxt,
&def->cputune.shares) < 0)
VIR_FREE(nodes);
/* Extract numatune if exists. */
- if ((n = virXPathNodeSet("./numatune", ctxt, NULL)) < 0) {
+ if ((n = virXPathNodeSet("./numatune", ctxt, &nodes)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot extract numatune nodes"));
goto error;
}
+ if (n > 1) {
+ virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only one numatune is supported"));
+ VIR_FREE(nodes);
+ goto error;
+ }
+
if (n) {
- tmp = virXPathString("string(./numatune/memory/@nodeset)", ctxt);
- if (tmp) {
- char *set = tmp;
- int nodemasklen = VIR_DOMAIN_CPUMASK_LEN;
+ cur = nodes[0]->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((xmlStrEqual(cur->name, BAD_CAST "memory"))) {
+ tmp = virXMLPropString(cur, "nodeset");
- if (VIR_ALLOC_N(def->numatune.memory.nodemask, nodemasklen) < 0) {
- goto no_memory;
- }
+ if (tmp) {
+ char *set = tmp;
+ int nodemasklen = VIR_DOMAIN_CPUMASK_LEN;
- /* "nodeset" leads same syntax with "cpuset". */
- if (virDomainCpuSetParse(set, 0, def->numatune.memory.nodemask,
- nodemasklen) < 0)
- goto error;
- VIR_FREE(tmp);
- } else {
- virDomainReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("nodeset for NUMA memory tuning must be set"));
- goto error;
- }
+ if (VIR_ALLOC_N(def->numatune.memory.nodemask,
+ nodemasklen) < 0) {
+ virReportOOMError();
+ goto error;
+ }
- tmp = virXPathString("string(./numatune/memory/@mode)", ctxt);
- if (tmp) {
- if ((def->numatune.memory.mode =
- virDomainNumatuneMemModeTypeFromString(tmp)) < 0) {
- virDomainReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unsupported NUMA memory tuning mode '%s'"),
- tmp);
- goto error;
+ /* "nodeset" leads same syntax with "cpuset". */
+ if (virDomainCpuSetParse(set, 0,
+ def->numatune.memory.nodemask,
+ nodemasklen) < 0)
+ goto error;
+ VIR_FREE(tmp);
+ } else {
+ virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+ _("nodeset for NUMA memory "
+ "tuning must be set"));
+ goto error;
+ }
+
+ tmp = virXMLPropString(cur, "mode");
+ if (tmp) {
+ if ((def->numatune.memory.mode =
+ virDomainNumatuneMemModeTypeFromString(tmp)) < 0) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("Unsupported NUMA memory "
+ "tuning mode '%s'"),
+ tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ } else {
+ def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
+ }
+ } else {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("unsupported XML element %s"),
+ (const char *)cur->name);
+ goto error;
+ }
}
- VIR_FREE(tmp);
- } else {
- def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
+ cur = cur->next;
}
}
+ VIR_FREE(nodes);
n = virXPathNodeSet("./features/*", ctxt, &nodes);
if (n < 0)
allones = 0;
virBufferAddLit(buf, " <vcpu");
+ if (def->placement_mode)
+ virBufferAsprintf(buf, " placement='%s'",
+ virDomainCpuPlacementModeTypeToString(def->placement_mode));
if (!allones) {
char *cpumask = NULL;
if ((cpumask =
virBufferAddLit(buf, " </cputune>\n");
if (def->numatune.memory.nodemask) {
+ virBufferAddLit(buf, " <numatune>\n");
const char *mode;
char *nodemask = NULL;
- virBufferAddLit(buf, " <numatune>\n");
nodemask = virDomainCpuSetFormat(def->numatune.memory.nodemask,
VIR_DOMAIN_CPUMASK_LEN);
if (nodemask == NULL) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to format nodeset for NUMA memory tuning"));
+ _("failed to format nodeset for "
+ "NUMA memory tuning"));
goto cleanup;
}
mode = virDomainNumatuneMemModeTypeToString(def->numatune.memory.mode);
virBufferAsprintf(buf, " <memory mode='%s' nodeset='%s'/>\n",
- mode, nodemask);
+ mode, nodemask);
VIR_FREE(nodemask);
+
virBufferAddLit(buf, " </numatune>\n");
}
VIR_DOMAIN_TIMER_MODE_LAST,
};
+enum virDomainCpuPlacementMode {
+ VIR_DOMAIN_CPU_PLACEMENT_MODE_DEFAULT = 0,
+ VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
+ VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO,
+
+ VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST,
+};
+
typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef;
typedef virDomainTimerCatchupDef *virDomainTimerCatchupDefPtr;
struct _virDomainTimerCatchupDef {
} mem;
unsigned short vcpus;
unsigned short maxvcpus;
+ int placement_mode;
int cpumasklen;
char *cpumask;
VIR_ENUM_DECL(virDomainTimerTrack)
VIR_ENUM_DECL(virDomainTimerTickpolicy)
VIR_ENUM_DECL(virDomainTimerMode)
+VIR_ENUM_DECL(virDomainCpuPlacementMode)
VIR_ENUM_DECL(virDomainStartupPolicy)
virDomainControllerModelUSBTypeFromString;
virDomainControllerModelUSBTypeToString;
virDomainControllerTypeToString;
+virDomainCpuPlacementTypeFromString;
+virDomainCpuPlacementTypeToString;
virDomainCpuSetFormat;
virDomainCpuSetParse;
virDomainDefAddImplicitControllers;
}
#endif
+#if defined(NUMAD)
+static char *
+qemuGetNumadAdvice(virDomainDefPtr def)
+{
+ virCommandPtr cmd = NULL;
+ char *args = NULL;
+ char *output = NULL;
+
+ if (virAsprintf(&args, "%d:%lu", def->vcpus, def->mem.cur_balloon) < 0) {
+ virReportOOMError();
+ goto out;
+ }
+ cmd = virCommandNewArgList(NUMAD, "-w", args, NULL);
+
+ virCommandSetOutputBuffer(cmd, &output);
+
+ if (virCommandRun(cmd, NULL) < 0)
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to query numad for the advisory nodeset"));
+
+out:
+ VIR_FREE(args);
+ virCommandFree(cmd);
+ return output;
+}
+#else
+static char *
+qemuGetNumadAdvice(virDomainDefPtr def ATTRIBUTE_UNUSED)
+{
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("numad is not available on this host"));
+ return NULL;
+}
+#endif
+
/*
* To be run between fork/exec of QEMU only
*/
static int
-qemuProcessInitCpuAffinity(virDomainObjPtr vm)
+qemuProcessInitCpuAffinity(struct qemud_driver *driver,
+ virDomainObjPtr vm)
{
int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
virNodeInfo nodeinfo;
return -1;
}
- if (vm->def->cpumask) {
- /* XXX why don't we keep 'cpumask' in the libvirt cpumap
- * format to start with ?!?! */
- for (i = 0 ; i < maxcpu && i < vm->def->cpumasklen ; i++)
- if (vm->def->cpumask[i])
+ if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
+ char *tmp_cpumask = NULL;
+ char *nodeset = NULL;
+
+ nodeset = qemuGetNumadAdvice(vm->def);
+ if (!nodeset)
+ return -1;
+
+ if (VIR_ALLOC_N(tmp_cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virDomainCpuSetParse(nodeset, 0, tmp_cpumask,
+ VIR_DOMAIN_CPUMASK_LEN) < 0) {
+ VIR_FREE(tmp_cpumask);
+ VIR_FREE(nodeset);
+ return -1;
+ }
+
+ for (i = 0; i < maxcpu && i < VIR_DOMAIN_CPUMASK_LEN; i++) {
+ if (tmp_cpumask[i])
VIR_USE_CPU(cpumap, i);
+ }
+
+ VIR_FREE(vm->def->cpumask);
+ vm->def->cpumask = tmp_cpumask;
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
+ VIR_WARN("Unable to save status on vm %s after state change",
+ vm->def->name);
+ }
+ VIR_FREE(nodeset);
} else {
- /* You may think this is redundant, but we can't assume libvirtd
- * itself is running on all pCPUs, so we need to explicitly set
- * the spawned QEMU instance to all pCPUs if no map is given in
- * its config file */
- for (i = 0 ; i < maxcpu ; i++)
- VIR_USE_CPU(cpumap, i);
+ if (vm->def->cpumask) {
+ /* XXX why don't we keep 'cpumask' in the libvirt cpumap
+ * format to start with ?!?! */
+ for (i = 0 ; i < maxcpu && i < vm->def->cpumasklen ; i++)
+ if (vm->def->cpumask[i])
+ VIR_USE_CPU(cpumap, i);
+ } else {
+ /* You may think this is redundant, but we can't assume libvirtd
+ * itself is running on all pCPUs, so we need to explicitly set
+ * the spawned QEMU instance to all pCPUs if no map is given in
+ * its config file */
+ for (i = 0 ; i < maxcpu ; i++)
+ VIR_USE_CPU(cpumap, i);
+ }
}
/* We are pressuming we are running between fork/exec of QEMU
/* This must be done after cgroup placement to avoid resetting CPU
* affinity */
VIR_DEBUG("Setup CPU affinity");
- if (qemuProcessInitCpuAffinity(h->vm) < 0)
+ if (qemuProcessInitCpuAffinity(h->driver, h->vm) < 0)
goto cleanup;
if (qemuProcessInitNumaMemoryPolicy(h->vm) < 0)
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</metadata>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</description>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</metadata>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
- <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>