Revert "perf tools: Default to cpu// for events v5"
PATCH v2 1/3 Revert "perf tools: Default to cpu// for events v5"
From: Kan Liang <[email protected]>
This reverts commit 50e200f07948 ("perf tools: Default to cpu// for events v5")
The fixup cannot handle the case that
new style format(which without //) mixed with
other different formats.
For example,
group events with new style format: {mem-stores,mem-loads} some hardware event + new style event: cycles,mem-loads Cache event + new style event: LLC-loads,mem-loads
Raw event + new style event:
cpu/event=0xc8,umask=0x08/,mem-loads
old style event and new stytle mixture: mem-stores,cpu/mem-loads/
--- tools/perf/util/include/linux/string.h | 1 - tools/perf/util/parse-events.c | 30 +----------------------------- tools/perf/util/string.c | 24 ------------------------ 3 files changed, 1 insertion(+), 54 deletions(-)
tools/perf/util/include/linux/string.h +0 -1
@@ -1,4 +1,3 @@#include <string.h> void *memdup (const void *src,size_t len); -int str_append (char **s,int *len,const char *a);
tools/perf/util/parse-events.c +1 -29
@@ -6,7 +6,7 @@#include "parse-options.h" #include "parse-events.h" #include "exec_cmd.h" -#include "linux/string.h" +#include "string.h" #include "symbol.h" #include "cache.h" #include "header.h"
@@ -852,32 +852,6 @@ int parse_events_name(struct list_head *list, char *name)return 0 ; } -static int parse_events__scanner (const char *str,void *data,int start_token); - -static int parse_events_fixup (int ret,const char *str,void *data, -int start_token) -{ -char *o =strdup (str); -char *s =NULL ; -char *t = o; -char *p; -int len =0 ; - -if (!o) -return ret; -while ((p =strsep (&t,"," )) !=NULL ) { -if (s) -str_append (&s, &len,"," ); -str_append (&s, &len,"cpu/" ); -str_append (&s, &len, p); -str_append (&s, &len,"/" ); - } -free (o); -if (!s) -return -ENOMEM ; -return parse_events__scanner (s, data, start_token); -} -static int parse_events__scanner (const char *str,void *data,int start_token) {YY_BUFFER_STATE buffer;
@@ -898,8 +872,6 @@ static int parse_events__scanner(const char *str, void *data, int start_token)parse_events__flush_buffer (buffer, scanner);parse_events__delete_buffer (buffer, scanner);parse_events_lex_destroy (scanner); -if (ret && !strchr (str,'/' )) - ret =parse_events_fixup (ret, str, data, start_token);return ret; }
tools/perf/util/string.c +0 -24
@@ -387,27 +387,3 @@ void *memdup(const void *src, size_t len)return p; } - -/** -* str_append - reallocate string and append another -* @s: pointer to string pointer -* @len: pointer to len (initialized) -* @a: string to append. -*/ -int str_append (char **s,int *len,const char *a) -{ -int olen = *s ?strlen (*s) :0 ; -int nlen = olen +strlen (a) +1 ; -if (*len < nlen) { - *len = *len *2 ; -if (*len < nlen) - *len = nlen; - *s =realloc (*s, *len); -if (!*s) -return -ENOMEM ; -if (olen ==0 ) - **s =0 ; - } -strcat (*s, a); -return 0 ; -}
Signature · 1 line
1.8.3.2
PATCH v2 2/3 perf tools: parse the pmu event prefix and surfix
From: Kan Liang <[email protected]>
There are two types of event formats for PMU events. E.g. el-abort OR perf tools: parse the pmu event prefix and surfix
There are two types of event formats for PMU events. E.g. el-abort OR cpu/el-abort/. However, the lexer mistakenly recognizes the simple style format as two events.
The parse_events_pmu_check function uses bsearch to search the name in known pmu event list. It can tell the lexer that the name is a PE_NAME or a PMU event name prefix or a PMU event name suffix. All these information will be used for accurately parsing kernel PMU events.
The pmu events list will be read from sysfs at runtime.
---
V2: Read kernel PMU events from sysfs at runtime
tools/perf/util/parse-events.c | 103 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 15 ++++++ tools/perf/util/pmu.c | 10 ---- tools/perf/util/pmu.h | 10 ++++ 4 files changed, 128 insertions(+), 10 deletions(-)
tools/perf/util/parse-events.c +103 -0
@@ -29,6 +29,9 @@ extern int parse_events_debug;#endif int parse_events_parse (void *data,void *scanner); +static struct kernel_pmu_event_symbol *kernel_pmu_events_list; +static size_t kernel_pmu_events_list_num; +static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX ] = { [PERF_COUNT_HW_CPU_CYCLES ] = { .symbol ="cpu-cycles" ,
@@ -852,6 +855,103 @@ int parse_events_name(struct list_head *list, char *name)return 0 ; } +static int +comp_pmu (const void *p1,const void *p2) +{ +struct kernel_pmu_event_symbol *pmu1 = + (struct kernel_pmu_event_symbol *) p1; +struct kernel_pmu_event_symbol *pmu2 = + (struct kernel_pmu_event_symbol *) p2; + +return strcmp (pmu1->symbol, pmu2->symbol); +} + +enum kernel_pmu_event_type +parse_events_pmu_check (const char *name) +{ +struct kernel_pmu_event_symbol p, *r; + +/* +* name "cpu" could be prefix of cpu-cycles or cpu// events. +* cpu-cycles has been handled by hardcode. +* So it must be cpu// events, not kernel pmu event. +*/ +if (!kernel_pmu_events_list_num || !strcmp (name,"cpu" )) +return NONE_KERNEL_PMU_EVENT ; + +strcpy (p.symbol, name); + r =bsearch (&p, kernel_pmu_events_list, + kernel_pmu_events_list_num, +sizeof (struct kernel_pmu_event_symbol ), comp_pmu); +if (r ==NULL ) +return NONE_KERNEL_PMU_EVENT ; +return r->type; +} + +/* +* Read the pmu events list from sysfs +* Save it into kernel_pmu_events_list +*/ +static void scan_kernel_pmu_events_list (void ) +{ + +struct perf_pmu *pmu =NULL ; +struct perf_pmu_alias *alias; +int len =0 ; + +while ((pmu =perf_pmu__scan (pmu)) !=NULL ) +list_for_each_entry (alias, &pmu->aliases, list) { +if (!strcmp (pmu->name,"cpu" )) { +if (strchr (alias->name,'-' )) + len++; + len++; + } + } +if (len ==0 ) +return ; + kernel_pmu_events_list = +malloc (sizeof (struct kernel_pmu_event_symbol ) * len); + kernel_pmu_events_list_num = len; + + pmu =NULL ; + len =0 ; +while ((pmu =perf_pmu__scan (pmu)) !=NULL ) +list_for_each_entry (alias, &pmu->aliases, list) { +if (!strcmp (pmu->name,"cpu" )) { +struct kernel_pmu_event_symbol *p = + kernel_pmu_events_list + len; +char *tmp =strchr (alias->name,'-' ); + +if (tmp !=NULL ) { +strncpy (p->symbol, alias->name, + tmp - alias->name); + p->type =KERNEL_PMU_EVENT_PREFIX ; + tmp++; + p++; +strcpy (p->symbol, tmp); + p->type =KERNEL_PMU_EVENT_SUFFIX ; + len +=2 ; + }else { +strcpy (p->symbol, alias->name); + p->type =KERNEL_PMU_EVENT ; + len++; + } + } + } +qsort (kernel_pmu_events_list, len, +sizeof (struct kernel_pmu_event_symbol ), comp_pmu); + +} + +static void release_kernel_pmu_events_list (void ) +{ +if (kernel_pmu_events_list) { +free (kernel_pmu_events_list); + kernel_pmu_events_list =NULL ; + } + kernel_pmu_events_list_num =0 ; +} +static int parse_events__scanner (const char *str,void *data,int start_token) {YY_BUFFER_STATE buffer;
@@ -905,7 +1005,10 @@ int parse_events(struct perf_evlist *evlist, const char *str) };int ret; +/* scan kernel pmu events from sysfs */ +scan_kernel_pmu_events_list (); ret =parse_events__scanner (str, &data,PE_START_EVENTS ); +release_kernel_pmu_events_list ();if (!ret) {int entries = data.idx - evlist->nr_entries;perf_evlist__splice_list_tail (evlist, &data.list, entries);
tools/perf/util/parse-events.h +15 -0
@@ -35,6 +35,19 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);#define EVENTS_HELP_MAX (128*1024) +#define KERNEL_PMU_EVENT_MAX 1024 +enum kernel_pmu_event_type { +NONE_KERNEL_PMU_EVENT ,/* not a PMU EVENT */ +KERNEL_PMU_EVENT ,/* normal style PMU event */ +KERNEL_PMU_EVENT_PREFIX ,/* prefix of pre-suf style event */ +KERNEL_PMU_EVENT_SUFFIX ,/* suffix of pre-suf style event */ +}; + +struct kernel_pmu_event_symbol { +char symbol[KERNEL_PMU_EVENT_MAX ]; +enum kernel_pmu_event_type type; +}; +enum {PARSE_EVENTS__TERM_TYPE_NUM ,PARSE_EVENTS__TERM_TYPE_STR ,
@@ -95,6 +108,8 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, void *ptr, char *type);int parse_events_add_pmu (struct list_head *list,int *idx,char *pmu ,struct list_head *head_config); +enum kernel_pmu_event_type +parse_events_pmu_check (const char *name);void parse_events__set_leader (char *name,struct list_head *list);void parse_events_update_lists (struct list_head *list_event,struct list_head *list_all);
tools/perf/util/pmu.c +0 -10
@@ -10,16 +10,6 @@#include "parse-events.h" #include "cpumap.h" -#define UNIT_MAX_LEN 31/* max length for event unit name */ - -struct perf_pmu_alias { -char *name; -struct list_head terms; -struct list_head list; -char unit[UNIT_MAX_LEN +1 ]; -double scale; -}; -struct perf_pmu_format {char *name;int value;
tools/perf/util/pmu.h +10 -0
@@ -22,6 +22,16 @@ struct perf_pmu {struct list_head list; }; +#define UNIT_MAX_LEN 31/* max length for event unit name */ + +struct perf_pmu_alias { +char *name; +struct list_head terms; +struct list_head list; +char unit[UNIT_MAX_LEN +1 ]; +double scale; +}; +struct perf_pmu *perf_pmu__find (const char *name);int perf_pmu__config (struct perf_pmu *pmu,struct perf_event_attr *attr,struct list_head *head_terms);
Signature · 1 line
1.8.3.2
Re: [PATCH V2 2/3] perf tools: parse the pmu event prefix and surfix
tools/perf/util/parse-events.c int parse_events_name(struct list_head *list, char *name) · line 927
Quoted 10 lines
tools/perf/util/parse-events.c +10
-0+while ((pmu =perf_pmu__scan (pmu)) !=NULL ) +list_for_each_entry (alias, &pmu->aliases, list) { +if (!strcmp (pmu->name,"cpu" )) { +struct kernel_pmu_event_symbol *p = + kernel_pmu_events_list + len; +char *tmp =strchr (alias->name,'-' ); + +if (tmp !=NULL ) { +strncpy (p->symbol, alias->name, + tmp - alias->name);
Please use strlcpy(). Otherwise p->symbol may not be zero terminated.
The rest of the patch looks good to me.
-Andi
PATCH v2 3/3 perf tools: Add support to new style format of kernel PMU event
In reply to [email protected]From: Kan Liang <[email protected]>
Add new rules for kernel PMU event.
event_pmu:PE_KERNEL_PMU_EVENT
|PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF
PE_KERNEL_PMU_EVENT token is for
cycles-ct/cycles-t/mem-loads/mem-stores.
The prefix cycles is mixed up with cpu-cycles.
loads and stores are mixed up with cache event
So they have to be hardcode in lex.
PE_PMU_EVENT_PRE and PE_PMU_EVENT_SUF tokens are for other PMU events.
The lex looks generic identifier up in the table and return the matched token. If there is no match, generic PE_NAME token will be return.
Using the rules, kernel PMU event could use new style format without //
so you can use
perf record -e mem-loads ...
instead of
perf record -e cpu/mem-loads/
--- tools/perf/util/parse-events.l | 30 +++++++++++++++++++++++++++++- tools/perf/util/parse-events.y | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-)
tools/perf/util/parse-events.l +29 -1
@@ -51,6 +51,24 @@ static int str(yyscan_t scanner, int token) return token; } +static int pmu_str_check(yyscan_t scanner) +{ + YYSTYPE *yylval = parse_events_get_lval(scanner); + char *text = parse_events_get_text(scanner); + + yylval->str = strdup(text); + switch (parse_events_pmu_check(text)) { + case KERNEL_PMU_EVENT_PREFIX: + return PE_PMU_EVENT_PRE; + case KERNEL_PMU_EVENT_SUFFIX: + return PE_PMU_EVENT_SUF; + case KERNEL_PMU_EVENT: + return PE_KERNEL_PMU_EVENT; + default: + return PE_NAME; + } +} + static int sym(yyscan_t scanner, int type, int config) { YYSTYPE *yylval = parse_events_get_lval(scanner);
@@ -178,6 +196,16 @@ alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_AL emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } + /* + * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately. + * Because the prefix cycles is mixed up with cpu-cycles. + * loads and stores are mixed up with cache event + */ +cycles-ct { return str(yyscanner, PE_KERNEL_PMU_EVENT); } +cycles-t { return str(yyscanner, PE_KERNEL_PMU_EVENT); } +mem-loads { return str(yyscanner, PE_KERNEL_PMU_EVENT); } +mem-stores { return str(yyscanner, PE_KERNEL_PMU_EVENT); } + L1-dcache|l1-d|l1d|L1-data | L1-icache|l1-i|l1i|L1-instruction | LLC|L2 |
@@ -199,7 +227,7 @@ r{num_raw_hex} { return raw(yyscanner); } {num_hex} { return value(yyscanner, 16); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } -{name} { return str(yyscanner, PE_NAME); } +{name} { return pmu_str_check(yyscanner); } "/" { BEGIN(config); return '/'; } - { return '-'; } , { BEGIN(event); return ','; }
tools/perf/util/parse-events.y +42 -0
60 lines not on this page · raw message
Signature · 1 line
1.8.3.2