[libvirt] [PATCH 1/1] perf: add support to perf event for MBM

MBM (Memory Bandwidth Monitoring) is a new feature introduced in some Intel processor families. MBM is build on the CMT (Cache Monitoring Technology) infrastructure to allow monitoring of bandwidth from one level of the cache hierarchy to the next. With current perf framework, this patch adds support to perf event for MBM. Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com> --- include/libvirt/libvirt-domain.h | 14 +++++++++++ src/qemu/qemu_driver.c | 50 ++++++++++++++++++++++++++++++++++++++++ src/util/virperf.c | 40 +++++++++++++++++++++----------- src/util/virperf.h | 2 ++ 4 files changed, 92 insertions(+), 14 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 160f20f..9c3795c 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1904,6 +1904,20 @@ void virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats); */ # define VIR_PERF_PARAM_CMT "cmt" +/** + * VIR_PERF_PARAM_MBMT: + * + * Macro for typed parameter name that represents MBMT perf event. + */ +# define VIR_PERF_PARAM_MBMT "mbmt" + +/** + * VIR_PERF_PARAM_MBML: + * + * Macro for typed parameter name that represents MBML perf event. + */ +# define VIR_PERF_PARAM_MBML "mbml" + int virDomainGetPerfEvents(virDomainPtr dom, virTypedParameterPtr *params, int *nparams, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c4c4968..8c79e49 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10051,6 +10051,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; @@ -19515,6 +19517,46 @@ qemuDomainGetStatsPerfCmt(virPerfPtr perf, } static int +qemuDomainGetStatsPerfMbmt(virPerfPtr perf, + virDomainStatsRecordPtr record, + int *maxparams) +{ + uint64_t total_bytes = 0; + + if (virPerfReadEvent(perf, VIR_PERF_EVENT_MBMT, &total_bytes) < 0) + return -1; + + if (virTypedParamsAddDouble(&record->params, + &record->nparams, + maxparams, + "perf.total_bytes", + total_bytes*1e-6) < 0) + return -1; + + return 0; +} + +static int +qemuDomainGetStatsPerfMbml(virPerfPtr perf, + virDomainStatsRecordPtr record, + int *maxparams) +{ + uint64_t local_bytes = 0; + + if (virPerfReadEvent(perf, VIR_PERF_EVENT_MBML, &local_bytes) < 0) + return -1; + + if (virTypedParamsAddDouble(&record->params, + &record->nparams, + maxparams, + "perf.local_bytes", + local_bytes*1e-6) < 0) + return -1; + + return 0; +} + +static int qemuDomainGetStatsPerf(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainObjPtr dom, virDomainStatsRecordPtr record, @@ -19534,6 +19576,14 @@ qemuDomainGetStatsPerf(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (qemuDomainGetStatsPerfCmt(priv->perf, record, maxparams) < 0) goto cleanup; break; + case VIR_PERF_EVENT_MBMT: + if (qemuDomainGetStatsPerfMbmt(priv->perf, record, maxparams) < 0) + goto cleanup; + break; + case VIR_PERF_EVENT_MBML: + if (qemuDomainGetStatsPerfMbml(priv->perf, record, maxparams) < 0) + goto cleanup; + break; } } diff --git a/src/util/virperf.c b/src/util/virperf.c index bd65587..7cfdd77 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; @@ -132,26 +132,36 @@ virPerfCmtEnable(virPerfEventPtr event, } VIR_FREE(buf); - 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; - 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; + 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; + + cmt_attr.config = 1; + break; + case VIR_PERF_EVENT_MBMT: + cmt_attr.config = 2; + break; + case VIR_PERF_EVENT_MBML: + cmt_attr.config = 3; + break; + } + event->fd = syscall(__NR_perf_event_open, &cmt_attr, pid, -1, -1, 0); if (event->fd < 0) { virReportSystemError(errno, @@ -186,6 +196,8 @@ virPerfEventEnable(virPerfPtr perf, switch (type) { case VIR_PERF_EVENT_CMT: + case VIR_PERF_EVENT_MBMT: + case VIR_PERF_EVENT_MBML: if (virPerfCmtEnable(event, pid) < 0) return -1; break; diff --git a/src/util/virperf.h b/src/util/virperf.h index 8ec8753..769e85a 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; -- 1.9.1

On Wed, May 11, 2016 at 17:09:01 +0800, Qiaowei Ren wrote:
MBM (Memory Bandwidth Monitoring) is a new feature introduced in some Intel processor families. MBM is build on the CMT (Cache Monitoring Technology) infrastructure to allow monitoring of bandwidth from one level of the cache hierarchy to the next. With current perf framework, this patch adds support to perf event for MBM.
Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com> --- include/libvirt/libvirt-domain.h | 14 +++++++++++ src/qemu/qemu_driver.c | 50 ++++++++++++++++++++++++++++++++++++++++ src/util/virperf.c | 40 +++++++++++++++++++++----------- src/util/virperf.h | 2 ++ 4 files changed, 92 insertions(+), 14 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 160f20f..9c3795c 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1904,6 +1904,20 @@ void virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats); */ # define VIR_PERF_PARAM_CMT "cmt"
+/** + * VIR_PERF_PARAM_MBMT: + * + * Macro for typed parameter name that represents MBMT perf event. + */ +# define VIR_PERF_PARAM_MBMT "mbmt" + +/** + * VIR_PERF_PARAM_MBML: + * + * Macro for typed parameter name that represents MBML perf event. + */ +# define VIR_PERF_PARAM_MBML "mbml"
Neither of those documents the unit or meaning of the value. [...]
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c4c4968..8c79e49 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c
[...]
@@ -19515,6 +19517,46 @@ qemuDomainGetStatsPerfCmt(virPerfPtr perf, }
static int +qemuDomainGetStatsPerfMbmt(virPerfPtr perf, + virDomainStatsRecordPtr record, + int *maxparams) +{ + uint64_t total_bytes = 0; + + if (virPerfReadEvent(perf, VIR_PERF_EVENT_MBMT, &total_bytes) < 0) + return -1; + + if (virTypedParamsAddDouble(&record->params, + &record->nparams, + maxparams, + "perf.total_bytes", + total_bytes*1e-6) < 0)
Memory bandwidth seems like it's in MiB/s thus dividing by 1 000 000 is not the right conversion. Additionally we should report it in bytes/s. The users can always convert it to any value they like.
+ return -1; + + return 0; +} + +static int +qemuDomainGetStatsPerfMbml(virPerfPtr perf, + virDomainStatsRecordPtr record, + int *maxparams) +{ + uint64_t local_bytes = 0; + + if (virPerfReadEvent(perf, VIR_PERF_EVENT_MBML, &local_bytes) < 0) + return -1; + + if (virTypedParamsAddDouble(&record->params, + &record->nparams, + maxparams, + "perf.local_bytes", + local_bytes*1e-6) < 0) + return -1; + + return 0; +}
Both above functions are almost identical. I think you could merge them and pass the difference as an argument.
+ +static int qemuDomainGetStatsPerf(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainObjPtr dom, virDomainStatsRecordPtr record,
[...]
diff --git a/src/util/virperf.c b/src/util/virperf.c index bd65587..7cfdd77 100644 --- a/src/util/virperf.c +++ b/src/util/virperf.c
[...]
@@ -132,26 +132,36 @@ virPerfCmtEnable(virPerfEventPtr event,
This does not seem to be the correct function to put this. All the variables and name hint that it's CMT specific ...
} VIR_FREE(buf);
- 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; - 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;
+ 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; + + cmt_attr.config = 1; + break; + case VIR_PERF_EVENT_MBMT: + cmt_attr.config = 2; + break; + case VIR_PERF_EVENT_MBML: + cmt_attr.config = 3; + break; + } + event->fd = syscall(__NR_perf_event_open, &cmt_attr, pid, -1, -1, 0); if (event->fd < 0) { virReportSystemError(errno, @@ -186,6 +196,8 @@ virPerfEventEnable(virPerfPtr perf,
switch (type) { case VIR_PERF_EVENT_CMT: + case VIR_PERF_EVENT_MBMT: + case VIR_PERF_EVENT_MBML: if (virPerfCmtEnable(event, pid) < 0)
... If you are going to reuse this function for the other events you need to refactor it before and make it universal.
return -1; break;
Peter
participants (2)
-
Peter Krempa
-
Qiaowei Ren