diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-list.c | 8 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 17 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 3 | ||||
-rw-r--r-- | tools/perf/util/pmus.c | 53 | ||||
-rw-r--r-- | tools/perf/util/pmus.h | 2 | ||||
-rw-r--r-- | tools/perf/util/print-events.h | 1 | ||||
-rw-r--r-- | tools/perf/util/s390-sample-raw.c | 3 |
7 files changed, 76 insertions, 11 deletions
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 8ac97a82744d..1ac47db4d66a 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -434,6 +434,13 @@ static void json_print_metric(void *ps __maybe_unused, const char *group, strbuf_release(&buf); } +static bool default_skip_duplicate_pmus(void *ps) +{ + struct print_state *print_state = ps; + + return !print_state->long_desc; +} + int cmd_list(int argc, const char **argv) { int i, ret = 0; @@ -445,6 +452,7 @@ int cmd_list(int argc, const char **argv) .print_end = default_print_end, .print_event = default_print_event, .print_metric = default_print_metric, + .skip_duplicate_pmus = default_skip_duplicate_pmus, }; const char *cputype = NULL; const char *unit_name = NULL; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index b92dc7237f3b..502fd58c3ea7 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1578,7 +1578,9 @@ int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, p .cb = cb, }; - return perf_pmu__for_each_event(pmu, &args, find_event_callback); + /* Sub-optimal, but function is only used by tests. */ + return perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/ false, + &args, find_event_callback); } static void perf_pmu__del_formats(struct list_head *formats) @@ -1652,10 +1654,13 @@ static int sub_non_neg(int a, int b) } static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, - const struct perf_pmu_alias *alias) + const struct perf_pmu_alias *alias, bool skip_duplicate_pmus) { struct parse_events_term *term; - int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); + int pmu_name_len = skip_duplicate_pmus + ? pmu_name_len_no_suffix(pmu->name, /*num=*/NULL) + : (int)strlen(pmu->name); + int used = snprintf(buf, len, "%.*s/%s", pmu_name_len, pmu->name, alias->name); list_for_each_entry(term, &alias->terms, list) { if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) @@ -1677,7 +1682,8 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, return buf; } -int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb) +int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, + void *state, pmu_event_callback cb) { char buf[1024]; struct perf_pmu_alias *event; @@ -1696,7 +1702,8 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callba info.name = event->name; buf_used = 0; } else { - info.name = format_alias(buf, sizeof(buf), pmu, event); + info.name = format_alias(buf, sizeof(buf), pmu, event, + skip_duplicate_pmus); if (pmu->is_core) { info.alias = info.name; info.name = event->name; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 73965f208009..6a4e170c61d6 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -212,7 +212,8 @@ bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu); bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu); bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name); size_t perf_pmu__num_events(struct perf_pmu *pmu); -int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb); +int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, + void *state, pmu_event_callback cb); bool pmu__name_match(const struct perf_pmu *pmu, const char *pmu_name); /** diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 7316da1c0ddb..6631367c756f 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -36,7 +36,7 @@ static LIST_HEAD(other_pmus); static bool read_sysfs_core_pmus; static bool read_sysfs_all_pmus; -static int pmu_name_len_no_suffix(const char *str, unsigned long *num) +int pmu_name_len_no_suffix(const char *str, unsigned long *num) { int orig_len, len; @@ -276,6 +276,43 @@ struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu) return NULL; } +static struct perf_pmu *perf_pmus__scan_skip_duplicates(struct perf_pmu *pmu) +{ + bool use_core_pmus = !pmu || pmu->is_core; + int last_pmu_name_len = 0; + const char *last_pmu_name = (pmu && pmu->name) ? pmu->name : ""; + + if (!pmu) { + pmu_read_sysfs(/*core_only=*/false); + pmu = list_prepare_entry(pmu, &core_pmus, list); + } else + last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", NULL); + + if (use_core_pmus) { + list_for_each_entry_continue(pmu, &core_pmus, list) { + int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", /*num=*/NULL); + + if (last_pmu_name_len == pmu_name_len && + !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len)) + continue; + + return pmu; + } + pmu = NULL; + pmu = list_prepare_entry(pmu, &other_pmus, list); + } + list_for_each_entry_continue(pmu, &other_pmus, list) { + int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", /*num=*/NULL); + + if (last_pmu_name_len == pmu_name_len && + !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len)) + continue; + + return pmu; + } + return NULL; +} + const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str) { struct perf_pmu *pmu = NULL; @@ -401,10 +438,17 @@ void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *p int len; struct sevent *aliases; struct events_callback_state state; + bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state); + struct perf_pmu *(*scan_fn)(struct perf_pmu *); + + if (skip_duplicate_pmus) + scan_fn = perf_pmus__scan_skip_duplicates; + else + scan_fn = perf_pmus__scan; pmu = NULL; len = 0; - while ((pmu = perf_pmus__scan(pmu)) != NULL) + while ((pmu = scan_fn(pmu)) != NULL) len += perf_pmu__num_events(pmu); aliases = zalloc(sizeof(struct sevent) * len); @@ -418,8 +462,9 @@ void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *p .aliases_len = len, .index = 0, }; - while ((pmu = perf_pmus__scan(pmu)) != NULL) { - perf_pmu__for_each_event(pmu, &state, perf_pmus__print_pmu_events__callback); + while ((pmu = scan_fn(pmu)) != NULL) { + perf_pmu__for_each_event(pmu, skip_duplicate_pmus, &state, + perf_pmus__print_pmu_events__callback); } qsort(aliases, len, sizeof(struct sevent), cmp_sevent); for (int j = 0; j < len; j++) { diff --git a/tools/perf/util/pmus.h b/tools/perf/util/pmus.h index a21464432d0f..4c67153ac257 100644 --- a/tools/perf/util/pmus.h +++ b/tools/perf/util/pmus.h @@ -5,6 +5,8 @@ struct perf_pmu; struct print_callbacks; +int pmu_name_len_no_suffix(const char *str, unsigned long *num); + void perf_pmus__destroy(void); struct perf_pmu *perf_pmus__find(const char *name); diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h index d7fab411e75c..bf4290bef0cd 100644 --- a/tools/perf/util/print-events.h +++ b/tools/perf/util/print-events.h @@ -26,6 +26,7 @@ struct print_callbacks { const char *expr, const char *threshold, const char *unit); + bool (*skip_duplicate_pmus)(void *print_state); }; /** Print all events, the default when no options are specified. */ diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index dc1ed3e95d4d..115b16edb451 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -171,7 +171,8 @@ static char *get_counter_name(int set, int nr, struct perf_pmu *pmu) if (!pmu) return NULL; - perf_pmu__for_each_event(pmu, &data, get_counter_name_callback); + perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/ true, + &data, get_counter_name_callback); return data.result; } |