]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf evsel: Add alternate_hw_config and use in evsel__match
authorIan Rogers <irogers@google.com>
Thu, 26 Sep 2024 14:48:32 +0000 (15:48 +0100)
committerNamhyung Kim <namhyung@kernel.org>
Thu, 26 Sep 2024 20:26:11 +0000 (13:26 -0700)
There are cases where we want to match events like instructions and
cycles with legacy hardware values, in particular in stat-shadow's
hard coded metrics. An evsel's name isn't a good point of reference as
it gets altered, strstr would be too imprecise and re-parsing the
event from its name is silly. Instead, hold the legacy hardware event
name, determined during parsing, in the evsel for this matching case.

Inline evsel__match2 that is only used in builtin-diff.

Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: James Clark <james.clark@linaro.org>
Cc: Yang Jihong <yangjihong@bytedance.com>
Cc: Dominique Martinet <asmadeus@codewreck.org>
Cc: Colin Ian King <colin.i.king@gmail.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Yunseong Kim <yskelg@gmail.com>
Cc: Ze Gao <zegao2021@gmail.com>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Yang Li <yang.lee@linux.alibaba.com>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: ak@linux.intel.com
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Sun Haiyong <sunhaiyong@loongson.cn>
Cc: John Garry <john.g.garry@oracle.com>
Link: https://lore.kernel.org/r/20240926144851.245903-2-james.clark@linaro.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/builtin-diff.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h

index 23326dd203339523a97e9ad3f76c189eb30ea2de..82fb7773e03e62eadeb9f596446e3e34c11db040 100644 (file)
@@ -469,13 +469,13 @@ out:
 
 static struct perf_diff pdiff;
 
-static struct evsel *evsel_match(struct evsel *evsel,
-                                     struct evlist *evlist)
+static struct evsel *evsel_match(struct evsel *evsel, struct evlist *evlist)
 {
        struct evsel *e;
 
        evlist__for_each_entry(evlist, e) {
-               if (evsel__match2(evsel, e))
+               if ((evsel->core.attr.type == e->core.attr.type) &&
+                   (evsel->core.attr.config == e->core.attr.config))
                        return e;
        }
 
index b9c18f33169974b7d6050603631cda26f81649dd..b9d7b56dfc5e98a5f386300b579bbe3b553a19c6 100644 (file)
@@ -299,6 +299,7 @@ void evsel__init(struct evsel *evsel,
        evsel->pmu_name      = NULL;
        evsel->group_pmu_name = NULL;
        evsel->skippable     = false;
+       evsel->alternate_hw_config = PERF_COUNT_HW_MAX;
 }
 
 struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx)
@@ -445,6 +446,8 @@ struct evsel *evsel__clone(struct evsel *orig)
        if (evsel__copy_config_terms(evsel, orig) < 0)
                goto out_err;
 
+       evsel->alternate_hw_config = orig->alternate_hw_config;
+
        return evsel;
 
 out_err:
@@ -1845,6 +1848,24 @@ static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread)
        return 0;
 }
 
+bool __evsel__match(const struct evsel *evsel, u32 type, u64 config)
+{
+
+       u32 e_type = evsel->core.attr.type;
+       u64 e_config = evsel->core.attr.config;
+
+       if (e_type != type) {
+               return type == PERF_TYPE_HARDWARE && evsel->pmu && evsel->pmu->is_core &&
+                       evsel->alternate_hw_config == config;
+       }
+
+       if ((type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) &&
+           perf_pmus__supports_extended_type())
+               e_config &= PERF_HW_EVENT_MASK;
+
+       return e_config == config;
+}
+
 int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread)
 {
        if (evsel__is_tool(evsel))
index 15e745a9a798fa29ef67cef9f03d2bb9616a891d..cf6f11fdfd061dc85b976818d20b71e39541cd94 100644 (file)
@@ -102,6 +102,7 @@ struct evsel {
                int                     bpf_fd;
                struct bpf_object       *bpf_obj;
                struct list_head        config_terms;
+               u64                     alternate_hw_config;
        };
 
        /*
@@ -393,26 +394,10 @@ u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sam
 struct tep_format_field *evsel__field(struct evsel *evsel, const char *name);
 struct tep_format_field *evsel__common_field(struct evsel *evsel, const char *name);
 
-static inline bool __evsel__match(const struct evsel *evsel, u32 type, u64 config)
-{
-       if (evsel->core.attr.type != type)
-               return false;
-
-       if ((type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE)  &&
-           perf_pmus__supports_extended_type())
-               return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == config;
-
-       return evsel->core.attr.config == config;
-}
+bool __evsel__match(const struct evsel *evsel, u32 type, u64 config);
 
 #define evsel__match(evsel, t, c) __evsel__match(evsel, PERF_TYPE_##t, PERF_COUNT_##c)
 
-static inline bool evsel__match2(struct evsel *e1, struct evsel *e2)
-{
-       return (e1->core.attr.type == e2->core.attr.type) &&
-              (e1->core.attr.config == e2->core.attr.config);
-}
-
 int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread);
 
 int __evsel__read_on_cpu(struct evsel *evsel, int cpu_map_idx, int thread, bool scale);
index 9a8be1e46d674ec781487715e4823cc72f379238..fcc4dab618bee4b113afc6dfa6e14bbf53126858 100644 (file)
@@ -228,7 +228,7 @@ __add_event(struct list_head *list, int *idx,
            bool init_attr,
            const char *name, const char *metric_id, struct perf_pmu *pmu,
            struct list_head *config_terms, bool auto_merge_stats,
-           struct perf_cpu_map *cpu_list)
+           struct perf_cpu_map *cpu_list, u64 alternate_hw_config)
 {
        struct evsel *evsel;
        struct perf_cpu_map *cpus = perf_cpu_map__is_empty(cpu_list) && pmu ? pmu->cpus : cpu_list;
@@ -264,6 +264,7 @@ __add_event(struct list_head *list, int *idx,
        evsel->auto_merge_stats = auto_merge_stats;
        evsel->pmu = pmu;
        evsel->pmu_name = pmu ? strdup(pmu->name) : NULL;
+       evsel->alternate_hw_config = alternate_hw_config;
 
        if (name)
                evsel->name = strdup(name);
@@ -286,16 +287,19 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr,
 {
        return __add_event(/*list=*/NULL, &idx, attr, /*init_attr=*/false, name,
                           metric_id, pmu, /*config_terms=*/NULL,
-                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL);
+                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL,
+                          /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
 }
 
 static int add_event(struct list_head *list, int *idx,
                     struct perf_event_attr *attr, const char *name,
-                    const char *metric_id, struct list_head *config_terms)
+                    const char *metric_id, struct list_head *config_terms,
+                    u64 alternate_hw_config)
 {
        return __add_event(list, idx, attr, /*init_attr*/true, name, metric_id,
                           /*pmu=*/NULL, config_terms,
-                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL) ? 0 : -ENOMEM;
+                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL,
+                          alternate_hw_config) ? 0 : -ENOMEM;
 }
 
 static int add_event_tool(struct list_head *list, int *idx,
@@ -315,7 +319,8 @@ static int add_event_tool(struct list_head *list, int *idx,
        evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL,
                            /*metric_id=*/NULL, /*pmu=*/NULL,
                            /*config_terms=*/NULL, /*auto_merge_stats=*/false,
-                           cpu_list);
+                           cpu_list,
+                           /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
        perf_cpu_map__put(cpu_list);
        if (!evsel)
                return -ENOMEM;
@@ -450,7 +455,7 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state,
 static int parse_events_add_pmu(struct parse_events_state *parse_state,
                                struct list_head *list, struct perf_pmu *pmu,
                                const struct parse_events_terms *const_parsed_terms,
-                               bool auto_merge_stats);
+                               bool auto_merge_stats, u64 alternate_hw_config);
 
 int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
                           struct parse_events_state *parse_state,
@@ -476,7 +481,8 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
                         */
                        ret = parse_events_add_pmu(parse_state, list, pmu,
                                                   parsed_terms,
-                                                  perf_pmu__auto_merge_stats(pmu));
+                                                  perf_pmu__auto_merge_stats(pmu),
+                                                  /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
                        if (ret)
                                return ret;
                        continue;
@@ -507,7 +513,8 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
 
                if (__add_event(list, idx, &attr, /*init_attr*/true, config_name ?: name,
                                metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
-                               /*cpu_list=*/NULL) == NULL)
+                               /*cpu_list=*/NULL,
+                               /*alternate_hw_config=*/PERF_COUNT_HW_MAX) == NULL)
                        return -ENOMEM;
 
                free_config_terms(&config_terms);
@@ -772,7 +779,7 @@ int parse_events_add_breakpoint(struct parse_events_state *parse_state,
        name = get_config_name(head_config);
 
        return add_event(list, &parse_state->idx, &attr, name, /*mertic_id=*/NULL,
-                        &config_terms);
+                       &config_terms, /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
 }
 
 static int check_type_val(struct parse_events_term *term,
@@ -1072,6 +1079,7 @@ static int config_term_pmu(struct perf_event_attr *attr,
                if (perf_pmu__have_event(pmu, term->config)) {
                        term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
                        term->no_value = true;
+                       term->alternate_hw_config = true;
                } else {
                        attr->type = PERF_TYPE_HARDWARE;
                        attr->config = term->val.num;
@@ -1384,8 +1392,9 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state,
        name = get_config_name(head_config);
        metric_id = get_config_metric_id(head_config);
        ret = __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, name,
-                       metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
-                       /*cpu_list=*/NULL) ? 0 : -ENOMEM;
+                         metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
+                         /*cpu_list=*/NULL, /*alternate_hw_config=*/PERF_COUNT_HW_MAX
+               ) == NULL ? -ENOMEM : 0;
        free_config_terms(&config_terms);
        return ret;
 }
@@ -1443,7 +1452,7 @@ static bool config_term_percore(struct list_head *config_terms)
 static int parse_events_add_pmu(struct parse_events_state *parse_state,
                                struct list_head *list, struct perf_pmu *pmu,
                                const struct parse_events_terms *const_parsed_terms,
-                               bool auto_merge_stats)
+                               bool auto_merge_stats, u64 alternate_hw_config)
 {
        struct perf_event_attr attr;
        struct perf_pmu_info info;
@@ -1480,7 +1489,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
                                    /*init_attr=*/true, /*name=*/NULL,
                                    /*metric_id=*/NULL, pmu,
                                    /*config_terms=*/NULL, auto_merge_stats,
-                                   /*cpu_list=*/NULL);
+                                   /*cpu_list=*/NULL, alternate_hw_config);
                return evsel ? 0 : -ENOMEM;
        }
 
@@ -1501,7 +1510,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
 
        /* Look for event names in the terms and rewrite into format based terms. */
        if (perf_pmu__check_alias(pmu, &parsed_terms,
-                                 &info, &alias_rewrote_terms, err)) {
+                                 &info, &alias_rewrote_terms,
+                                 &alternate_hw_config, err)) {
                parse_events_terms__exit(&parsed_terms);
                return -EINVAL;
        }
@@ -1546,7 +1556,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
        evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true,
                            get_config_name(&parsed_terms),
                            get_config_metric_id(&parsed_terms), pmu,
-                           &config_terms, auto_merge_stats, /*cpu_list=*/NULL);
+                           &config_terms, auto_merge_stats, /*cpu_list=*/NULL,
+                           alternate_hw_config);
        if (!evsel) {
                parse_events_terms__exit(&parsed_terms);
                return -ENOMEM;
@@ -1567,7 +1578,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_)
 {
@@ -1620,7 +1631,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
 
                auto_merge_stats = perf_pmu__auto_merge_stats(pmu);
                if (!parse_events_add_pmu(parse_state, list, pmu,
-                                         &parsed_terms, auto_merge_stats)) {
+                                         &parsed_terms, auto_merge_stats, hw_config)) {
                        struct strbuf sb;
 
                        strbuf_init(&sb, /*hint=*/ 0);
@@ -1633,7 +1644,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
 
        if (parse_state->fake_pmu) {
                if (!parse_events_add_pmu(parse_state, list, perf_pmus__fake_pmu(), &parsed_terms,
-                                         /*auto_merge_stats=*/true)) {
+                                         /*auto_merge_stats=*/true, hw_config)) {
                        struct strbuf sb;
 
                        strbuf_init(&sb, /*hint=*/ 0);
@@ -1674,13 +1685,15 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
        /* Attempt to add to list assuming event_or_pmu is a PMU name. */
        pmu = perf_pmus__find(event_or_pmu);
        if (pmu && !parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms,
-                                       /*auto_merge_stats=*/false))
+                                        /*auto_merge_stats=*/false,
+                                        /*alternate_hw_config=*/PERF_COUNT_HW_MAX))
                return 0;
 
        if (parse_state->fake_pmu) {
                if (!parse_events_add_pmu(parse_state, *listp, perf_pmus__fake_pmu(),
                                          const_parsed_terms,
-                                         /*auto_merge_stats=*/false))
+                                         /*auto_merge_stats=*/false,
+                                         /*alternate_hw_config=*/PERF_COUNT_HW_MAX))
                        return 0;
        }
 
@@ -1693,7 +1706,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
 
                        if (!parse_events_add_pmu(parse_state, *listp, pmu,
                                                  const_parsed_terms,
-                                                 auto_merge_stats)) {
+                                                 auto_merge_stats,
+                                                 /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) {
                                ok++;
                                parse_state->wild_card_pmus = true;
                        }
@@ -1704,7 +1718,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 10cc9c433116d673f99ad3e153fca24cb9fb659e..2b52f8d6aa29acb8054c16a07e537bc07912599f 100644 (file)
@@ -127,6 +127,12 @@ struct parse_events_term {
         * value is assumed to be 1. An event name also has no value.
         */
        bool no_value;
+       /**
+        * @alternate_hw_config: config is the event name but num is an
+        * alternate PERF_TYPE_HARDWARE config value which is often nice for the
+        * sake of quick matching.
+        */
+       bool alternate_hw_config;
 };
 
 struct parse_events_error {
@@ -238,7 +244,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 b3c51f06cbdc4b0f9cdd4e3f6722c904020bfd97..dcf47fabdfdd7a56f4c5fcc5da329a976774242e 100644 (file)
@@ -292,7 +292,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;
index 61bdda01a05aca4aedcc06a6b23b243550b02375..e32d601b48f1ed74d8b49a7586ee2b7b16b99851 100644 (file)
@@ -1606,7 +1606,7 @@ static int check_info_data(struct perf_pmu *pmu,
  */
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,
                          struct perf_pmu_info *info, bool *rewrote_terms,
-                         struct parse_events_error *err)
+                         u64 *alternate_hw_config, struct parse_events_error *err)
 {
        struct parse_events_term *term, *h;
        struct perf_pmu_alias *alias;
@@ -1638,6 +1638,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
                                                NULL);
                        return ret;
                }
+
                *rewrote_terms = true;
                ret = check_info_data(pmu, alias, info, err, term->err_term);
                if (ret)
@@ -1646,6 +1647,9 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
                if (alias->per_pkg)
                        info->per_pkg = true;
 
+               if (term->alternate_hw_config)
+                       *alternate_hw_config = term->val.num;
+
                list_del_init(&term->list);
                parse_events_term__delete(term);
        }
index 4397c48ad569a33586f2abbcf61543f393705404..f4271395c374453e21edd2ecec8abad64e4d05d4 100644 (file)
@@ -215,7 +215,7 @@ __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name);
 int perf_pmu__format_type(struct perf_pmu *pmu, const char *name);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,
                          struct perf_pmu_info *info, bool *rewrote_terms,
-                         struct parse_events_error *err);
+                         u64 *alternate_hw_config, struct parse_events_error *err);
 int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);
 
 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits);