This patch adds new xml element, and so we can have the option of
also having perf events enabled immediately at startup.
Signed-off-by: Qiaowei Ren <qiaowei.ren(a)intel.com>
---
docs/schemas/domaincommon.rng | 27 +++++++
src/conf/domain_conf.c | 111 ++++++++++++++++++++++++++
src/conf/domain_conf.h | 10 +++
src/qemu/qemu_driver.c | 26 ++++++
src/qemu/qemu_process.c | 8 +-
tests/domainschemadata/domain-perf-simple.xml | 20 +++++
6 files changed, 200 insertions(+), 2 deletions(-)
create mode 100644 tests/domainschemadata/domain-perf-simple.xml
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index da6de40..03b4ed2 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -56,6 +56,9 @@
<ref name="pm"/>
</optional>
<optional>
+ <ref name="perf"/>
+ </optional>
+ <optional>
<ref name="idmap"/>
</optional>
<optional>
@@ -393,6 +396,30 @@
</define>
<!--
+ Enable or disable perf events for the domain. For each
+ of the events the following rules apply:
+ on: the event will be forcefully enabled
+ off: the event will be forcefully disabled
+ not specified: the event will be disabled by default
+ -->
+ <define name="perf">
+ <element name="perf">
+ <oneOrMore>
+ <element name="event">
+ <attribute name="name">
+ <choice>
+ <value>cmt</value>
+ </choice>
+ </attribute>
+ <attribute name="enabled">
+ <ref name="virYesNo"/>
+ </attribute>
+ </element>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
The Identifiers can be:
- an optional id attribute with a number on the domain element
- a mandatory name
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d5d9ff7..c004ce9 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2635,6 +2635,8 @@ void virDomainDefFree(virDomainDefPtr def)
VIR_FREE(def->keywrap);
+ VIR_FREE(def->perf);
+
if (def->namespaceData && def->ns.free)
(def->ns.free)(def->namespaceData);
@@ -12561,6 +12563,91 @@ virDomainPMStateParseXML(xmlXPathContextPtr ctxt,
static int
+virDomainPerfEventDefParseXML(virDomainPerfDefPtr perf,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ char *name = NULL;
+ char *enabled = NULL;
+ int enabled_type;
+ int name_type;
+ int ret = -1;
+
+ xmlNodePtr oldnode = ctxt->node;
+
+ ctxt->node = node;
+ if (!(name = virXPathString("string(./@name)", ctxt))) {
+ virReportError(VIR_ERR_CONF_SYNTAX, "%s",
+ _("missing name for event"));
+ goto cleanup;
+ }
+
+ if ((name_type = virPerfEventTypeFromString(name)) < 0) {
+ virReportError(VIR_ERR_CONF_SYNTAX,
+ _("%s is not a supported event name"), name);
+ goto cleanup;
+ }
+
+ if (!(enabled = virXPathString("string(./@enabled)", ctxt))) {
+ virReportError(VIR_ERR_CONF_SYNTAX,
+ _("missing state for cipher named %s"), name);
+ goto cleanup;
+ }
+
+ if ((enabled_type = virTristateBoolTypeFromString(enabled)) < 0) {
+ virReportError(VIR_ERR_CONF_SYNTAX,
+ _("%s is not a supported enabled state"), enabled);
+ goto cleanup;
+ }
+
+ if (perf->events[VIR_PERF_EVENT_CMT] != VIR_TRISTATE_BOOL_ABSENT) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("A domain definition can have no more than "
+ "one event node with name %s"),
+ virTristateBoolTypeToString(name_type));
+
+ goto cleanup;
+ }
+ perf->events[VIR_PERF_EVENT_CMT] = enabled_type;
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(name);
+ VIR_FREE(enabled);
+ ctxt->node = oldnode;
+ return ret;
+}
+
+static int
+virDomainPerfDefParseXML(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt)
+{
+ size_t i;
+ int ret = -1;
+ xmlNodePtr *nodes = NULL;
+ int n;
+
+ if ((n = virXPathNodeSet("./perf/event", ctxt, &nodes)) < 0)
+ return n;
+
+ if (VIR_ALLOC(def->perf) < 0)
+ goto cleanup;
+
+ for (i = 0; i < n; i++) {
+ if (virDomainPerfEventDefParseXML(def->perf, nodes[i], ctxt) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (ret < 0)
+ VIR_FREE(def->perf);
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
virDomainMemorySourceDefParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
virDomainMemoryDefPtr def)
@@ -15769,6 +15856,9 @@ virDomainDefParseXML(xmlDocPtr xml,
&def->pm.s4) < 0)
goto error;
+ if (virDomainPerfDefParseXML(def, ctxt) < 0)
+ goto error;
+
if ((tmp = virXPathString("string(./clock/@offset)", ctxt)) &&
(def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -21653,6 +21743,24 @@ virDomainKeyWrapDefFormat(virBufferPtr buf,
virDomainKeyWrapDefPtr keywrap)
virBufferAddLit(buf, "</keywrap>\n");
}
+static void
+virDomainPerfDefFormat(virBufferPtr buf, virDomainPerfDefPtr perf)
+{
+ size_t i;
+ virBufferAddLit(buf, "<perf>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ for (i = 0; i < VIR_PERF_EVENT_LAST; i++) {
+ if (perf->events[i])
+ virBufferAsprintf(buf, "<event name='%s'
enabled='%s'/>\n",
+ virPerfEventTypeToString(i),
+ virTristateBoolTypeToString(perf->events[i]));
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</perf>\n");
+}
+
static bool
virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
{
@@ -22515,6 +22623,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virBufferAddLit(buf, "</pm>\n");
}
+ if (def->perf)
+ virDomainPerfDefFormat(buf, def->perf);
+
virBufferAddLit(buf, "<devices>\n");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 83bdd67..fd104fb 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -51,6 +51,7 @@
# include "virseclabel.h"
# include "virprocess.h"
# include "virgic.h"
+# include "virperf.h"
/* forward declarations of all device types, required by
* virDomainDeviceDef
@@ -2179,6 +2180,13 @@ struct _virDomainPowerManagement {
int s4;
};
+typedef struct _virDomainPerfDef virDomainPerfDef;
+typedef virDomainPerfDef *virDomainPerfDefPtr;
+struct _virDomainPerfDef {
+ /* These options are of type enum virTristateBool */
+ int events[VIR_PERF_EVENT_LAST];
+};
+
typedef struct _virDomainKeyWrapDef virDomainKeyWrapDef;
typedef virDomainKeyWrapDef *virDomainKeyWrapDefPtr;
struct _virDomainKeyWrapDef {
@@ -2229,6 +2237,8 @@ struct _virDomainDef {
virDomainPowerManagement pm;
+ virDomainPerfDefPtr perf;
+
virDomainOSDef os;
char *emulator;
/* These three options are of type virTristateSwitch,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 599d5ed..7e01459 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10042,9 +10042,14 @@ qemuDomainSetPerfEvents(virDomainPtr dom,
virTypedParameterPtr params,
int nparams)
{
+ virQEMUDriverPtr driver = dom->conn->privateData;
size_t i;
virDomainObjPtr vm = NULL;
+ virQEMUDriverConfigPtr cfg = NULL;
qemuDomainObjPrivatePtr priv;
+ virDomainDefPtr def;
+ virDomainDefPtr persistentDef;
+ unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
int ret = -1;
virPerfEventType type;
bool enabled;
@@ -10055,11 +10060,15 @@ qemuDomainSetPerfEvents(virDomainPtr dom,
if (!(vm = qemuDomObjFromDomain(dom)))
return -1;
+ cfg = virQEMUDriverGetConfig(driver);
priv = vm->privateData;
if (virDomainSetPerfEventsEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
+ if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
+ goto cleanup;
+
for (i = 0; i < nparams; i++) {
virTypedParameterPtr param = ¶ms[i];
enabled = params->value.b;
@@ -10069,12 +10078,29 @@ qemuDomainSetPerfEvents(virDomainPtr dom,
goto cleanup;
if (enabled && virPerfEventEnable(priv->perf, type, vm->pid))
goto cleanup;
+
+ if (def) {
+ def->perf->events[type] = enabled ?
+ VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO;
+
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm,
driver->caps) < 0)
+ goto cleanup;
+ }
+
+ if (persistentDef) {
+ persistentDef->perf->events[type] = enabled ?
+ VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO;
+
+ if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef)
< 0)
+ goto cleanup;
+ }
}
ret = 0;
cleanup:
virDomainObjEndAPI(&vm);
+ virObjectUnref(cfg);
return ret;
}
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index f7d30e9..cf7df1a 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -5254,8 +5254,12 @@ qemuProcessLaunch(virConnectPtr conn,
goto cleanup;
priv->perf = virPerfNew();
- if (!priv->perf)
- goto cleanup;
+ if (priv->perf) {
+ for (size_t i = 0; i < VIR_PERF_EVENT_LAST; i++) {
+ if (vm->def->perf->events[i] == VIR_TRISTATE_BOOL_YES)
+ virPerfEventEnable(priv->perf, i, vm->pid);
+ }
+ }
/* This must be done after cgroup placement to avoid resetting CPU
* affinity */
diff --git a/tests/domainschemadata/domain-perf-simple.xml
b/tests/domainschemadata/domain-perf-simple.xml
new file mode 100644
index 0000000..d7be7c9
--- /dev/null
+++ b/tests/domainschemadata/domain-perf-simple.xml
@@ -0,0 +1,20 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <perf>
+ <event name='cmt' enabled='yes'/>
+ </perf>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ </devices>
+</domain>
--
1.9.1