perf vendor events: Use more flexible pattern matching for CPU identification for...
authorWilliam Cohen <wcohen@redhat.com>
Mon, 4 Dec 2017 14:57:28 +0000 (09:57 -0500)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 5 Dec 2017 18:43:55 +0000 (15:43 -0300)
The powerpc cpuid information includes chip revision information.
Changes between chip revisions are usually minor bug fixes and usually
do not affect the operation of the performance monitoring hardware.

The original mapfile.csv matching requires enumerating every possible
cpuid string.  When a new minor chip revision is produced a new entry
has to be added to the mapfile.csv and the code recompiled to allow perf
to have the implementation specific perf events for this new minor
revision.  For users of various distibutions of Linux having to wait for
a new release of the kernel's perf tool to be built with these trivial
patches is inconvenient.

Using regular expressions rather than exactly string matching of the
entire cpuid string allows developers to write mapfile.csv files that do
not require patches and recompiles for each of these minor version
changes.  If special cases need to be made for some particular versions,
they can be placed earlier in the mapfile.csv file before the more
general matches.

Signed-off-by: William Cohen <wcohen@redhat.com>
Tested-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shriya <shriyak@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/20171204145728.16792-1-wcohen@redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/pmu-events/arch/powerpc/mapfile.csv
tools/perf/pmu-events/arch/x86/mapfile.csv
tools/perf/pmu-events/jevents.c
tools/perf/util/pmu.c

index a0f3a11ca19f14660ec7f3ad46ff5d8d848c66e4..229150e7ab7d0143668dfa78a5daab6c9a1f296f 100644 (file)
 #
 
 # Power8 entries
-004b0000,1,power8,core
-004b0201,1,power8,core
-004c0000,1,power8,core
-004d0000,1,power8,core
-004d0100,1,power8,core
-004d0200,1,power8,core
-004c0100,1,power8,core
-004e0100,1,power9,core
-004e0200,1,power9,core
-004e1200,1,power9,core
+004[bcd][[:xdigit:]]{4},1,power8,core
+004e[[:xdigit:]]{4},1,power9,core
index fe1a2c47cabf22d9dcbb28cc1718911dd1fb88cb..93656f2fd53a025a23ad88183bfc6da9e96023b1 100644 (file)
@@ -23,10 +23,7 @@ GenuineIntel-6-1E,v2,nehalemep,core
 GenuineIntel-6-1F,v2,nehalemep,core
 GenuineIntel-6-1A,v2,nehalemep,core
 GenuineIntel-6-2E,v2,nehalemex,core
-GenuineIntel-6-4E,v24,skylake,core
-GenuineIntel-6-5E,v24,skylake,core
-GenuineIntel-6-8E,v24,skylake,core
-GenuineIntel-6-9E,v24,skylake,core
+GenuineIntel-6-[4589]E,v24,skylake,core
 GenuineIntel-6-37,v13,silvermont,core
 GenuineIntel-6-4D,v13,silvermont,core
 GenuineIntel-6-4C,v13,silvermont,core
index 9eb7047bafe471277fa25cf9022057bddfcae31c..b578aa26e375dbdd0aeb12b3fea3f2b9c870dee2 100644 (file)
@@ -116,6 +116,43 @@ static void fixdesc(char *s)
                *e = 0;
 }
 
+/* Add escapes for '\' so they are proper C strings. */
+static char *fixregex(char *s)
+{
+       int len = 0;
+       int esc_count = 0;
+       char *fixed = NULL;
+       char *p, *q;
+
+       /* Count the number of '\' in string */
+       for (p = s; *p; p++) {
+               ++len;
+               if (*p == '\\')
+                       ++esc_count;
+       }
+
+       if (esc_count == 0)
+               return s;
+
+       /* allocate space for a new string */
+       fixed = (char *) malloc(len + 1);
+       if (!fixed)
+               return NULL;
+
+       /* copy over the characters */
+       q = fixed;
+       for (p = s; *p; p++) {
+               if (*p == '\\') {
+                       *q = '\\';
+                       ++q;
+               }
+               *q = *p;
+               ++q;
+       }
+       *q = '\0';
+       return fixed;
+}
+
 static struct msrmap {
        const char *num;
        const char *pname;
@@ -648,7 +685,7 @@ static int process_mapfile(FILE *outfp, char *fpath)
                }
                line[strlen(line)-1] = '\0';
 
-               cpuid = strtok_r(p, ",", &save);
+               cpuid = fixregex(strtok_r(p, ",", &save));
                version = strtok_r(NULL, ",", &save);
                fname = strtok_r(NULL, ",", &save);
                type = strtok_r(NULL, ",", &save);
index 8b7c151579c03f525dc8b4202b51aa3d38476584..57e38fdf0b34eb3bbcd93a41f354783c2a15c09b 100644 (file)
@@ -12,6 +12,7 @@
 #include <dirent.h>
 #include <api/fs/fs.h>
 #include <locale.h>
+#include <regex.h>
 #include "util.h"
 #include "pmu.h"
 #include "parse-events.h"
@@ -609,14 +610,31 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
 
        i = 0;
        for (;;) {
+               regex_t re;
+               regmatch_t pmatch[1];
+               int match;
+
                map = &pmu_events_map[i++];
                if (!map->table) {
                        map = NULL;
                        break;
                }
 
-               if (!strcmp(map->cpuid, cpuid))
+               if (regcomp(&re, map->cpuid, REG_EXTENDED) != 0) {
+                       /* Warn unable to generate match particular string. */
+                       pr_info("Invalid regular expression %s\n", map->cpuid);
                        break;
+               }
+
+               match = !regexec(&re, cpuid, 1, pmatch, 0);
+               regfree(&re);
+               if (match) {
+                       size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
+
+                       /* Verify the entire string matched. */
+                       if (match_len == strlen(cpuid))
+                               break;
+               }
        }
        free(cpuid);
        return map;