From 4bb311b29e82c795340a6e4a5db83d8ccbe2dc49 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:39 -0800 Subject: perf parse-events: Pass ownership of the group name Pass ownership of the group name rather than copying and freeing the original. This saves a memory allocation and copy. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0336ff27c15f..1be454697d57 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1761,6 +1761,7 @@ parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, handled: ret = 1; + free(name); out: free(leaders); return ret; @@ -1786,7 +1787,7 @@ void parse_events__set_leader(char *name, struct list_head *list, leader = arch_evlist__leader(list); __perf_evlist__set_leader(list, &leader->core); - leader->group_name = name ? strdup(name) : NULL; + leader->group_name = name; list_move(&leader->core.node, list); } -- cgit From 347c2f0a0988c59c402148054ef54648853fa669 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:40 -0800 Subject: perf parse-events: Sort and group parsed events This change is intended to be a no-op for most current cases, the default sort order is the order the events were parsed. Where it varies is in how groups are handled. Previously an uncore and core event that are grouped would most often cause the group to be removed: ``` $ perf stat -e '{instructions,uncore_imc_free_running_0/data_total/}' -a sleep 1 WARNING: grouped events cpus do not match, disabling group: anon group { instructions, uncore_imc_free_running_0/data_total/ } ... ``` However, when wildcards are used the events should be re-sorted and re-grouped in parse_events__set_leader, but this currently fails for simple examples: ``` $ perf stat -e '{uncore_imc_free_running/data_read/,uncore_imc_free_running/data_write/}' -a sleep 1 Performance counter stats for 'system wide': MiB uncore_imc_free_running/data_read/ MiB uncore_imc_free_running/data_write/ 1.000996992 seconds time elapsed ``` A futher failure mode, fixed in this patch, is to force topdown events into a group. This change moves sorting the evsels in the evlist after parsing. It requires parsing to set up groups. First the evsels are sorted respecting the existing groupings and parse order, but also reordering to ensure evsels of the same PMU and group appear together. So that software and aux events respect groups, their pmu_name is taken from the group leader. The sorting is done with list_sort removing a memory allocation. After sorting a pass is done to correct the group leaders and for topdown events ensuring they have a group leader. This fixes the problems seen before: ``` $ perf stat -e '{uncore_imc_free_running/data_read/,uncore_imc_free_running/data_write/}' -a sleep 1 Performance counter stats for 'system wide': 727.42 MiB uncore_imc_free_running/data_read/ 81.84 MiB uncore_imc_free_running/data_write/ 1.000948615 seconds time elapsed ``` As well as making groups not fail for cases like: ``` $ perf stat -e '{imc_free_running_0/data_total/,imc_free_running_1/data_total/}' -a sleep 1 Performance counter stats for 'system wide': 256.47 MiB imc_free_running_0/data_total/ 256.48 MiB imc_free_running_1/data_total/ 1.001165442 seconds time elapsed ``` Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 240 ++++++++++++++++++++--------------------- 1 file changed, 116 insertions(+), 124 deletions(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1be454697d57..394ab23089d0 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include #include @@ -1655,125 +1656,7 @@ int parse_events__modifier_group(struct list_head *list, return parse_events__modifier_event(list, event_mod, true); } -/* - * Check if the two uncore PMUs are from the same uncore block - * The format of the uncore PMU name is uncore_#blockname_#pmuidx - */ -static bool is_same_uncore_block(const char *pmu_name_a, const char *pmu_name_b) -{ - char *end_a, *end_b; - - end_a = strrchr(pmu_name_a, '_'); - end_b = strrchr(pmu_name_b, '_'); - - if (!end_a || !end_b) - return false; - - if ((end_a - pmu_name_a) != (end_b - pmu_name_b)) - return false; - - return (strncmp(pmu_name_a, pmu_name_b, end_a - pmu_name_a) == 0); -} - -static int -parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, - struct parse_events_state *parse_state) -{ - struct evsel *evsel, *leader; - uintptr_t *leaders; - bool is_leader = true; - int i, nr_pmu = 0, total_members, ret = 0; - - leader = list_first_entry(list, struct evsel, core.node); - evsel = list_last_entry(list, struct evsel, core.node); - total_members = evsel->core.idx - leader->core.idx + 1; - - leaders = calloc(total_members, sizeof(uintptr_t)); - if (WARN_ON(!leaders)) - return 0; - - /* - * Going through the whole group and doing sanity check. - * All members must use alias, and be from the same uncore block. - * Also, storing the leader events in an array. - */ - __evlist__for_each_entry(list, evsel) { - - /* Only split the uncore group which members use alias */ - if (!evsel->use_uncore_alias) - goto out; - - /* The events must be from the same uncore block */ - if (!is_same_uncore_block(leader->pmu_name, evsel->pmu_name)) - goto out; - - if (!is_leader) - continue; - /* - * If the event's PMU name starts to repeat, it must be a new - * event. That can be used to distinguish the leader from - * other members, even they have the same event name. - */ - if ((leader != evsel) && - !strcmp(leader->pmu_name, evsel->pmu_name)) { - is_leader = false; - continue; - } - - /* Store the leader event for each PMU */ - leaders[nr_pmu++] = (uintptr_t) evsel; - } - - /* only one event alias */ - if (nr_pmu == total_members) { - parse_state->nr_groups--; - goto handled; - } - - /* - * An uncore event alias is a joint name which means the same event - * runs on all PMUs of a block. - * Perf doesn't support mixed events from different PMUs in the same - * group. The big group has to be split into multiple small groups - * which only include the events from the same PMU. - * - * Here the uncore event aliases must be from the same uncore block. - * The number of PMUs must be same for each alias. The number of new - * small groups equals to the number of PMUs. - * Setting the leader event for corresponding members in each group. - */ - i = 0; - __evlist__for_each_entry(list, evsel) { - if (i >= nr_pmu) - i = 0; - evsel__set_leader(evsel, (struct evsel *) leaders[i++]); - } - - /* The number of members and group name are same for each group */ - for (i = 0; i < nr_pmu; i++) { - evsel = (struct evsel *) leaders[i]; - evsel->core.nr_members = total_members / nr_pmu; - evsel->group_name = name ? strdup(name) : NULL; - } - - /* Take the new small groups into account */ - parse_state->nr_groups += nr_pmu - 1; - -handled: - ret = 1; - free(name); -out: - free(leaders); - return ret; -} - -__weak struct evsel *arch_evlist__leader(struct list_head *list) -{ - return list_first_entry(list, struct evsel, core.node); -} - -void parse_events__set_leader(char *name, struct list_head *list, - struct parse_events_state *parse_state) +void parse_events__set_leader(char *name, struct list_head *list) { struct evsel *leader; @@ -1782,13 +1665,9 @@ void parse_events__set_leader(char *name, struct list_head *list, return; } - if (parse_events__set_leader_for_uncore_aliase(name, list, parse_state)) - return; - - leader = arch_evlist__leader(list); + leader = list_first_entry(list, struct evsel, core.node); __perf_evlist__set_leader(list, &leader->core); leader->group_name = name; - list_move(&leader->core.node, list); } /* list_event is assumed to point to malloc'ed memory */ @@ -2245,6 +2124,117 @@ static int parse_events__with_hybrid_pmu(struct parse_events_state *parse_state, return ret; } +__weak int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs) +{ + /* Order by insertion index. */ + return lhs->core.idx - rhs->core.idx; +} + +static int evlist__cmp(void *state, const struct list_head *l, const struct list_head *r) +{ + const struct perf_evsel *lhs_core = container_of(l, struct perf_evsel, node); + const struct evsel *lhs = container_of(lhs_core, struct evsel, core); + const struct perf_evsel *rhs_core = container_of(r, struct perf_evsel, node); + const struct evsel *rhs = container_of(rhs_core, struct evsel, core); + int *leader_idx = state; + int lhs_leader_idx = *leader_idx, rhs_leader_idx = *leader_idx, ret; + const char *lhs_pmu_name, *rhs_pmu_name; + + /* + * First sort by grouping/leader. Read the leader idx only if the evsel + * is part of a group, as -1 indicates no group. + */ + if (lhs_core->leader != lhs_core || lhs_core->nr_members > 1) + lhs_leader_idx = lhs_core->leader->idx; + if (rhs_core->leader != rhs_core || rhs_core->nr_members > 1) + rhs_leader_idx = rhs_core->leader->idx; + + if (lhs_leader_idx != rhs_leader_idx) + return lhs_leader_idx - rhs_leader_idx; + + /* Group by PMU. Groups can't span PMUs. */ + lhs_pmu_name = evsel__group_pmu_name(lhs); + rhs_pmu_name = evsel__group_pmu_name(rhs); + ret = strcmp(lhs_pmu_name, rhs_pmu_name); + if (ret) + return ret; + + /* Architecture specific sorting. */ + return arch_evlist__cmp(lhs, rhs); +} + +static void parse_events__sort_events_and_fix_groups(struct list_head *list) +{ + int idx = -1; + struct evsel *pos, *cur_leader = NULL; + struct perf_evsel *cur_leaders_grp = NULL; + + /* + * Compute index to insert ungrouped events at. Place them where the + * first ungrouped event appears. + */ + list_for_each_entry(pos, list, core.node) { + const struct evsel *pos_leader = evsel__leader(pos); + + if (pos != pos_leader || pos->core.nr_members > 1) + continue; + + idx = pos->core.idx; + break; + } + + /* Sort events. */ + list_sort(&idx, list, evlist__cmp); + + /* + * Recompute groups, splitting for PMUs and adding groups for events + * that require them. + */ + idx = 0; + list_for_each_entry(pos, list, core.node) { + const struct evsel *pos_leader = evsel__leader(pos); + const char *pos_pmu_name = evsel__group_pmu_name(pos); + const char *cur_leader_pmu_name, *pos_leader_pmu_name; + bool force_grouped = arch_evsel__must_be_in_group(pos); + + /* Reset index and nr_members. */ + pos->core.idx = idx++; + pos->core.nr_members = 0; + + /* + * Set the group leader respecting the given groupings and that + * groups can't span PMUs. + */ + if (!cur_leader) + cur_leader = pos; + + cur_leader_pmu_name = evsel__group_pmu_name(cur_leader); + if ((cur_leaders_grp != pos->core.leader && !force_grouped) || + strcmp(cur_leader_pmu_name, pos_pmu_name)) { + /* Event is for a different group/PMU than last. */ + cur_leader = pos; + /* + * Remember the leader's group before it is overwritten, + * so that later events match as being in the same + * group. + */ + cur_leaders_grp = pos->core.leader; + } + pos_leader_pmu_name = evsel__group_pmu_name(pos_leader); + if (strcmp(pos_leader_pmu_name, pos_pmu_name) || force_grouped) { + /* + * Event's PMU differs from its leader's. Groups can't + * span PMUs, so update leader from the group/PMU + * tracker. + */ + evsel__set_leader(pos, cur_leader); + } + } + list_for_each_entry(pos, list, core.node) { + pos->core.leader->nr_members++; + } +} + int __parse_events(struct evlist *evlist, const char *str, struct parse_events_error *err, struct perf_pmu *fake_pmu) { @@ -2266,6 +2256,8 @@ int __parse_events(struct evlist *evlist, const char *str, return -1; } + parse_events__sort_events_and_fix_groups(&parse_state.list); + /* * Add list to the evlist even with errors to allow callers to clean up. */ -- cgit From e733f87e8c77751a00a538627eab1ac05e77cf0d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:41 -0800 Subject: perf evsel: Remove use_uncore_alias This flag used to be used when regrouping uncore events in particular due to wildcard matches. This is now handled by sorting evlist and so the flag is redundant. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 394ab23089d0..93a90651266f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1445,15 +1445,13 @@ static int parse_events__inside_hybrid_pmu(struct parse_events_state *parse_stat int parse_events_add_pmu(struct parse_events_state *parse_state, struct list_head *list, char *name, struct list_head *head_config, - bool auto_merge_stats, - bool use_alias) + bool auto_merge_stats) { struct perf_event_attr attr; struct perf_pmu_info info; struct perf_pmu *pmu; struct evsel *evsel; struct parse_events_error *err = parse_state->error; - bool use_uncore_alias; LIST_HEAD(config_terms); pmu = parse_state->fake_pmu ?: perf_pmu__find(name); @@ -1488,8 +1486,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, memset(&attr, 0, sizeof(attr)); } - use_uncore_alias = (pmu->is_uncore && use_alias); - if (!head_config) { attr.type = pmu->type; evsel = __add_event(list, &parse_state->idx, &attr, @@ -1499,7 +1495,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, /*cpu_list=*/NULL); if (evsel) { evsel->pmu_name = name ? strdup(name) : NULL; - evsel->use_uncore_alias = use_uncore_alias; return 0; } else { return -ENOMEM; @@ -1560,7 +1555,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, evsel->use_config_name = true; evsel->pmu_name = name ? strdup(name) : NULL; - evsel->use_uncore_alias = use_uncore_alias; evsel->percore = config_term_percore(&evsel->config_terms); if (parse_state->fake_pmu) @@ -1622,7 +1616,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, parse_events_copy_term_list(head, &orig_head); if (!parse_events_add_pmu(parse_state, list, pmu->name, orig_head, - true, true)) { + /*auto_merge_stats=*/true)) { pr_debug("%s -> %s/%s/\n", str, pmu->name, alias->str); ok++; @@ -1634,7 +1628,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, str, head, - true, true)) { + /*auto_merge_stats=*/true)) { pr_debug("%s -> %s/%s/\n", str, "fake_pmu", str); ok++; } -- cgit From 9d2dc632e09c0fe3a8a5890845bbd65b211fd662 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:42 -0800 Subject: perf evlist: Remove nr_groups Maintaining the number of groups during event parsing is problematic and since changing to sort/regroup events can only be computed by a linear pass over the evlist. As the value is generally only used in tests, rather than hold it in a variable compute it by passing over the evlist when necessary. This change highlights that libpfm's counting of groups with a single entry disagreed with regular event parsing. The libpfm tests are updated accordingly. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 93a90651266f..9ec3c1dc81e0 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2260,7 +2260,6 @@ int __parse_events(struct evlist *evlist, const char *str, if (!ret) { struct evsel *last; - evlist->core.nr_groups += parse_state.nr_groups; last = evlist__last(evlist); last->cmdline_group_boundary = true; -- cgit From a4c7d7c502b935f3a8324d954de78aecf6940897 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:43 -0800 Subject: perf parse-events: Warn when events are regrouped Use if an event is reordered or the number of groups increases to signal that regrouping has happened and warn about it. Disable the warning in the case wild card PMU names are used and for metrics. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 9ec3c1dc81e0..3b2e5bb3e852 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2157,11 +2157,13 @@ static int evlist__cmp(void *state, const struct list_head *l, const struct list return arch_evlist__cmp(lhs, rhs); } -static void parse_events__sort_events_and_fix_groups(struct list_head *list) +static bool parse_events__sort_events_and_fix_groups(struct list_head *list) { - int idx = -1; + int idx = 0, unsorted_idx = -1; struct evsel *pos, *cur_leader = NULL; struct perf_evsel *cur_leaders_grp = NULL; + bool idx_changed = false; + int orig_num_leaders = 0, num_leaders = 0; /* * Compute index to insert ungrouped events at. Place them where the @@ -2170,15 +2172,22 @@ static void parse_events__sort_events_and_fix_groups(struct list_head *list) list_for_each_entry(pos, list, core.node) { const struct evsel *pos_leader = evsel__leader(pos); - if (pos != pos_leader || pos->core.nr_members > 1) - continue; + if (pos == pos_leader) + orig_num_leaders++; - idx = pos->core.idx; - break; + /* + * Ensure indexes are sequential, in particular for multiple + * event lists being merged. The indexes are used to detect when + * the user order is modified. + */ + pos->core.idx = idx++; + + if (unsorted_idx == -1 && pos == pos_leader && pos->core.nr_members < 2) + unsorted_idx = pos->core.idx; } /* Sort events. */ - list_sort(&idx, list, evlist__cmp); + list_sort(&unsorted_idx, list, evlist__cmp); /* * Recompute groups, splitting for PMUs and adding groups for events @@ -2192,6 +2201,8 @@ static void parse_events__sort_events_and_fix_groups(struct list_head *list) bool force_grouped = arch_evsel__must_be_in_group(pos); /* Reset index and nr_members. */ + if (pos->core.idx != idx) + idx_changed = true; pos->core.idx = idx++; pos->core.nr_members = 0; @@ -2225,12 +2236,18 @@ static void parse_events__sort_events_and_fix_groups(struct list_head *list) } } list_for_each_entry(pos, list, core.node) { - pos->core.leader->nr_members++; + struct evsel *pos_leader = evsel__leader(pos); + + if (pos == pos_leader) + num_leaders++; + pos_leader->core.nr_members++; } + return idx_changed || num_leaders != orig_num_leaders; } int __parse_events(struct evlist *evlist, const char *str, - struct parse_events_error *err, struct perf_pmu *fake_pmu) + struct parse_events_error *err, struct perf_pmu *fake_pmu, + bool warn_if_reordered) { struct parse_events_state parse_state = { .list = LIST_HEAD_INIT(parse_state.list), @@ -2250,7 +2267,9 @@ int __parse_events(struct evlist *evlist, const char *str, return -1; } - parse_events__sort_events_and_fix_groups(&parse_state.list); + if (parse_events__sort_events_and_fix_groups(&parse_state.list) && + warn_if_reordered && !parse_state.wild_card_pmus) + pr_warning("WARNING: events were regrouped to match PMUs\n"); /* * Add list to the evlist even with errors to allow callers to clean up. -- cgit From d180aa56b50dd243dec89b24d23e0a59c3f0c0eb Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 14 Mar 2023 16:42:30 -0700 Subject: perf record: Add BPF event filter support Use --filter option to set BPF filter for generic events other than the tracepoints or Intel PT. The BPF program will check the sample data and filter according to the expression. For example, the below is the typical perf record for frequency mode. The sample period started from 1 and increased gradually. $ sudo ./perf record -e cycles true $ sudo ./perf script perf-exec 2272336 546683.916875: 1 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916892: 1 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916899: 3 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916905: 17 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916911: 100 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916917: 589 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916924: 3470 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) perf-exec 2272336 546683.916930: 20465 cycles: ffffffff828499b8 perf_event_exec+0x298 ([kernel.kallsyms]) true 2272336 546683.916940: 119873 cycles: ffffffff8283afdd perf_iterate_ctx+0x2d ([kernel.kallsyms]) true 2272336 546683.917003: 461349 cycles: ffffffff82892517 vma_interval_tree_insert+0x37 ([kernel.kallsyms]) true 2272336 546683.917237: 635778 cycles: ffffffff82a11400 security_mmap_file+0x20 ([kernel.kallsyms]) When you add a BPF filter to get samples having periods greater than 1000, the output would look like below: $ sudo ./perf record -e cycles --filter 'period > 1000' true $ sudo ./perf script perf-exec 2273949 546850.708501: 5029 cycles: ffffffff826f9e25 finish_wait+0x5 ([kernel.kallsyms]) perf-exec 2273949 546850.708508: 32409 cycles: ffffffff826f9e25 finish_wait+0x5 ([kernel.kallsyms]) perf-exec 2273949 546850.708526: 143369 cycles: ffffffff82b4cdbf xas_start+0x5f ([kernel.kallsyms]) perf-exec 2273949 546850.708600: 372650 cycles: ffffffff8286b8f7 __pagevec_lru_add+0x117 ([kernel.kallsyms]) perf-exec 2273949 546850.708791: 482953 cycles: ffffffff829190de __mod_memcg_lruvec_state+0x4e ([kernel.kallsyms]) true 2273949 546850.709036: 501985 cycles: ffffffff828add7c tlb_gather_mmu+0x4c ([kernel.kallsyms]) true 2273949 546850.709292: 503065 cycles: 7f2446d97c03 _dl_map_object_deps+0x973 (/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2) Committer notes: Add stubs for perf_bpf_filter__prepare() and perf_bpf_filter__destroy() to tools/perf/util/python.c to keep it building. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: Hao Luo Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Kan Liang Cc: Leo Yan Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Stephane Eranian Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230314234237.3008956-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 3b2e5bb3e852..6c5cf5244486 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -28,6 +28,7 @@ #include "perf.h" #include "util/parse-events-hybrid.h" #include "util/pmu-hybrid.h" +#include "util/bpf-filter.h" #include "tracepoint.h" #include "thread_map.h" @@ -2542,11 +2543,8 @@ static int set_filter(struct evsel *evsel, const void *arg) perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters); - if (!nr_addr_filters) { - fprintf(stderr, - "This CPU does not support address filtering\n"); - return -1; - } + if (!nr_addr_filters) + return perf_bpf_filter__parse(&evsel->bpf_filters, str); if (evsel__append_addr_filter(evsel, str) < 0) { fprintf(stderr, -- cgit From 204e7c499f5fa7732144ef9765c195982be72f31 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 17 Feb 2023 16:32:11 -0600 Subject: perf tools: Add support for perf_event_attr::config3 perf_event_attr has gained a new field, config3, so add support for it extending the existing configN support. Signed-off-by: Rob Herring Cc: Alexander Shishkin Cc: James Clark Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20220914-arm-perf-tool-spe1-2-v2-v5-2-2cf5210b2f77@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6c5cf5244486..cc8e8766ca30 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -949,6 +949,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_CONFIG] = "config", [PARSE_EVENTS__TERM_TYPE_CONFIG1] = "config1", [PARSE_EVENTS__TERM_TYPE_CONFIG2] = "config2", + [PARSE_EVENTS__TERM_TYPE_CONFIG3] = "config3", [PARSE_EVENTS__TERM_TYPE_NAME] = "name", [PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD] = "period", [PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ] = "freq", @@ -988,6 +989,7 @@ config_term_avail(int term_type, struct parse_events_error *err) case PARSE_EVENTS__TERM_TYPE_CONFIG: case PARSE_EVENTS__TERM_TYPE_CONFIG1: case PARSE_EVENTS__TERM_TYPE_CONFIG2: + case PARSE_EVENTS__TERM_TYPE_CONFIG3: case PARSE_EVENTS__TERM_TYPE_NAME: case PARSE_EVENTS__TERM_TYPE_METRIC_ID: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: @@ -1033,6 +1035,10 @@ do { \ CHECK_TYPE_VAL(NUM); attr->config2 = term->val.num; break; + case PARSE_EVENTS__TERM_TYPE_CONFIG3: + CHECK_TYPE_VAL(NUM); + attr->config3 = term->val.num; + break; case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: CHECK_TYPE_VAL(NUM); break; -- cgit From 66c9598bd8916c6c1319d0100ac916cac89d4b0e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 31 Mar 2023 13:29:42 -0700 Subject: perf tools: Fix a asan issue in parse_events_multi_pmu_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the parse_events_multi_pmu_add() it passes the 'config' variable twice to parse_events_term__num() - one for config and another for loc_term. I'm not sure about the second one as it's converted to YYLTYPE variable. Asan reports it like below: In function ‘parse_events_term__num’, inlined from ‘parse_events_multi_pmu_add’ at util/parse-events.c:1602:6: util/parse-events.c:2653:64: error: array subscript ‘YYLTYPE[0]’ is partly outside array bounds of ‘char[8]’ [-Werror=array-bounds] 2653 | .err_term = loc_term ? loc_term->first_column : 0, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ util/parse-events.c: In function ‘parse_events_multi_pmu_add’: util/parse-events.c:1587:15: note: object ‘config’ of size 8 1587 | char *config; | ^~~~~~ cc1: all warnings being treated as errors Signed-off-by: Namhyung Kim Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index cc8e8766ca30..0010e5e0ee68 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1601,7 +1601,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, - config, 1, false, &config, + config, 1, false, NULL, NULL) < 0) { free(config); goto out_err; -- cgit From ea0c52399d99d2e48cafdf97e2d8589bf8beb7c2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 10 Apr 2023 09:25:11 -0700 Subject: perf util: Move perf_guest/host declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definitions are in util.c so move the declarations to match. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Chengdong Li Cc: Denis Nikitin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Martin Liška Cc: Mathieu Poirier Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raul Silvera Cc: Ravi Bangoria Cc: Rob Herring Cc: Sean Christopherson Cc: Suzuki Poulouse Cc: Will Deacon Cc: Xing Zhengjun Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230410162511.3055900-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0010e5e0ee68..f341995cb04e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -25,10 +25,10 @@ #include "util/parse-branch-options.h" #include "util/evsel_config.h" #include "util/event.h" -#include "perf.h" #include "util/parse-events-hybrid.h" #include "util/pmu-hybrid.h" #include "util/bpf-filter.h" +#include "util/util.h" #include "tracepoint.h" #include "thread_map.h" -- cgit From 25feb605fe3b2674142d084379e0737a99945aba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Apr 2023 09:50:08 -0300 Subject: perf parse-events: Use zfree() to reduce chances of use after free Do defensive programming by using zfree() to initialize freed pointers to NULL, so that eventual use after free result in a NULL pointer deref instead of more subtle behaviour. Also remove one NULL test before free(), as it accepts a NULL arg and we get one line shaved not doing it explicitely. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index f341995cb04e..d71019dcd614 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2020,7 +2020,7 @@ int perf_pmu__test_parse_init(void) err_free: for (j = 0, tmp = list; j < i; j++, tmp++) - free(tmp->symbol); + zfree(&tmp->symbol); free(list); return -ENOMEM; } -- cgit From 327daf34554d20a6aa190dce5a625a555055435e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 2 May 2023 15:38:11 -0700 Subject: perf parse-events: Don't reorder ungrouped events by PMU The pmu_group_name by default returns "cpu" which on non-hybrid/ARM means that ungrouped software, and hardware events are all going to sort by the original insertion index. However, on hybrid and ARM wildcard expansion may mean the PMU name is set and events will be unnecessarily reordered - triggering the reordering warning. Signed-off-by: Ian Rogers Tested-by: Kan Liang Cc: Adrian Hunter Cc: Ahmad Yasin Cc: Alexander Shishkin Cc: Andi Kleen Cc: Athira Rajeev Cc: Caleb Biggers Cc: Edward Baker Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kang Minchul Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Cc: Samantha Alt Cc: Stephane Eranian Cc: Sumanth Korikkar Cc: Suzuki Poulouse Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xing Zhengjun Cc: Yang Jihong Link: https://lore.kernel.org/r/20230502223851.2234828-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'tools/perf/util/parse-events.c') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d71019dcd614..34ba840ae19a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2140,25 +2140,32 @@ static int evlist__cmp(void *state, const struct list_head *l, const struct list int *leader_idx = state; int lhs_leader_idx = *leader_idx, rhs_leader_idx = *leader_idx, ret; const char *lhs_pmu_name, *rhs_pmu_name; + bool lhs_has_group = false, rhs_has_group = false; /* * First sort by grouping/leader. Read the leader idx only if the evsel * is part of a group, as -1 indicates no group. */ - if (lhs_core->leader != lhs_core || lhs_core->nr_members > 1) + if (lhs_core->leader != lhs_core || lhs_core->nr_members > 1) { + lhs_has_group = true; lhs_leader_idx = lhs_core->leader->idx; - if (rhs_core->leader != rhs_core || rhs_core->nr_members > 1) + } + if (rhs_core->leader != rhs_core || rhs_core->nr_members > 1) { + rhs_has_group = true; rhs_leader_idx = rhs_core->leader->idx; + } if (lhs_leader_idx != rhs_leader_idx) return lhs_leader_idx - rhs_leader_idx; - /* Group by PMU. Groups can't span PMUs. */ - lhs_pmu_name = evsel__group_pmu_name(lhs); - rhs_pmu_name = evsel__group_pmu_name(rhs); - ret = strcmp(lhs_pmu_name, rhs_pmu_name); - if (ret) - return ret; + /* Group by PMU if there is a group. Groups can't span PMUs. */ + if (lhs_has_group && rhs_has_group) { + lhs_pmu_name = evsel__group_pmu_name(lhs); + rhs_pmu_name = evsel__group_pmu_name(rhs); + ret = strcmp(lhs_pmu_name, rhs_pmu_name); + if (ret) + return ret; + } /* Architecture specific sorting. */ return arch_evlist__cmp(lhs, rhs); -- cgit