Hello

I have been working on hybrid CPU support for PAPI.  libpfm4 supports this 
on Intel chips, but we are also interested in having big.LITTLE support on 
ARM.  Currently the libpfm4 arm PMU probing doesn't support this.

The patch below adds a new interface to libpfm4 that allows probing for 
multiple ARM PMUs instead of stopping after the first one found.  It 
modifies the Cortex-A53 to support this.  Before modifying any of the 
other ARM PMUs I wanted to see if this might be a viable way to get this 
support added to libpfm4.

I've tested this on an OrangePi800 machine with big.LITTLE 
Cortex-A72/Cor2tex-A53 and it works as expected (this requires a separate 
patch for Cortex-A72 support that hasn't been merged upstream yet).

diff --git a/lib/pfmlib_arm.c b/lib/pfmlib_arm.c
index 67efaeb..1cf831a 100644
--- a/lib/pfmlib_arm.c
+++ b/lib/pfmlib_arm.c
@@ -86,7 +86,7 @@ pfmlib_getcpuinfo_attr(const char *attr, char *ret_buf, 
size_t maxlen)
                        goto error;
 
                /*
-                * p+2: +1 = space, +2= firt character
+                * p+2: +1 = space, +2= first character
                 * strlen()-1 gets rid of \n
                 */
                *p = '\0';
@@ -105,12 +105,79 @@ error:
        fclose(fp);
        return ret;
 }
+
+int
+pfm_arm_detect_cpu(int implementer, int part)
+{
+
+       FILE *fp = NULL;
+       int ret = PFM_ERR_NOTSUPP;
+       char *buffer;
+       size_t buf_len = 0;
+       char *p, *value = NULL;
+       int last_implementer = -1, found_part = -1;
+
+       fp = fopen("/proc/cpuinfo", "r");
+       if (fp == NULL) {
+               return -1;
+       }
+
+
+       while(pfmlib_getl(&buffer, &buf_len, fp) != -1){
+
+               /* skip  blank lines */
+               if (*buffer == '\n')
+                       continue;
+
+               p = strchr(buffer, ':');
+               if (p == NULL)
+                       goto error;
+
+               /*
+                * p+2: +1 = space, +2= first character
+                * strlen()-1 gets rid of \n
+                */
+               *p = '\0';
+               value = p+2;
+
+               value[strlen(value)-1] = '\0';
+
+               if (!strncmp("CPU implementer", buffer, strlen("CPU 
implementer"))) {
+                       last_implementer = strtol(buffer, NULL, 16);
+               }
+
+               if (!strncmp("CPU part", buffer, strlen("CPU part"))) {
+                       found_part = strtol(value, NULL, 16);
+
+                       if ((last_implementer=implementer) &&
+                               (found_part==part)) {
+
+                               ret=PFM_SUCCESS;
+
+                               break;
+                       }
+               }
+       }
+
+error:
+       free(buffer);
+       fclose(fp);
+       return ret;
+}
+
+
 #else
 static int
 pfmlib_getcpuinfo_attr(const char *attr, char *ret_buf, size_t maxlen)
 {
        return -1;
 }
+
+int
+pfm_arm_detect_cpu(int implementer, int part)
+{
+       return -1;
+}
 #endif
 
 static int
diff --git a/lib/pfmlib_arm_armv8.c b/lib/pfmlib_arm_armv8.c
index bc1727b..812ff24 100644
--- a/lib/pfmlib_arm_armv8.c
+++ b/lib/pfmlib_arm_armv8.c
@@ -206,6 +206,7 @@ pfmlib_pmu_t arm_cortex_a57_support={
 pfmlib_pmu_t arm_cortex_a53_support={
        .desc                   = "ARM Cortex A53",
        .name                   = "arm_ac53",
+       .perf_name              = "armv8_cortex_a53",
        .pmu                    = PFM_PMU_ARM_CORTEX_A53,
        .pme_count              = LIBPFM_ARRAY_SIZE(arm_cortex_a53_pe),
        .type                   = PFM_PMU_TYPE_CORE,
diff --git a/lib/pfmlib_arm_perf_event.c b/lib/pfmlib_arm_perf_event.c
index de2396a..003d3c7 100644
--- a/lib/pfmlib_arm_perf_event.c
+++ b/lib/pfmlib_arm_perf_event.c
@@ -24,12 +24,39 @@
 #include <sys/types.h>
 #include <string.h>
 #include <stdlib.h>
+#include <limits.h>
 
 /* private headers */
 #include "pfmlib_priv.h"               /* library private */
 #include "pfmlib_arm_priv.h"
 #include "pfmlib_perf_event_priv.h"
 
+static int
+find_pmu_type_by_name(const char *name)
+{
+        char filename[PATH_MAX];
+        FILE *fp;
+        int ret, type;
+
+        if (!name)
+                return PFM_ERR_NOTSUPP;
+
+        sprintf(filename, "/sys/bus/event_source/devices/%s/type", name);
+
+        fp = fopen(filename, "r");
+        if (!fp)
+                return PFM_ERR_NOTSUPP;
+
+        ret = fscanf(fp, "%d", &type);
+        if (ret != 1)
+                type = PFM_ERR_NOTSUPP;
+
+        fclose(fp);
+
+        return type;
+}
+
+
 int
 pfm_arm_get_perf_encoding(void *this, pfmlib_event_desc_t *e)
 {
@@ -53,7 +80,17 @@ pfm_arm_get_perf_encoding(void *this, pfmlib_event_desc_t *e)
                return PFM_ERR_NOTSUPP;
        }
 
-       attr->type = PERF_TYPE_RAW;
+       if (pmu->perf_name) {
+               int type = find_pmu_type_by_name(pmu->perf_name);
+               if (type == PFM_ERR_NOTSUPP) {
+                       DPRINT("perf PMU %s, not supported by OS\n", 
pmu->perf_name);
+               } else {
+                       DPRINT("PMU %s perf type=%d\n", pmu->name, type);
+                       attr->type = type;
+               }
+       }
+
+//     attr->type = PERF_TYPE_RAW;
        reg.val = e->codes[0];
        /*
         * suppress the bits which are under the control of perf_events.
diff --git a/lib/pfmlib_arm_priv.h b/lib/pfmlib_arm_priv.h
index e3ed78a..1085f7f 100644
--- a/lib/pfmlib_arm_priv.h
+++ b/lib/pfmlib_arm_priv.h
@@ -62,6 +62,7 @@ typedef struct {
 extern pfm_arm_config_t pfm_arm_cfg;
 
 extern int pfm_arm_detect(void *this);
+extern int pfm_arm_detect_cpu(int implementer, int part);
 extern int pfm_arm_get_encoding(void *this, pfmlib_event_desc_t *e);
 extern int pfm_arm_get_event_first(void *this);
 extern int pfm_arm_get_event_next(void *this, int idx);


_______________________________________________
perfmon2-devel mailing list
perfmon2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

Reply via email to