summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-list.c8
-rw-r--r--tools/perf/util/pmu.c17
-rw-r--r--tools/perf/util/pmu.h3
-rw-r--r--tools/perf/util/pmus.c53
-rw-r--r--tools/perf/util/pmus.h2
-rw-r--r--tools/perf/util/print-events.h1
-rw-r--r--tools/perf/util/s390-sample-raw.c3
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;
}