Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf evlist: Make uniquifying counter names consistent

'perf stat' has different uniquification logic to 'perf record' and perf
top. In the case of perf record and 'perf top' all hybrid event names
are uniquified.

'perf stat' is more disciplined respecting name config terms, libpfm4
events, etc.

'perf stat' will uniquify hybrid events and the non-core PMU cases
shouldn't apply to perf record or 'perf top'.

For consistency, remove the uniquification for 'perf record' and 'perf
top' and reuse the 'perf stat' uniquification, making the code more
globally visible for this.

Fix the detection of cross-PMU for disabling uniquify by correctly
setting last_pmu.

When setting uniquify on an evsel, make sure the PMUs between the 2
considered events differ otherwise the uniquify isn't adding value.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Chun-Tse Shao <ctshao@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Dr. David Alan Gilbert <linux@treblig.org>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Levi Yun <yeoreum.yun@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Weilin Wang <weilin.wang@intel.com>
Link: https://lore.kernel.org/r/20250513215401.2315949-2-ctshao@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
7d45f402 ef60b8f5

+180 -177
+6 -1
tools/perf/builtin-record.c
··· 26 26 #include "util/target.h" 27 27 #include "util/session.h" 28 28 #include "util/tool.h" 29 + #include "util/stat.h" 29 30 #include "util/symbol.h" 30 31 #include "util/record.h" 31 32 #include "util/cpumap.h" ··· 2485 2484 pr_warning("WARNING: --timestamp-filename option is not available in pipe mode.\n"); 2486 2485 } 2487 2486 2488 - evlist__uniquify_name(rec->evlist); 2487 + /* 2488 + * Use global stat_config that is zero meaning aggr_mode is AGGR_NONE 2489 + * and hybrid_merge is false. 2490 + */ 2491 + evlist__uniquify_evsel_names(rec->evlist, &stat_config); 2489 2492 2490 2493 evlist__config(rec->evlist, opts, &callchain_param); 2491 2494
+6 -1
tools/perf/builtin-top.c
··· 35 35 #include "util/mmap.h" 36 36 #include "util/session.h" 37 37 #include "util/thread.h" 38 + #include "util/stat.h" 38 39 #include "util/symbol.h" 39 40 #include "util/synthetic-events.h" 40 41 #include "util/top.h" ··· 1310 1309 } 1311 1310 } 1312 1311 1313 - evlist__uniquify_name(top->evlist); 1312 + /* 1313 + * Use global stat_config that is zero meaning aggr_mode is AGGR_NONE 1314 + * and hybrid_merge is false. 1315 + */ 1316 + evlist__uniquify_evsel_names(top->evlist, &stat_config); 1314 1317 ret = perf_top__start_counters(top); 1315 1318 if (ret) 1316 1319 return ret;
+47 -25
tools/perf/util/evlist.c
··· 2565 2565 perf_cpu_map__put(user_requested_cpus); 2566 2566 } 2567 2567 2568 - void evlist__uniquify_name(struct evlist *evlist) 2568 + /* Should uniquify be disabled for the evlist? */ 2569 + static bool evlist__disable_uniquify(const struct evlist *evlist) 2569 2570 { 2570 - char *new_name, empty_attributes[2] = ":", *attributes; 2571 - struct evsel *pos; 2571 + struct evsel *counter; 2572 + struct perf_pmu *last_pmu = NULL; 2573 + bool first = true; 2572 2574 2573 - if (perf_pmus__num_core_pmus() == 1) 2574 - return; 2575 - 2576 - evlist__for_each_entry(evlist, pos) { 2577 - if (!evsel__is_hybrid(pos)) 2578 - continue; 2579 - 2580 - if (strchr(pos->name, '/')) 2581 - continue; 2582 - 2583 - attributes = strchr(pos->name, ':'); 2584 - if (attributes) 2585 - *attributes = '\0'; 2586 - else 2587 - attributes = empty_attributes; 2588 - 2589 - if (asprintf(&new_name, "%s/%s/%s", pos->pmu ? pos->pmu->name : "", 2590 - pos->name, attributes + 1)) { 2591 - free(pos->name); 2592 - pos->name = new_name; 2593 - } else { 2594 - *attributes = ':'; 2575 + evlist__for_each_entry(evlist, counter) { 2576 + /* If PMUs vary then uniquify can be useful. */ 2577 + if (!first && counter->pmu != last_pmu) 2578 + return false; 2579 + first = false; 2580 + if (counter->pmu) { 2581 + /* Allow uniquify for uncore PMUs. */ 2582 + if (!counter->pmu->is_core) 2583 + return false; 2584 + /* Keep hybrid event names uniquified for clarity. */ 2585 + if (perf_pmus__num_core_pmus() > 1) 2586 + return false; 2595 2587 } 2588 + last_pmu = counter->pmu; 2589 + } 2590 + return true; 2591 + } 2592 + 2593 + static bool evlist__set_needs_uniquify(struct evlist *evlist, const struct perf_stat_config *config) 2594 + { 2595 + struct evsel *counter; 2596 + bool needs_uniquify = false; 2597 + 2598 + if (evlist__disable_uniquify(evlist)) { 2599 + evlist__for_each_entry(evlist, counter) 2600 + counter->uniquified_name = true; 2601 + return false; 2602 + } 2603 + 2604 + evlist__for_each_entry(evlist, counter) { 2605 + if (evsel__set_needs_uniquify(counter, config)) 2606 + needs_uniquify = true; 2607 + } 2608 + return needs_uniquify; 2609 + } 2610 + 2611 + void evlist__uniquify_evsel_names(struct evlist *evlist, const struct perf_stat_config *config) 2612 + { 2613 + if (evlist__set_needs_uniquify(evlist, config)) { 2614 + struct evsel *pos; 2615 + 2616 + evlist__for_each_entry(evlist, pos) 2617 + evsel__uniquify_counter(pos); 2596 2618 } 2597 2619 } 2598 2620
+2 -1
tools/perf/util/evlist.h
··· 19 19 struct pollfd; 20 20 struct thread_map; 21 21 struct perf_cpu_map; 22 + struct perf_stat_config; 22 23 struct record_opts; 23 24 struct strbuf; 24 25 struct target; ··· 435 434 void evlist__format_evsels(struct evlist *evlist, struct strbuf *sb, size_t max_length); 436 435 void evlist__check_mem_load_aux(struct evlist *evlist); 437 436 void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list); 438 - void evlist__uniquify_name(struct evlist *evlist); 437 + void evlist__uniquify_evsel_names(struct evlist *evlist, const struct perf_stat_config *config); 439 438 bool evlist__has_bpf_output(struct evlist *evlist); 440 439 bool evlist__needs_bpf_sb_event(struct evlist *evlist); 441 440
+113
tools/perf/util/evsel.c
··· 3954 3954 leader->core.nr_members--; 3955 3955 } 3956 3956 } 3957 + 3958 + bool evsel__set_needs_uniquify(struct evsel *counter, const struct perf_stat_config *config) 3959 + { 3960 + struct evsel *evsel; 3961 + 3962 + if (counter->needs_uniquify) { 3963 + /* Already set. */ 3964 + return true; 3965 + } 3966 + 3967 + if (counter->merged_stat) { 3968 + /* Counter won't be shown. */ 3969 + return false; 3970 + } 3971 + 3972 + if (counter->use_config_name || counter->is_libpfm_event) { 3973 + /* Original name will be used. */ 3974 + return false; 3975 + } 3976 + 3977 + if (!config->hybrid_merge && evsel__is_hybrid(counter)) { 3978 + /* Unique hybrid counters necessary. */ 3979 + counter->needs_uniquify = true; 3980 + return true; 3981 + } 3982 + 3983 + if (counter->core.attr.type < PERF_TYPE_MAX && counter->core.attr.type != PERF_TYPE_RAW) { 3984 + /* Legacy event, don't uniquify. */ 3985 + return false; 3986 + } 3987 + 3988 + if (counter->pmu && counter->pmu->is_core && 3989 + counter->alternate_hw_config != PERF_COUNT_HW_MAX) { 3990 + /* A sysfs or json event replacing a legacy event, don't uniquify. */ 3991 + return false; 3992 + } 3993 + 3994 + if (config->aggr_mode == AGGR_NONE) { 3995 + /* Always unique with no aggregation. */ 3996 + counter->needs_uniquify = true; 3997 + return true; 3998 + } 3999 + 4000 + /* 4001 + * Do other non-merged events in the evlist have the same name? If so 4002 + * uniquify is necessary. 4003 + */ 4004 + evlist__for_each_entry(counter->evlist, evsel) { 4005 + if (evsel == counter || evsel->merged_stat || evsel->pmu == counter->pmu) 4006 + continue; 4007 + 4008 + if (evsel__name_is(counter, evsel__name(evsel))) { 4009 + counter->needs_uniquify = true; 4010 + return true; 4011 + } 4012 + } 4013 + return false; 4014 + } 4015 + 4016 + void evsel__uniquify_counter(struct evsel *counter) 4017 + { 4018 + const char *name, *pmu_name; 4019 + char *new_name, *config; 4020 + int ret; 4021 + 4022 + /* No uniquification necessary. */ 4023 + if (!counter->needs_uniquify) 4024 + return; 4025 + 4026 + /* The evsel was already uniquified. */ 4027 + if (counter->uniquified_name) 4028 + return; 4029 + 4030 + /* Avoid checking to uniquify twice. */ 4031 + counter->uniquified_name = true; 4032 + 4033 + name = evsel__name(counter); 4034 + pmu_name = counter->pmu->name; 4035 + /* Already prefixed by the PMU name. */ 4036 + if (!strncmp(name, pmu_name, strlen(pmu_name))) 4037 + return; 4038 + 4039 + config = strchr(name, '/'); 4040 + if (config) { 4041 + int len = config - name; 4042 + 4043 + if (config[1] == '/') { 4044 + /* case: event// */ 4045 + ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 2); 4046 + } else { 4047 + /* case: event/.../ */ 4048 + ret = asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config + 1); 4049 + } 4050 + } else { 4051 + config = strchr(name, ':'); 4052 + if (config) { 4053 + /* case: event:.. */ 4054 + int len = config - name; 4055 + 4056 + ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 1); 4057 + } else { 4058 + /* case: event */ 4059 + ret = asprintf(&new_name, "%s/%s/", pmu_name, name); 4060 + } 4061 + } 4062 + if (ret > 0) { 4063 + free(counter->name); 4064 + counter->name = new_name; 4065 + } else { 4066 + /* ENOMEM from asprintf. */ 4067 + counter->uniquified_name = false; 4068 + } 4069 + }
+4
tools/perf/util/evsel.h
··· 16 16 struct bpf_object; 17 17 struct cgroup; 18 18 struct perf_counts; 19 + struct perf_stat_config; 19 20 struct perf_stat_evsel; 20 21 union perf_event; 21 22 struct bpf_counter_ops; ··· 548 547 void evsel__remove_from_group(struct evsel *evsel, struct evsel *leader); 549 548 550 549 bool arch_evsel__must_be_in_group(const struct evsel *evsel); 550 + 551 + bool evsel__set_needs_uniquify(struct evsel *counter, const struct perf_stat_config *config); 552 + void evsel__uniquify_counter(struct evsel *counter); 551 553 552 554 /* 553 555 * Macro to swap the bit-field postition and size.
+1 -1
tools/perf/util/parse-events.c
··· 2267 2267 if (verbose > 0) { 2268 2268 struct strbuf sb = STRBUF_INIT; 2269 2269 2270 - evlist__uniquify_name(evlist); 2270 + evlist__uniquify_evsel_names(evlist, &stat_config); 2271 2271 evlist__format_evsels(evlist, &sb, 2048); 2272 2272 pr_debug("evlist after sorting/fixing: '%s'\n", sb.buf); 2273 2273 strbuf_release(&sb);
+1 -148
tools/perf/util/stat-display.c
··· 915 915 } 916 916 } 917 917 918 - static void evsel__uniquify_counter(struct evsel *counter) 919 - { 920 - const char *name, *pmu_name; 921 - char *new_name, *config; 922 - int ret; 923 - 924 - /* No uniquification necessary. */ 925 - if (!counter->needs_uniquify) 926 - return; 927 - 928 - /* The evsel was already uniquified. */ 929 - if (counter->uniquified_name) 930 - return; 931 - 932 - /* Avoid checking to uniquify twice. */ 933 - counter->uniquified_name = true; 934 - 935 - name = evsel__name(counter); 936 - pmu_name = counter->pmu->name; 937 - /* Already prefixed by the PMU name. */ 938 - if (!strncmp(name, pmu_name, strlen(pmu_name))) 939 - return; 940 - 941 - config = strchr(name, '/'); 942 - if (config) { 943 - int len = config - name; 944 - 945 - if (config[1] == '/') { 946 - /* case: event// */ 947 - ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 2); 948 - } else { 949 - /* case: event/.../ */ 950 - ret = asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config + 1); 951 - } 952 - } else { 953 - config = strchr(name, ':'); 954 - if (config) { 955 - /* case: event:.. */ 956 - int len = config - name; 957 - 958 - ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 1); 959 - } else { 960 - /* case: event */ 961 - ret = asprintf(&new_name, "%s/%s/", pmu_name, name); 962 - } 963 - } 964 - if (ret > 0) { 965 - free(counter->name); 966 - counter->name = new_name; 967 - } else { 968 - /* ENOMEM from asprintf. */ 969 - counter->uniquified_name = false; 970 - } 971 - } 972 - 973 918 /** 974 919 * should_skip_zero_count() - Check if the event should print 0 values. 975 920 * @config: The perf stat configuration (including aggregation mode). ··· 1004 1059 /* Skip already merged uncore/hybrid events */ 1005 1060 if (counter->merged_stat) 1006 1061 return; 1007 - 1008 - evsel__uniquify_counter(counter); 1009 1062 1010 1063 val = aggr->counts.val; 1011 1064 ena = aggr->counts.ena; ··· 1579 1636 print_metric_end(config, os); 1580 1637 } 1581 1638 1582 - /* Should uniquify be disabled for the evlist? */ 1583 - static bool evlist__disable_uniquify(const struct evlist *evlist) 1584 - { 1585 - struct evsel *counter; 1586 - struct perf_pmu *last_pmu = NULL; 1587 - bool first = true; 1588 - 1589 - evlist__for_each_entry(evlist, counter) { 1590 - /* If PMUs vary then uniquify can be useful. */ 1591 - if (!first && counter->pmu != last_pmu) 1592 - return false; 1593 - first = false; 1594 - if (counter->pmu) { 1595 - /* Allow uniquify for uncore PMUs. */ 1596 - if (!counter->pmu->is_core) 1597 - return false; 1598 - /* Keep hybrid event names uniquified for clarity. */ 1599 - if (perf_pmus__num_core_pmus() > 1) 1600 - return false; 1601 - } 1602 - } 1603 - return true; 1604 - } 1605 - 1606 - static void evsel__set_needs_uniquify(struct evsel *counter, const struct perf_stat_config *config) 1607 - { 1608 - struct evsel *evsel; 1609 - 1610 - if (counter->merged_stat) { 1611 - /* Counter won't be shown. */ 1612 - return; 1613 - } 1614 - 1615 - if (counter->use_config_name || counter->is_libpfm_event) { 1616 - /* Original name will be used. */ 1617 - return; 1618 - } 1619 - 1620 - if (!config->hybrid_merge && evsel__is_hybrid(counter)) { 1621 - /* Unique hybrid counters necessary. */ 1622 - counter->needs_uniquify = true; 1623 - return; 1624 - } 1625 - 1626 - if (counter->core.attr.type < PERF_TYPE_MAX && counter->core.attr.type != PERF_TYPE_RAW) { 1627 - /* Legacy event, don't uniquify. */ 1628 - return; 1629 - } 1630 - 1631 - if (counter->pmu && counter->pmu->is_core && 1632 - counter->alternate_hw_config != PERF_COUNT_HW_MAX) { 1633 - /* A sysfs or json event replacing a legacy event, don't uniquify. */ 1634 - return; 1635 - } 1636 - 1637 - if (config->aggr_mode == AGGR_NONE) { 1638 - /* Always unique with no aggregation. */ 1639 - counter->needs_uniquify = true; 1640 - return; 1641 - } 1642 - 1643 - /* 1644 - * Do other non-merged events in the evlist have the same name? If so 1645 - * uniquify is necessary. 1646 - */ 1647 - evlist__for_each_entry(counter->evlist, evsel) { 1648 - if (evsel == counter || evsel->merged_stat) 1649 - continue; 1650 - 1651 - if (evsel__name_is(counter, evsel__name(evsel))) { 1652 - counter->needs_uniquify = true; 1653 - return; 1654 - } 1655 - } 1656 - } 1657 - 1658 - static void evlist__set_needs_uniquify(struct evlist *evlist, const struct perf_stat_config *config) 1659 - { 1660 - struct evsel *counter; 1661 - 1662 - if (evlist__disable_uniquify(evlist)) { 1663 - evlist__for_each_entry(evlist, counter) 1664 - counter->uniquified_name = true; 1665 - return; 1666 - } 1667 - 1668 - evlist__for_each_entry(evlist, counter) 1669 - evsel__set_needs_uniquify(counter, config); 1670 - } 1671 - 1672 1639 void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, 1673 1640 struct target *_target, struct timespec *ts, 1674 1641 int argc, const char **argv) ··· 1590 1737 .first = true, 1591 1738 }; 1592 1739 1593 - evlist__set_needs_uniquify(evlist, config); 1740 + evlist__uniquify_evsel_names(evlist, config); 1594 1741 1595 1742 if (config->iostat_run) 1596 1743 evlist->selected = evlist__first(evlist);