Use more flexible pattern matching for CPU identification for mapfile.csv
PATCH v4 1/1 Use more flexible pattern matching for CPU identification for mapfile.csv
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.
--- tools/perf/pmu-events/arch/powerpc/mapfile.csv | 12 ++------ tools/perf/pmu-events/arch/x86/mapfile.csv | 5 +--- tools/perf/pmu-events/jevents.c | 39 +++++++++++++++++++++++++- tools/perf/util/pmu.c | 20 ++++++++++++- 4 files changed, 60 insertions(+), 16 deletions(-)
tools/perf/pmu-events/arch/powerpc/mapfile.csv +2 -10
@@ -13,13 +13,5 @@ # # 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
tools/perf/pmu-events/arch/x86/mapfile.csv +1 -4
@@ -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
tools/perf/pmu-events/jevents.c +38 -1
@@ -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);
tools/perf/util/pmu.c +19 -1
@@ -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"
@@ -570,14 +571,31 @@ struct pmu_events_map *perf_pmu__find_map(void) 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;
Signature · 1 line
2.13.6
Quoted 11 lines · William Cohen
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.
Thanks,
Ravi
Arnaldo Carvalho de Melo
maintainerEm Tue, Dec 05, 2017 at 09:25:56AM +0530, Ravi Bangoria escreveu:
Quoted 14 lines · William Cohen
Quoted 11 lines
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.
Quoted 1 line
Tested-by Ravi Bangoria <[email protected]>
Thanks, added to the commit.
- Arnaldo
tip-bot for William Cohen
merge bot[tip:perf/core] perf vendor events: Use more flexible pattern matching for CPU identification for mapfile.csv
In reply to William Cohenperf vendor events: Use more flexible pattern matching for CPU identification for mapfile.csv
Commit-ID: fbc2844e84038ce3687d203ac80b66194e9f21e6 Gitweb: https://git.kernel.org/tip/fbc2844e84038ce3687d203ac80b66194e9f21e6 Author: William Cohen <[email protected]> AuthorDate: Mon, 4 Dec 2017 09:57:28 -0500 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 5 Dec 2017 15:43:55 -0300
perf vendor events: Use more flexible pattern matching for CPU identification for mapfile.csv
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.
--- tools/perf/pmu-events/arch/powerpc/mapfile.csv | 12 ++------ tools/perf/pmu-events/arch/x86/mapfile.csv | 5 +--- tools/perf/pmu-events/jevents.c | 39 +++++++++++++++++++++++++- tools/perf/util/pmu.c | 20 ++++++++++++- 4 files changed, 60 insertions(+), 16 deletions(-)
tools/perf/pmu-events/arch/powerpc/mapfile.csv +2 -10
@@ -13,13 +13,5 @@ # # 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
tools/perf/pmu-events/arch/x86/mapfile.csv +1 -4
@@ -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
tools/perf/pmu-events/jevents.c +38 -1
@@ -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);
tools/perf/util/pmu.c +19 -1
@@ -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;