提交 7387e3fe 编写于 作者: M Martin Kletzander

conf: Add support for cputune/cachetune

More info in the documentation, this is basically the XML parsing/formatting
support, schemas, tests and documentation for the new cputune/cachetune element
that will get used by following patches.
Signed-off-by: NMartin Kletzander <mkletzan@redhat.com>
上级 a64c761c
......@@ -702,6 +702,10 @@
&lt;iothread_quota&gt;-1&lt;/iothread_quota&gt;
&lt;vcpusched vcpus='0-4,^3' scheduler='fifo' priority='1'/&gt;
&lt;iothreadsched iothreads='2' scheduler='batch'/&gt;
&lt;cachetune vcpus='0-3'&gt;
&lt;cache id='0' level='3' type='both' size='3' unit='MiB'/&gt;
&lt;cache id='1' level='3' type='both' size='3' unit='MiB'/&gt;
&lt;/cachetune&gt;
&lt;/cputune&gt;
...
&lt;/domain&gt;
......@@ -847,6 +851,56 @@
<span class="since">Since 1.2.13</span>
</dd>
<dt><code>cachetune</code><span class="since">Since 4.1.0</span></dt>
<dd>
Optional <code>cachetune</code> element can control allocations for CPU
caches using the resctrl on the host. Whether or not is this supported
can be gathered from capabilities where some limitations like minimum
size and required granularity are reported as well. The required
attribute <code>vcpus</code> specifies to which vCPUs this allocation
applies. A vCPU can only be member of one <code>cachetune</code> element
allocations. Supported subelements are:
<dl>
<dt><code>cache</code></dt>
<dd>
This element controls the allocation of CPU cache and has the
following attributes:
<dl>
<dt><code>level</code></dt>
<dd>
Host cache level from which to allocate.
</dd>
<dt><code>id</code></dt>
<dd>
Host cache id from which to allocate.
</dd>
<dt><code>type</code></dt>
<dd>
Type of allocation. Can be <code>code</code> for code
(instructions), <code>data</code> for data or <code>both</code>
for both code and data (unified). Currently the allocation can
be done only with the same type as the host supports, meaning
you cannot request <code>both</code> for host with CDP
(code/data prioritization) enabled.
</dd>
<dt><code>size</code></dt>
<dd>
The size of the region to allocate. The value by default is in
bytes, but the <code>unit</code> attribute can be used to scale
the value.
</dd>
<dt><code>unit</code> (optional)</dt>
<dd>
If specified it is the unit such as KiB, MiB, GiB, or TiB
(described in the <code>memory</code> element
for <a href="#elementsMemoryAllocation">Memory Allocation</a>)
in which <code>size</code> is specified, defaults to bytes.
</dd>
</dl>
</dd>
</dl>
</dd>
</dl>
......
......@@ -900,6 +900,38 @@
<ref name="schedparam"/>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="cachetune">
<attribute name="vcpus">
<ref name='cpuset'/>
</attribute>
<oneOrMore>
<element name="cache">
<attribute name="id">
<ref name='unsignedInt'/>
</attribute>
<attribute name="level">
<ref name='unsignedInt'/>
</attribute>
<attribute name="type">
<choice>
<value>both</value>
<value>code</value>
<value>data</value>
</choice>
</attribute>
<attribute name="size">
<ref name='unsignedLong'/>
</attribute>
<optional>
<attribute name='unit'>
<ref name='unit'/>
</attribute>
</optional>
</element>
</oneOrMore>
</element>
</zeroOrMore>
</interleave>
</element>
</define>
......
......@@ -2883,6 +2883,19 @@ virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
VIR_FREE(loader);
}
static void
virDomainCachetuneDefFree(virDomainCachetuneDefPtr cachetune)
{
if (!cachetune)
return;
virObjectUnref(cachetune->alloc);
virBitmapFree(cachetune->vcpus);
VIR_FREE(cachetune);
}
void virDomainDefFree(virDomainDefPtr def)
{
size_t i;
......@@ -3055,6 +3068,10 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainShmemDefFree(def->shmems[i]);
VIR_FREE(def->shmems);
for (i = 0; i < def->ncachetunes; i++)
virDomainCachetuneDefFree(def->cachetunes[i]);
VIR_FREE(def->cachetunes);
VIR_FREE(def->keywrap);
if (def->namespaceData && def->ns.free)
......@@ -18294,6 +18311,194 @@ virDomainDefParseBootOptions(virDomainDefPtr def,
}
static int
virDomainCachetuneDefParseCache(xmlXPathContextPtr ctxt,
xmlNodePtr node,
virResctrlAllocPtr alloc)
{
xmlNodePtr oldnode = ctxt->node;
unsigned int level;
unsigned int cache;
int type;
unsigned long long size;
char *tmp = NULL;
int ret = -1;
ctxt->node = node;
tmp = virXMLPropString(node, "id");
if (!tmp) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing cachetune attribute 'id'"));
goto cleanup;
}
if (virStrToLong_uip(tmp, NULL, 10, &cache) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cachetune attribute 'id' value '%s'"),
tmp);
goto cleanup;
}
VIR_FREE(tmp);
tmp = virXMLPropString(node, "level");
if (!tmp) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing cachetune attribute 'level'"));
goto cleanup;
}
if (virStrToLong_uip(tmp, NULL, 10, &level) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cachetune attribute 'level' value '%s'"),
tmp);
goto cleanup;
}
VIR_FREE(tmp);
tmp = virXMLPropString(node, "type");
if (!tmp) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing cachetune attribute 'type'"));
goto cleanup;
}
type = virCacheTypeFromString(tmp);
if (type < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cachetune attribute 'type' value '%s'"),
tmp);
goto cleanup;
}
VIR_FREE(tmp);
if (virDomainParseScaledValue("./@size", "./@unit",
ctxt, &size, 1024,
ULLONG_MAX, true) < 0)
goto cleanup;
if (virResctrlAllocSetSize(alloc, level, type, cache, size) < 0)
goto cleanup;
ret = 0;
cleanup:
ctxt->node = oldnode;
VIR_FREE(tmp);
return ret;
}
static int
virDomainCachetuneDefParse(virDomainDefPtr def,
xmlXPathContextPtr ctxt,
xmlNodePtr node,
unsigned int flags)
{
xmlNodePtr oldnode = ctxt->node;
xmlNodePtr *nodes = NULL;
virBitmapPtr vcpus = NULL;
virResctrlAllocPtr alloc = virResctrlAllocNew();
virDomainCachetuneDefPtr tmp_cachetune = NULL;
char *tmp = NULL;
char *vcpus_str = NULL;
char *alloc_id = NULL;
ssize_t i = 0;
int n;
int ret = -1;
ctxt->node = node;
if (!alloc)
goto cleanup;
if (VIR_ALLOC(tmp_cachetune) < 0)
goto cleanup;
vcpus_str = virXMLPropString(node, "vcpus");
if (!vcpus_str) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing cachetune attribute 'vcpus'"));
goto cleanup;
}
if (virBitmapParse(vcpus_str, &vcpus, VIR_DOMAIN_CPUMASK_LEN) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cachetune attribute 'vcpus' value '%s'"),
vcpus_str);
goto cleanup;
}
/* We need to limit the bitmap to number of vCPUs. If there's nothing left,
* then we can just clean up and return 0 immediately */
virBitmapShrink(vcpus, def->maxvcpus);
if (virBitmapIsAllClear(vcpus)) {
ret = 0;
goto cleanup;
}
if ((n = virXPathNodeSet("./cache", ctxt, &nodes)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot extract cache nodes under cachetune"));
goto cleanup;
}
for (i = 0; i < n; i++) {
if (virDomainCachetuneDefParseCache(ctxt, nodes[i], alloc) < 0)
goto cleanup;
}
if (virResctrlAllocIsEmpty(alloc)) {
ret = 0;
goto cleanup;
}
for (i = 0; i < def->ncachetunes; i++) {
if (virBitmapOverlaps(def->cachetunes[i]->vcpus, vcpus)) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Overlapping vcpus in cachetunes"));
goto cleanup;
}
}
/* We need to format it back because we need to be consistent in the naming
* even when users specify some "sub-optimal" string there. */
VIR_FREE(vcpus_str);
vcpus_str = virBitmapFormat(vcpus);
if (!vcpus_str)
goto cleanup;
if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
alloc_id = virXMLPropString(node, "id");
if (!alloc_id) {
/* The number of allocations is limited and the directory structure is flat,
* not hierarchical, so we need to have all same allocations in one
* directory, so it's nice to have it named appropriately. For now it's
* 'vcpus_...' but it's designed in order for it to be changeable in the
* future (it's part of the status XML). */
if (virAsprintf(&alloc_id, "vcpus_%s", vcpus_str) < 0)
goto cleanup;
}
if (virResctrlAllocSetID(alloc, alloc_id) < 0)
goto cleanup;
VIR_STEAL_PTR(tmp_cachetune->vcpus, vcpus);
VIR_STEAL_PTR(tmp_cachetune->alloc, alloc);
if (VIR_APPEND_ELEMENT(def->cachetunes, def->ncachetunes, tmp_cachetune) < 0)
goto cleanup;
ret = 0;
cleanup:
ctxt->node = oldnode;
virDomainCachetuneDefFree(tmp_cachetune);
virObjectUnref(alloc);
virBitmapFree(vcpus);
VIR_FREE(alloc_id);
VIR_FREE(vcpus_str);
VIR_FREE(nodes);
VIR_FREE(tmp);
return ret;
}
static virDomainDefPtr
virDomainDefParseXML(xmlDocPtr xml,
xmlNodePtr root,
......@@ -18846,6 +19051,18 @@ virDomainDefParseXML(xmlDocPtr xml,
}
VIR_FREE(nodes);
if ((n = virXPathNodeSet("./cputune/cachetune", ctxt, &nodes)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot extract cachetune nodes"));
goto error;
}
for (i = 0; i < n; i++) {
if (virDomainCachetuneDefParse(def, ctxt, nodes[i], flags) < 0)
goto error;
}
VIR_FREE(nodes);
if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
goto error;
......@@ -25797,9 +26014,80 @@ virDomainSchedulerFormat(virBufferPtr buf,
}
static int
virDomainCachetuneDefFormatHelper(unsigned int level,
virCacheType type,
unsigned int cache,
unsigned long long size,
void *opaque)
{
const char *unit;
virBufferPtr buf = opaque;
unsigned long long short_size = virFormatIntPretty(size, &unit);
virBufferAsprintf(buf,
"<cache id='%u' level='%u' type='%s' "
"size='%llu' unit='%s'/>\n",
cache, level, virCacheTypeToString(type),
short_size, unit);
return 0;
}
static int
virDomainCachetuneDefFormat(virBufferPtr buf,
virDomainCachetuneDefPtr cachetune,
unsigned int flags)
{
virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
char *vcpus = NULL;
int ret = -1;
virBufferSetChildIndent(&childrenBuf, buf);
virResctrlAllocForeachSize(cachetune->alloc,
virDomainCachetuneDefFormatHelper,
&childrenBuf);
if (virBufferCheckError(&childrenBuf) < 0)
goto cleanup;
if (!virBufferUse(&childrenBuf)) {
ret = 0;
goto cleanup;
}
vcpus = virBitmapFormat(cachetune->vcpus);
if (!vcpus)
goto cleanup;
virBufferAsprintf(buf, "<cachetune vcpus='%s'", vcpus);
if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
const char *alloc_id = virResctrlAllocGetID(cachetune->alloc);
if (!alloc_id)
goto cleanup;
virBufferAsprintf(buf, " id='%s'", alloc_id);
}
virBufferAddLit(buf, ">\n");
virBufferAddBuffer(buf, &childrenBuf);
virBufferAddLit(buf, "</cachetune>\n");
ret = 0;
cleanup:
virBufferFreeAndReset(&childrenBuf);
VIR_FREE(vcpus);
return ret;
}
static int
virDomainCputuneDefFormat(virBufferPtr buf,
virDomainDefPtr def)
virDomainDefPtr def,
unsigned int flags)
{
size_t i;
virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
......@@ -25898,6 +26186,9 @@ virDomainCputuneDefFormat(virBufferPtr buf,
def->iothreadids[i]->iothread_id);
}
for (i = 0; i < def->ncachetunes; i++)
virDomainCachetuneDefFormat(&childrenBuf, def->cachetunes[i], flags);
if (virBufferCheckError(&childrenBuf) < 0)
return -1;
......@@ -26235,7 +26526,7 @@ virDomainDefFormatInternal(virDomainDefPtr def,
}
}
if (virDomainCputuneDefFormat(buf, def) < 0)
if (virDomainCputuneDefFormat(buf, def, flags) < 0)
goto error;
if (virDomainNumatuneFormatXML(buf, def->numa) < 0)
......
......@@ -56,6 +56,7 @@
# include "virperf.h"
# include "virtypedparam.h"
# include "virsavecookie.h"
# include "virresctrl.h"
/* forward declarations of all device types, required by
* virDomainDeviceDef
......@@ -2194,6 +2195,15 @@ struct _virDomainCputune {
};
typedef struct _virDomainCachetuneDef virDomainCachetuneDef;
typedef virDomainCachetuneDef *virDomainCachetuneDefPtr;
struct _virDomainCachetuneDef {
virBitmapPtr vcpus;
virResctrlAllocPtr alloc;
};
typedef struct _virDomainVcpuDef virDomainVcpuDef;
typedef virDomainVcpuDef *virDomainVcpuDefPtr;
......@@ -2322,6 +2332,9 @@ struct _virDomainDef {
virDomainCputune cputune;
virDomainCachetuneDefPtr *cachetunes;
size_t ncachetunes;
virDomainNumaPtr numa;
virDomainResourceDefPtr resource;
virDomainIdMapDef idmap;
......
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>4</vcpu>
<cputune>
<cachetune vcpus='0-1'>
<cache id='0' level='3' type='code' size='7680' unit='KiB'/>
<cache id='1' level='3' type='data' size='3840' unit='KiB'/>
</cachetune>
<cachetune vcpus='2'>
<cache id='1' level='3' type='code' size='6' unit='MiB'/>
</cachetune>
<cachetune vcpus='3'>
<cache id='1' level='3' type='data' size='6912' unit='KiB'/>
</cachetune>
</cputune>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'/>
</devices>
</domain>
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>4</vcpu>
<cputune>
<cachetune vcpus='0'>
<cache id='0' level='3' type='code' size='12' unit='KiB'/>
<cache id='0' level='3' type='code' size='18' unit='KiB'/>
</cachetune>
</cputune>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'/>
</devices>
</domain>
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>4</vcpu>
<cputune>
<cachetune vcpus='0'>
<cache id='0' level='3' type='code' size='12' unit='KiB'/>
</cachetune>
<cachetune vcpus='0'>
<cache id='0' level='3' type='data' size='18' unit='KiB'/>
</cachetune>
</cputune>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'/>
</devices>
</domain>
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>4</vcpu>
<cputune>
<cachetune vcpus='0-1'>
<cache id='0' level='3' type='both' size='12' unit='KiB'/>
<cache id='0' level='3' type='code' size='6' unit='KiB'/>
</cachetune>
</cputune>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'/>
</devices>
</domain>
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>4</vcpu>
<cputune>
<cachetune vcpus='0-1'>
<cache id='0' level='3' type='both' size='768' unit='KiB'/>
</cachetune>
</cputune>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'/>
</devices>
</domain>
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>4</vcpu>
<cputune>
<cachetune vcpus='0-1'>
<cache id='0' level='3' type='both' size='3' unit='MiB'/>
<cache id='1' level='3' type='both' size='3' unit='MiB'/>
</cachetune>
<cachetune vcpus='3'>
<cache id='0' level='3' type='both' size='3' unit='MiB'/>
</cachetune>
</cputune>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<memballoon model='virtio'/>
</devices>
</domain>
......@@ -130,6 +130,16 @@ mymain(void)
DO_TEST_FULL("chardev-reconnect-invalid-mode", 0, false,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
DO_TEST("cachetune");
DO_TEST("cachetune-small");
DO_TEST("cachetune-cdp");
DO_TEST_FULL("cachetune-colliding-allocs", false, true,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
DO_TEST_FULL("cachetune-colliding-tunes", false, true,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
DO_TEST_FULL("cachetune-colliding-types", false, true,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
virObjectUnref(caps);
virObjectUnref(xmlopt);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册