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(a)intel.com>
---
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