diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 160f20faa5..27ed29a646 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1900,10 +1900,34 @@ void virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats); /** * VIR_PERF_PARAM_CMT: * - * Macro for typed parameter name that represents CMT perf event. + * Macro for typed parameter name that represents CMT perf event + * which can be used to measure the usage of cache (bytes) by + * applications running on the platform. It corresponds to the + * "perf.cmt" field in the *Stats APIs. */ # define VIR_PERF_PARAM_CMT "cmt" +/** + * VIR_PERF_PARAM_MBMT: + * + * Macro for typed parameter name that represents MBMT perf event + * which can be used to monitor total system bandwidth (bytes/s) + * from one level of cache to another. It corresponds to the + * "perf.mbmt" field in the *Stats APIs. + + */ +# define VIR_PERF_PARAM_MBMT "mbmt" + +/** + * VIR_PERF_PARAM_MBML: + * + * Macro for typed parameter name that represents MBML perf event + * which can be used to monitor the amount of data (bytes/s) sent + * through the memory controller on the socket. It corresponds to + * the "perf.mbml" field in the *Stats APIs. + */ +# define VIR_PERF_PARAM_MBML "mbml" + int virDomainGetPerfEvents(virDomainPtr dom, virTypedParameterPtr *params, int *nparams, diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 4f473c95ca..73ae369de0 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11441,6 +11441,18 @@ virConnectGetDomainCapabilities(virConnectPtr conn, * "block..physical" - physical size in bytes of the container of the * backing image as unsigned long long. * + * VIR_DOMAIN_STATS_PERF: Return perf event statistics. + * The typed parameter keys are in this format: + * "perf.cmt" - the usage of l3 cache (bytes) by applications running on the + * platform as unsigned long long. It is produced by cmt perf + * event. + * "perf.mbmt" - the total system bandwidth (bytes/s) from one level of cache + * to another as unsigned long long. It is produced by mbmt perf + * event. + * "perf.mbml" - the amount of data (bytes/s) sent through the memory controller + * on the socket as unsigned long long. It is produced by mbml + * perf event. + * * Note that entire stats groups or individual stat fields may be missing from * the output in case they are not supported by the given hypervisor, are not * applicable for the current state of the guest domain, or their retrieval diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ab1f58131d..51d6e331ff 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10038,6 +10038,8 @@ qemuDomainSetPerfEvents(virDomainPtr dom, if (virTypedParamsValidate(params, nparams, VIR_PERF_PARAM_CMT, VIR_TYPED_PARAM_BOOLEAN, + VIR_PERF_PARAM_MBMT, VIR_TYPED_PARAM_BOOLEAN, + VIR_PERF_PARAM_MBML, VIR_TYPED_PARAM_BOOLEAN, NULL) < 0) return -1; @@ -19479,20 +19481,25 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver, #undef QEMU_ADD_COUNT_PARAM static int -qemuDomainGetStatsPerfCmt(virPerfPtr perf, +qemuDomainGetStatsPerfRdt(virPerfPtr perf, + virPerfEventType type, virDomainStatsRecordPtr record, int *maxparams) { - uint64_t cache = 0; + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; + uint64_t value = 0; - if (virPerfReadEvent(perf, VIR_PERF_EVENT_CMT, &cache) < 0) + if (virPerfReadEvent(perf, type, &value) < 0) return -1; + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "perf.%s", + virPerfEventTypeToString(type)); + if (virTypedParamsAddULLong(&record->params, &record->nparams, maxparams, - "perf.cache", - cache) < 0) + param_name, + value) < 0) return -1; return 0; @@ -19515,7 +19522,9 @@ qemuDomainGetStatsPerf(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, switch (i) { case VIR_PERF_EVENT_CMT: - if (qemuDomainGetStatsPerfCmt(priv->perf, record, maxparams) < 0) + case VIR_PERF_EVENT_MBMT: + case VIR_PERF_EVENT_MBML: + if (qemuDomainGetStatsPerfRdt(priv->perf, i, record, maxparams) < 0) goto cleanup; break; } diff --git a/src/util/virperf.c b/src/util/virperf.c index bd6558733b..450b3baf2a 100644 --- a/src/util/virperf.c +++ b/src/util/virperf.c @@ -38,7 +38,7 @@ VIR_LOG_INIT("util.perf"); #define VIR_FROM_THIS VIR_FROM_PERF VIR_ENUM_IMPL(virPerfEvent, VIR_PERF_EVENT_LAST, - "cmt"); + "cmt", "mbmt", "mbml"); struct virPerfEvent { int type; @@ -110,10 +110,10 @@ virPerfGetEvent(virPerfPtr perf, } static int -virPerfCmtEnable(virPerfEventPtr event, +virPerfRdtEnable(virPerfEventPtr event, pid_t pid) { - struct perf_event_attr cmt_attr; + struct perf_event_attr rdt_attr; char *buf = NULL; char *tmp = NULL; unsigned int event_type, scale; @@ -127,32 +127,42 @@ virPerfCmtEnable(virPerfEventPtr event, if (virStrToLong_ui(buf, NULL, 10, &event_type) < 0) { virReportSystemError(errno, "%s", - _("failed to get cmt event type")); + _("failed to get rdt event type")); goto error; } VIR_FREE(buf); - if (virFileReadAll("/sys/devices/intel_cqm/events/llc_occupancy.scale", - 10, &buf) < 0) - goto error; + memset(&rdt_attr, 0, sizeof(rdt_attr)); + rdt_attr.size = sizeof(rdt_attr); + rdt_attr.type = event_type; + rdt_attr.inherit = 1; + rdt_attr.disabled = 1; + rdt_attr.enable_on_exec = 0; - if (virStrToLong_ui(buf, NULL, 10, &scale) < 0) { - virReportSystemError(errno, "%s", - _("failed to get cmt scaling factor")); - goto error; + switch (event->type) { + case VIR_PERF_EVENT_CMT: + if (virFileReadAll("/sys/devices/intel_cqm/events/llc_occupancy.scale", + 10, &buf) < 0) + goto error; + + if (virStrToLong_ui(buf, NULL, 10, &scale) < 0) { + virReportSystemError(errno, "%s", + _("failed to get cmt scaling factor")); + goto error; + } + event->efields.cmt.scale = scale; + + rdt_attr.config = 1; + break; + case VIR_PERF_EVENT_MBMT: + rdt_attr.config = 2; + break; + case VIR_PERF_EVENT_MBML: + rdt_attr.config = 3; + break; } - event->efields.cmt.scale = scale; - - memset(&cmt_attr, 0, sizeof(cmt_attr)); - cmt_attr.size = sizeof(cmt_attr); - cmt_attr.type = event_type; - cmt_attr.config = 1; - cmt_attr.inherit = 1; - cmt_attr.disabled = 1; - cmt_attr.enable_on_exec = 0; - - event->fd = syscall(__NR_perf_event_open, &cmt_attr, pid, -1, -1, 0); + event->fd = syscall(__NR_perf_event_open, &rdt_attr, pid, -1, -1, 0); if (event->fd < 0) { virReportSystemError(errno, _("Unable to open perf type=%d for pid=%d"), @@ -161,8 +171,9 @@ virPerfCmtEnable(virPerfEventPtr event, } if (ioctl(event->fd, PERF_EVENT_IOC_ENABLE) < 0) { - virReportSystemError(errno, "%s", - _("Unable to enable perf event for CMT")); + virReportSystemError(errno, + _("Unable to enable perf event for %s"), + virPerfEventTypeToString(event->type)); goto error; } @@ -186,7 +197,9 @@ virPerfEventEnable(virPerfPtr perf, switch (type) { case VIR_PERF_EVENT_CMT: - if (virPerfCmtEnable(event, pid) < 0) + case VIR_PERF_EVENT_MBMT: + case VIR_PERF_EVENT_MBML: + if (virPerfRdtEnable(event, pid) < 0) return -1; break; case VIR_PERF_EVENT_LAST: diff --git a/src/util/virperf.h b/src/util/virperf.h index 8ec87530b9..769e85a2fa 100644 --- a/src/util/virperf.h +++ b/src/util/virperf.h @@ -26,6 +26,8 @@ typedef enum { VIR_PERF_EVENT_CMT, + VIR_PERF_EVENT_MBMT, + VIR_PERF_EVENT_MBML, VIR_PERF_EVENT_LAST } virPerfEventType;