[libvirt] [PATCH v4 2/4] perf: introduce a static attr table and refactor virPerfEventEnable() for general purpose

Qiaowei Ren qiaowei.ren at intel.com
Sat Jul 16 08:15:11 UTC 2016


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 at 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




More information about the libvir-list mailing list