]> www.infradead.org Git - nvme.git/commitdiff
perf parse-events: Prefer sysfs/JSON hardware events over legacy
authorIan Rogers <irogers@google.com>
Tue, 16 Apr 2024 06:15:25 +0000 (23:15 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Sat, 27 Apr 2024 01:07:20 +0000 (22:07 -0300)
It was requested that RISC-V be able to add events to the perf tool so
the PMU driver didn't need to map legacy events to config encodings:
https://lore.kernel.org/lkml/20240217005738.3744121-1-atishp@rivosinc.com/

This change makes the priority of events specified without a PMU the
same as those specified with a PMU, namely sysfs and JSON events are
checked first before using the legacy encoding.

The hw_term is made more generic as a hardware_event that encodes a
pair of string and int value, allowing parse_events_multi_pmu_add to
fall back on a known encoding when the sysfs/JSON adding fails for
core events. As this covers PE_VALUE_SYM_HW, that token is removed and
related code simplified.

Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Beeman Strong <beeman@rivosinc.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240416061533.921723-10-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l
tools/perf/util/parse-events.y

index 1b408e3dccc7bc360a3b709c01bb871982367fef..805872c90a3e03e85a39ab6a0c79e54c76abacde 100644 (file)
@@ -1543,7 +1543,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
 }
 
 int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
-                              const char *event_name,
+                              const char *event_name, u64 hw_config,
                               const struct parse_events_terms *const_parsed_terms,
                               struct list_head **listp, void *loc_)
 {
@@ -1551,8 +1551,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
        struct list_head *list = NULL;
        struct perf_pmu *pmu = NULL;
        YYLTYPE *loc = loc_;
-       int ok = 0;
-       const char *config;
+       int ok = 0, core_ok = 0;
+       const char *tmp;
        struct parse_events_terms parsed_terms;
 
        *listp = NULL;
@@ -1565,15 +1565,15 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
                        return ret;
        }
 
-       config = strdup(event_name);
-       if (!config)
+       tmp = strdup(event_name);
+       if (!tmp)
                goto out_err;
 
        if (parse_events_term__num(&term,
                                   PARSE_EVENTS__TERM_TYPE_USER,
-                                  config, /*num=*/1, /*novalue=*/true,
+                                  tmp, /*num=*/1, /*novalue=*/true,
                                   loc, /*loc_val=*/NULL) < 0) {
-               zfree(&config);
+               zfree(&tmp);
                goto out_err;
        }
        list_add_tail(&term->list, &parsed_terms.terms);
@@ -1604,6 +1604,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
                        pr_debug("%s -> %s/%s/\n", event_name, pmu->name, sb.buf);
                        strbuf_release(&sb);
                        ok++;
+                       if (pmu->is_core)
+                               core_ok++;
                }
        }
 
@@ -1620,6 +1622,18 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
                }
        }
 
+       if (hw_config != PERF_COUNT_HW_MAX && !core_ok) {
+               /*
+                * The event wasn't found on core PMUs but it has a hardware
+                * config version to try.
+                */
+               if (!parse_events_add_numeric(parse_state, list,
+                                               PERF_TYPE_HARDWARE, hw_config,
+                                               const_parsed_terms,
+                                               /*wildcard=*/true))
+                       ok++;
+       }
+
 out_err:
        parse_events_terms__exit(&parsed_terms);
        if (ok)
@@ -1673,7 +1687,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
 
        /* Failure to add, assume event_or_pmu is an event name. */
        zfree(listp);
-       if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc))
+       if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, PERF_COUNT_HW_MAX,
+                                       const_parsed_terms, listp, loc))
                return 0;
 
        if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0)
index 5005782766e974a6ac47ffaa875ef51b5111868c..7e5afad3feb8190a82808404506aea6de3a8b5f6 100644 (file)
@@ -215,7 +215,7 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr,
                                      struct perf_pmu *pmu);
 
 int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
-                              const char *event_name,
+                              const char *event_name, u64 hw_config,
                               const struct parse_events_terms *const_parsed_terms,
                               struct list_head **listp, void *loc);
 
index e86c45675e1d50b7294508cb7e6b221f363fce85..6fe37003ab7bc7c41d52d6139d47a4c278b1c6f3 100644 (file)
@@ -100,12 +100,12 @@ do {                                                              \
        yyless(0);                                              \
 } while (0)
 
-static int sym(yyscan_t scanner, int type, int config)
+static int sym(yyscan_t scanner, int config)
 {
        YYSTYPE *yylval = parse_events_get_lval(scanner);
 
-       yylval->num = (type << 16) + config;
-       return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
+       yylval->num = config;
+       return PE_VALUE_SYM_SW;
 }
 
 static int tool(yyscan_t scanner, enum perf_tool_event event)
@@ -124,13 +124,13 @@ static int term(yyscan_t scanner, enum parse_events__term_type type)
        return PE_TERM;
 }
 
-static int hw_term(yyscan_t scanner, int config)
+static int hw(yyscan_t scanner, int config)
 {
        YYSTYPE *yylval = parse_events_get_lval(scanner);
        char *text = parse_events_get_text(scanner);
 
-       yylval->hardware_term.str = strdup(text);
-       yylval->hardware_term.num = PERF_TYPE_HARDWARE + config;
+       yylval->hardware_event.str = strdup(text);
+       yylval->hardware_event.num = config;
        return PE_TERM_HW;
 }
 
@@ -246,16 +246,16 @@ percore                   { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); }
 aux-output             { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }
 aux-sample-size                { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); }
 metric-id              { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
-cpu-cycles|cycles                              { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend   { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend     { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions                                   { return hw_term(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references                               { return hw_term(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses                                   { return hw_term(yyscanner, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches                   { return hw_term(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses                                  { return hw_term(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles                                     { return hw_term(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles                                     { return hw_term(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-cycles|cycles                              { return hw(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend   { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend     { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions                                   { return hw(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references                               { return hw(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses                                   { return hw(yyscanner, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches                   { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses                                  { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles                                     { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles                                     { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
 r{num_raw_hex}         { return str(yyscanner, PE_RAW); }
 r0x{num_raw_hex}       { return str(yyscanner, PE_RAW); }
 ,                      { return ','; }
@@ -299,31 +299,31 @@ r0x{num_raw_hex}  { return str(yyscanner, PE_RAW); }
 <<EOF>>                        { BEGIN(INITIAL); }
 }
 
-cpu-cycles|cycles                              { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend     { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions                                   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references                               { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses                                   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches                   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses                                  { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles                                     { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles                                     { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
-cpu-clock                                      { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
-task-clock                                     { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
-page-faults|faults                             { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
-minor-faults                                   { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
-major-faults                                   { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
-context-switches|cs                            { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
-cpu-migrations|migrations                      { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
-alignment-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
-emulation-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
-dummy                                          { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
+cpu-cycles|cycles                              { return hw(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend   { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend     { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions                                   { return hw(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references                               { return hw(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses                                   { return hw(yyscanner, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches                   { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses                                  { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles                                     { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles                                     { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock                                      { return sym(yyscanner, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock                                     { return sym(yyscanner, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults                             { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults                                   { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults                                   { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs                            { return sym(yyscanner, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations                      { return sym(yyscanner, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults                               { return sym(yyscanner, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults                               { return sym(yyscanner, PERF_COUNT_SW_EMULATION_FAULTS); }
+dummy                                          { return sym(yyscanner, PERF_COUNT_SW_DUMMY); }
 duration_time                                  { return tool(yyscanner, PERF_TOOL_DURATION_TIME); }
 user_time                                              { return tool(yyscanner, PERF_TOOL_USER_TIME); }
 system_time                                            { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); }
-bpf-output                                     { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
-cgroup-switches                                        { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); }
+bpf-output                                     { return sym(yyscanner, PERF_COUNT_SW_BPF_OUTPUT); }
+cgroup-switches                                        { return sym(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); }
 
 {lc_type}                      { return str(yyscanner, PE_LEGACY_CACHE); }
 {lc_type}-{lc_op_result}       { return str(yyscanner, PE_LEGACY_CACHE); }
index 254f8aeca461d5082c62906b94b202ee0916cd31..31fe8cf428ffd546657a9b03b7640fad62a09ee5 100644 (file)
@@ -55,7 +55,7 @@ static void free_list_evsel(struct list_head* list_evsel)
 %}
 
 %token PE_START_EVENTS PE_START_TERMS
-%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM
+%token PE_VALUE PE_VALUE_SYM_SW PE_TERM
 %token PE_VALUE_SYM_TOOL
 %token PE_EVENT_NAME
 %token PE_RAW PE_NAME
@@ -66,11 +66,9 @@ static void free_list_evsel(struct list_head* list_evsel)
 %token PE_DRV_CFG_TERM
 %token PE_TERM_HW
 %type <num> PE_VALUE
-%type <num> PE_VALUE_SYM_HW
 %type <num> PE_VALUE_SYM_SW
 %type <num> PE_VALUE_SYM_TOOL
 %type <term_type> PE_TERM
-%type <num> value_sym
 %type <str> PE_RAW
 %type <str> PE_NAME
 %type <str> PE_LEGACY_CACHE
@@ -87,6 +85,7 @@ static void free_list_evsel(struct list_head* list_evsel)
 %type <list_terms> opt_pmu_config
 %destructor { parse_events_terms__delete ($$); } <list_terms>
 %type <list_evsel> event_pmu
+%type <list_evsel> event_legacy_hardware
 %type <list_evsel> event_legacy_symbol
 %type <list_evsel> event_legacy_cache
 %type <list_evsel> event_legacy_mem
@@ -104,8 +103,8 @@ static void free_list_evsel(struct list_head* list_evsel)
 %destructor { free_list_evsel ($$); } <list_evsel>
 %type <tracepoint_name> tracepoint_name
 %destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
-%type <hardware_term> PE_TERM_HW
-%destructor { free ($$.str); } <hardware_term>
+%type <hardware_event> PE_TERM_HW
+%destructor { free ($$.str); } <hardware_event>
 
 %union
 {
@@ -119,10 +118,10 @@ static void free_list_evsel(struct list_head* list_evsel)
                char *sys;
                char *event;
        } tracepoint_name;
-       struct hardware_term {
+       struct hardware_event {
                char *str;
                u64 num;
-       } hardware_term;
+       } hardware_event;
 }
 %%
 
@@ -263,6 +262,7 @@ PE_EVENT_NAME event_def
 event_def
 
 event_def: event_pmu |
+          event_legacy_hardware |
           event_legacy_symbol |
           event_legacy_cache sep_dc |
           event_legacy_mem sep_dc |
@@ -289,7 +289,7 @@ PE_NAME sep_dc
        struct list_head *list;
        int err;
 
-       err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1);
+       err = parse_events_multi_pmu_add(_parse_state, $1, PERF_COUNT_HW_MAX, NULL, &list, &@1);
        if (err < 0) {
                struct parse_events_state *parse_state = _parse_state;
                struct parse_events_error *error = parse_state->error;
@@ -305,24 +305,45 @@ PE_NAME sep_dc
        $$ = list;
 }
 
-value_sym:
-PE_VALUE_SYM_HW
+event_legacy_hardware:
+PE_TERM_HW opt_pmu_config
+{
+       /* List of created evsels. */
+       struct list_head *list = NULL;
+       int err = parse_events_multi_pmu_add(_parse_state, $1.str, $1.num, $2, &list, &@1);
+
+       free($1.str);
+       parse_events_terms__delete($2);
+       if (err)
+               PE_ABORT(err);
+
+       $$ = list;
+}
 |
-PE_VALUE_SYM_SW
+PE_TERM_HW sep_dc
+{
+       struct list_head *list;
+       int err;
+
+       err = parse_events_multi_pmu_add(_parse_state, $1.str, $1.num, NULL, &list, &@1);
+       free($1.str);
+       if (err)
+               PE_ABORT(err);
+       $$ = list;
+}
 
 event_legacy_symbol:
-value_sym '/' event_config '/'
+PE_VALUE_SYM_SW '/' event_config '/'
 {
        struct list_head *list;
-       int type = $1 >> 16;
-       int config = $1 & 255;
        int err;
-       bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
 
        list = alloc_list();
        if (!list)
                YYNOMEM;
-       err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard);
+       err = parse_events_add_numeric(_parse_state, list,
+                               /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1,
+                               $3, /*wildcard=*/false);
        parse_events_terms__delete($3);
        if (err) {
                free_list_evsel(list);
@@ -331,18 +352,17 @@ value_sym '/' event_config '/'
        $$ = list;
 }
 |
-value_sym sep_slash_slash_dc
+PE_VALUE_SYM_SW sep_slash_slash_dc
 {
        struct list_head *list;
-       int type = $1 >> 16;
-       int config = $1 & 255;
-       bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
        int err;
 
        list = alloc_list();
        if (!list)
                YYNOMEM;
-       err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard);
+       err = parse_events_add_numeric(_parse_state, list,
+                               /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1,
+                               /*head_config=*/NULL, /*wildcard=*/false);
        if (err)
                PE_ABORT(err);
        $$ = list;