This patch creates some sort of static table/matrix that would be able to convert the VIR_PERF_EVENT_* into their respective "attr.type" and "attr.config", so that virPerfEventEnable() doesn't have the switch the calling function passes by value the 'type'. This change is for general purpose in future. Signed-off-by: Qiaowei Ren <qiaowei.ren@xxxxxxxxx> --- src/util/virperf.c | 160 ++++++++++++++++++++++++++++++----------------------- src/util/virperf.h | 6 ++ 2 files changed, 97 insertions(+), 69 deletions(-) diff --git a/src/util/virperf.c b/src/util/virperf.c index 4661ba3..01c7c70 100644 --- a/src/util/virperf.c +++ b/src/util/virperf.c @@ -57,6 +57,8 @@ struct virPerf { struct virPerfEvent events[VIR_PERF_EVENT_LAST]; }; +static void virPerfRdtAttrInit(void); + virPerfPtr virPerfNew(void) { @@ -72,6 +74,8 @@ virPerfNew(void) perf->events[i].enabled = false; } + virPerfRdtAttrInit(); + return perf; } @@ -95,12 +99,21 @@ virPerfFree(virPerfPtr perf) # include <linux/perf_event.h> -static virPerfEventPtr -virPerfGetEvent(virPerfPtr perf, - virPerfEventType type) +static struct virPerfEventAttr { + int type; + unsigned int attrType; + unsigned long long attrConfig; +} attrs[] = { + {.type = VIR_PERF_EVENT_CMT, .attrType = 0, .attrConfig = 1}, + {.type = VIR_PERF_EVENT_MBMT, .attrType = 0, .attrConfig = 2}, + {.type = VIR_PERF_EVENT_MBML, .attrType = 0, .attrConfig = 3}, +}; +typedef struct virPerfEventAttr *virPerfEventAttrPtr; + +static virPerfEventAttrPtr +virPerfGetEventAttr(virPerfEventType type) { - if (!perf) - return NULL; + size_t i; if (type >= VIR_PERF_EVENT_LAST) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -109,17 +122,20 @@ virPerfGetEvent(virPerfPtr perf, return NULL; } - return perf->events + type; + for (i = 0; i < VIR_PERF_EVENT_LAST; i++) { + if (i == type) + return attrs + i; + } + + return NULL; } -static int -virPerfRdtEnable(virPerfEventPtr event, - pid_t pid) +static void virPerfRdtAttrInit(void) { - struct perf_event_attr rdt_attr; char *buf = NULL; char *tmp = NULL; - unsigned int event_type, scale; + size_t i; + unsigned int attr_type = 0; if (virFileReadAll("/sys/devices/intel_cqm/type", 10, &buf) < 0) @@ -128,48 +144,74 @@ virPerfRdtEnable(virPerfEventPtr event, if ((tmp = strchr(buf, '\n'))) *tmp = '\0'; - if (virStrToLong_ui(buf, NULL, 10, &event_type) < 0) { + if (virStrToLong_ui(buf, NULL, 10, &attr_type) < 0) { virReportSystemError(errno, "%s", _("failed to get rdt event type")); goto error; } VIR_FREE(buf); - 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; - - 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; + for (i = 0; i < VIR_PERF_EVENT_LAST; i++) { + if (i == VIR_PERF_EVENT_CMT || + i == VIR_PERF_EVENT_MBMT || + i == VIR_PERF_EVENT_MBML) + attrs[i].attrType = attr_type; + } + + error: + VIR_FREE(buf); +} + +static virPerfEventPtr +virPerfGetEvent(virPerfPtr perf, + virPerfEventType type) +{ + if (!perf) + return NULL; + + if (type >= VIR_PERF_EVENT_LAST) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Event '%d' is not supported"), + type); + return NULL; } - event->fd = syscall(__NR_perf_event_open, &rdt_attr, pid, -1, -1, 0); + return perf->events + type; +} + +int +virPerfEventEnable(virPerfPtr perf, + virPerfEventType type, + pid_t pid) +{ + struct perf_event_attr attr; + virPerfEventPtr event = virPerfGetEvent(perf, type); + virPerfEventAttrPtr event_attr = virPerfGetEventAttr(type); + if (event == NULL || event_attr == NULL) + return -1; + + if (event_attr->attrType == 0 && (type == VIR_PERF_EVENT_CMT || + type == VIR_PERF_EVENT_MBMT || + type == VIR_PERF_EVENT_MBML)) { + virReportSystemError(errno, + _("Unable to open perf event for %s"), + virPerfEventTypeToString(event->type)); + return -1; + } + + memset(&attr, 0, sizeof(attr)); + attr.size = sizeof(attr); + attr.inherit = 1; + attr.disabled = 1; + attr.enable_on_exec = 0; + attr.type = event_attr->attrType; + attr.config = event_attr->attrConfig; + + event->fd = syscall(__NR_perf_event_open, &attr, pid, -1, -1, 0); if (event->fd < 0) { virReportSystemError(errno, - _("Unable to open perf type=%d for pid=%d"), - event_type, pid); + _("Unable to open perf event for %s"), + virPerfEventTypeToString(event->type)); goto error; } @@ -185,36 +227,10 @@ virPerfRdtEnable(virPerfEventPtr event, error: VIR_FORCE_CLOSE(event->fd); - VIR_FREE(buf); return -1; } int -virPerfEventEnable(virPerfPtr perf, - virPerfEventType type, - pid_t pid) -{ - virPerfEventPtr event = virPerfGetEvent(perf, type); - if (event == NULL) - return -1; - - switch (type) { - case VIR_PERF_EVENT_CMT: - case VIR_PERF_EVENT_MBMT: - case VIR_PERF_EVENT_MBML: - if (virPerfRdtEnable(event, pid) < 0) - return -1; - break; - case VIR_PERF_EVENT_LAST: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected perf event type=%d"), type); - return -1; - } - - return 0; -} - -int virPerfEventDisable(virPerfPtr perf, virPerfEventType type) { @@ -266,6 +282,12 @@ virPerfReadEvent(virPerfPtr perf, } #else +static void virPerfRdtAttrInit(void) +{ + virReportSystemError(ENXIO, "%s", + _("Perf not supported on this platform")); +} + int virPerfEventEnable(virPerfPtr perf ATTRIBUTE_UNUSED, virPerfEventType type ATTRIBUTE_UNUSED, diff --git a/src/util/virperf.h b/src/util/virperf.h index 7163410..acb59ab 100644 --- a/src/util/virperf.h +++ b/src/util/virperf.h @@ -25,6 +25,12 @@ # include "virutil.h" typedef enum { + /* Some Intel processor families introduced some RDT (Resource + * Director Technology) features to monitor or control shared + * resource. Among the features, CMT (Cache Monitoring Technology) + * and MBM (Memory Bandwidth Monitoring) is implemented based + * on perf framework in linux kernel. + */ VIR_PERF_EVENT_CMT, VIR_PERF_EVENT_MBMT, VIR_PERF_EVENT_MBML, -- 1.9.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list