From nobody Wed Dec 17 08:54:24 2025 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 785FC1DF251 for ; Thu, 27 Mar 2025 22:58:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743116307; cv=none; b=EidRY2kZnJVj9AYKQVdmp+Fp2clPk8CUnO5xVRoG4dClGAR0YqIBR1DNR5uI0avdLv9MMrxsoL1JP8sbsUbFos43Wdyn/uAme4yQUd1yIeIt1pwd5FovBRGqE1DaSQ+l/cgB6VgG16AySV3mkd5slN3vEDo1qQy8EOprpXQoBRU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743116307; c=relaxed/simple; bh=wkevOxYvJ90gHnAHDg+l7eIZl9oCC0h8whUaFRY6HrY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=PCSgqxCpBFhJp6C4BGBLWz0pUQxDlTxVDnhAbCeot9HGg/Y1Gn8hUcZ0HQb96XvyA2/QJ6GnYtyu1Ht2aXc3cGC7M4T/hbI8taC11pReVl+dMUIxmilKoi2Djy64obCaRyNjI/Wuv7kQTYhIslDM1mR5ML7aH3Jr62dz4ysEwKI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ctshao.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Fpk1vkAC; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ctshao.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Fpk1vkAC" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-3032f4eacd8so2474969a91.3 for ; Thu, 27 Mar 2025 15:58:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1743116304; x=1743721104; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=1I8CulgY0H1HqXO45SdfR3BmdRLWAEz/cuHQAct0OTY=; b=Fpk1vkACednsEU/Eebpp92wpTTq46F+sOcyGOXr2ai5AfB8o5SKuUOG4f8svU4LS6j czjKsF7l99ULoQXfel9VUAfnNJpXZE1PVs1+SVu1RI22303HlHYWoQz5oTDEzFA0BX1n Up9VMAGnK+rWL5ifa3/3fe6neDJGAb0YgmO8REZe5pxMVO++8lt54880rhLLCbNI/5pm WUg650y5GXCWcKV0EL9m4kqv2++zVPzJVcDihqaGEdNJBnSosFod+q53YFaaiN+gsqbB F+5eWzLCvLHxeV0y8P9Rkw4tnPaPg0y9Qz9l920X4r2rTB+2rxyUX/KGL7Xmrh/FlNa8 KcEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1743116304; x=1743721104; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=1I8CulgY0H1HqXO45SdfR3BmdRLWAEz/cuHQAct0OTY=; b=QolAHNUZUzsXxfm5uUFqLOwHbY3rmIfrBx2xTx4pHtnh6vKiSf0LqCGosgOi+agHTU VWXJm7RK8wK4SB53vS3k7lEDX1UKXIbUZanhDtwNIdV9uf5Vhpu2n7zx6tY5CCsR/ru3 Uzbj1Flv9pKW/l8YA8+L7qHrwBTOLLeg4nokKRmJy9ggy0Pl+JOoqywgjV6+DZvdRuEg nn/tZKR8nMp4Je6AMI6o6buuiz1CUxe1Gd82qtv71BmBwQRMnsNYQQnySPIEVVxebbkl TxytVFkfqaE9cdaTYkeFaPJcM+bfXdmMhUc6vbPd/Xak2yec5+nnClQJTlZZBHOdsHRt q4JQ== X-Gm-Message-State: AOJu0YwdqvBFier7W3ukBO9VVEaZygT11Rlijwdrd7wFUn+JCjT5OYt8 0LE4bg03piCNo+DQM4n45CCXluxFEg7WUp1fMeCrLKGKBuukcTzyT+yRnt4pwp7NwlJf9nuH6nH CWXIlkEW+b+y7n1OIpSvOLJN62r8PzSOhL7UtGLifWTB4SNRUKMcZVM9Wde+PTXhlhFvKOMIXNE eCy2wa5CHfykNtLkbn24EQhZV3FVULar/EF2Mv9yu0 X-Google-Smtp-Source: AGHT+IFNscdaz9cj03S4vDnmKdNKhIs0FjPH1QS6zuDvo3Y2H7r6fgoFrwEPl0AXQq2Kbh864huYvLJtYic= X-Received: from pjbsk8.prod.google.com ([2002:a17:90b:2dc8:b0:2ea:448a:8cd1]) (user=ctshao job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2645:b0:2ff:4bac:6fba with SMTP id 98e67ed59e1d1-303a85c1c47mr8925268a91.24.1743116304398; Thu, 27 Mar 2025 15:58:24 -0700 (PDT) Date: Thu, 27 Mar 2025 15:48:16 -0700 In-Reply-To: <20250327225651.642965-1-ctshao@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250327225651.642965-1-ctshao@google.com> X-Mailer: git-send-email 2.49.0.472.ge94155a9ec-goog Message-ID: <20250327225651.642965-2-ctshao@google.com> Subject: [PATCH v2 1/3] perf evlist: Make uniquifying counter names consistent From: Chun-Tse Shao To: linux-kernel@vger.kernel.org Cc: Ian Rogers , Chun-Tse Shao , peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, kan.liang@linux.intel.com, howardchu95@gmail.com, yeoreum.yun@arm.com, linux@treblig.org, james.clark@linaro.org, ak@linux.intel.com, weilin.wang@intel.com, asmadeus@codewreck.org, linux-perf-users@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ian Rogers 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 Tested-by: Chun-Tse Shao Tested-by: Ian Rogers --- tools/perf/builtin-record.c | 7 +- tools/perf/builtin-top.c | 7 +- tools/perf/util/evlist.c | 66 ++++++++++----- tools/perf/util/evlist.h | 3 +- tools/perf/util/evsel.c | 113 +++++++++++++++++++++++++ tools/perf/util/evsel.h | 4 + tools/perf/util/stat-display.c | 149 +-------------------------------- 7 files changed, 176 insertions(+), 173 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ba20bf7c011d..83f8f9728e12 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -26,6 +26,7 @@ #include "util/target.h" #include "util/session.h" #include "util/tool.h" +#include "util/stat.h" #include "util/symbol.h" #include "util/record.h" #include "util/cpumap.h" @@ -2483,7 +2484,11 @@ static int __cmd_record(struct record *rec, int argc= , const char **argv) pr_warning("WARNING: --timestamp-filename option is not available in pip= e mode.\n"); } =20 - evlist__uniquify_name(rec->evlist); + /* + * Use global stat_config that is zero meaning aggr_mode is AGGR_NONE + * and hybrid_merge is false. + */ + evlist__uniquify_evsel_names(rec->evlist, &stat_config); =20 evlist__config(rec->evlist, opts, &callchain_param); =20 diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1061f4eebc3f..b7c8ecafa2f2 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -35,6 +35,7 @@ #include "util/mmap.h" #include "util/session.h" #include "util/thread.h" +#include "util/stat.h" #include "util/symbol.h" #include "util/synthetic-events.h" #include "util/top.h" @@ -1309,7 +1310,11 @@ static int __cmd_top(struct perf_top *top) } } =20 - evlist__uniquify_name(top->evlist); + /* + * Use global stat_config that is zero meaning aggr_mode is AGGR_NONE + * and hybrid_merge is false. + */ + evlist__uniquify_evsel_names(top->evlist, &stat_config); ret =3D perf_top__start_counters(top); if (ret) return ret; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c1a04141aed0..a28ab52e7d85 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -2552,34 +2552,56 @@ void evlist__warn_user_requested_cpus(struct evlist= *evlist, const char *cpu_lis perf_cpu_map__put(user_requested_cpus); } =20 -void evlist__uniquify_name(struct evlist *evlist) +/* Should uniquify be disabled for the evlist? */ +static bool evlist__disable_uniquify(const struct evlist *evlist) { - char *new_name, empty_attributes[2] =3D ":", *attributes; - struct evsel *pos; + struct evsel *counter; + struct perf_pmu *last_pmu =3D NULL; + bool first =3D true; =20 - if (perf_pmus__num_core_pmus() =3D=3D 1) - return; + evlist__for_each_entry(evlist, counter) { + /* If PMUs vary then uniquify can be useful. */ + if (!first && counter->pmu !=3D last_pmu) + return false; + first =3D false; + if (counter->pmu) { + /* Allow uniquify for uncore PMUs. */ + if (!counter->pmu->is_core) + return false; + /* Keep hybrid event names uniquified for clarity. */ + if (perf_pmus__num_core_pmus() > 1) + return false; + } + last_pmu =3D counter->pmu; + } + return true; +} =20 - evlist__for_each_entry(evlist, pos) { - if (!evsel__is_hybrid(pos)) - continue; +static bool evlist__set_needs_uniquify(struct evlist *evlist, const struct= perf_stat_config *config) +{ + struct evsel *counter; + bool needs_uniquify =3D false; =20 - if (strchr(pos->name, '/')) - continue; + if (evlist__disable_uniquify(evlist)) { + evlist__for_each_entry(evlist, counter) + counter->uniquified_name =3D true; + return false; + } + + evlist__for_each_entry(evlist, counter) { + if (evsel__set_needs_uniquify(counter, config)) + needs_uniquify =3D true; + } + return needs_uniquify; +} =20 - attributes =3D strchr(pos->name, ':'); - if (attributes) - *attributes =3D '\0'; - else - attributes =3D empty_attributes; +void evlist__uniquify_evsel_names(struct evlist *evlist, const struct perf= _stat_config *config) +{ + if (evlist__set_needs_uniquify(evlist, config)) { + struct evsel *pos; =20 - if (asprintf(&new_name, "%s/%s/%s", pos->pmu ? pos->pmu->name : "", - pos->name, attributes + 1)) { - free(pos->name); - pos->name =3D new_name; - } else { - *attributes =3D ':'; - } + evlist__for_each_entry(evlist, pos) + evsel__uniquify_counter(pos); } } =20 diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index edcbf1c10e92..7cfdaf543214 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -19,6 +19,7 @@ struct pollfd; struct thread_map; struct perf_cpu_map; +struct perf_stat_config; struct record_opts; struct target; =20 @@ -433,7 +434,7 @@ struct evsel *evlist__find_evsel(struct evlist *evlist,= int idx); int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf); void evlist__check_mem_load_aux(struct evlist *evlist); void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *c= pu_list); -void evlist__uniquify_name(struct evlist *evlist); +void evlist__uniquify_evsel_names(struct evlist *evlist, const struct perf= _stat_config *config); bool evlist__has_bpf_output(struct evlist *evlist); bool evlist__needs_bpf_sb_event(struct evlist *evlist); =20 diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1974395492d7..f00cfff119aa 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3939,3 +3939,116 @@ void evsel__remove_from_group(struct evsel *evsel, = struct evsel *leader) leader->core.nr_members--; } } + +bool evsel__set_needs_uniquify(struct evsel *counter, const struct perf_st= at_config *config) +{ + struct evsel *evsel; + + if (counter->needs_uniquify) { + /* Already set. */ + return true; + } + + if (counter->merged_stat) { + /* Counter won't be shown. */ + return false; + } + + if (counter->use_config_name || counter->is_libpfm_event) { + /* Original name will be used. */ + return false; + } + + if (!config->hybrid_merge && evsel__is_hybrid(counter)) { + /* Unique hybrid counters necessary. */ + counter->needs_uniquify =3D true; + return true; + } + + if (counter->core.attr.type < PERF_TYPE_MAX && counter->core.attr.type != =3D PERF_TYPE_RAW) { + /* Legacy event, don't uniquify. */ + return false; + } + + if (counter->pmu && counter->pmu->is_core && + counter->alternate_hw_config !=3D PERF_COUNT_HW_MAX) { + /* A sysfs or json event replacing a legacy event, don't uniquify. */ + return false; + } + + if (config->aggr_mode =3D=3D AGGR_NONE) { + /* Always unique with no aggregation. */ + counter->needs_uniquify =3D true; + return true; + } + + /* + * Do other non-merged events in the evlist have the same name? If so + * uniquify is necessary. + */ + evlist__for_each_entry(counter->evlist, evsel) { + if (evsel =3D=3D counter || evsel->merged_stat || evsel->pmu =3D=3D coun= ter->pmu) + continue; + + if (evsel__name_is(counter, evsel__name(evsel))) { + counter->needs_uniquify =3D true; + return true; + } + } + return false; +} + +void evsel__uniquify_counter(struct evsel *counter) +{ + const char *name, *pmu_name; + char *new_name, *config; + int ret; + + /* No uniquification necessary. */ + if (!counter->needs_uniquify) + return; + + /* The evsel was already uniquified. */ + if (counter->uniquified_name) + return; + + /* Avoid checking to uniquify twice. */ + counter->uniquified_name =3D true; + + name =3D evsel__name(counter); + pmu_name =3D counter->pmu->name; + /* Already prefixed by the PMU name. */ + if (!strncmp(name, pmu_name, strlen(pmu_name))) + return; + + config =3D strchr(name, '/'); + if (config) { + int len =3D config - name; + + if (config[1] =3D=3D '/') { + /* case: event// */ + ret =3D asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config += 2); + } else { + /* case: event/.../ */ + ret =3D asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config += 1); + } + } else { + config =3D strchr(name, ':'); + if (config) { + /* case: event:.. */ + int len =3D config - name; + + ret =3D asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config += 1); + } else { + /* case: event */ + ret =3D asprintf(&new_name, "%s/%s/", pmu_name, name); + } + } + if (ret > 0) { + free(counter->name); + counter->name =3D new_name; + } else { + /* ENOMEM from asprintf. */ + counter->uniquified_name =3D false; + } +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index aae431d63d64..76ccb7c7e8c2 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -16,6 +16,7 @@ struct bpf_object; struct cgroup; struct perf_counts; +struct perf_stat_config; struct perf_stat_evsel; union perf_event; struct bpf_counter_ops; @@ -542,6 +543,9 @@ void evsel__remove_from_group(struct evsel *evsel, stru= ct evsel *leader); =20 bool arch_evsel__must_be_in_group(const struct evsel *evsel); =20 +bool evsel__set_needs_uniquify(struct evsel *counter, const struct perf_st= at_config *config); +void evsel__uniquify_counter(struct evsel *counter); + /* * Macro to swap the bit-field postition and size. * Used when, diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index e852ac0d9847..d427e0ca98a1 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -929,61 +929,6 @@ static void printout(struct perf_stat_config *config, = struct outstate *os, } } =20 -static void evsel__uniquify_counter(struct evsel *counter) -{ - const char *name, *pmu_name; - char *new_name, *config; - int ret; - - /* No uniquification necessary. */ - if (!counter->needs_uniquify) - return; - - /* The evsel was already uniquified. */ - if (counter->uniquified_name) - return; - - /* Avoid checking to uniquify twice. */ - counter->uniquified_name =3D true; - - name =3D evsel__name(counter); - pmu_name =3D counter->pmu->name; - /* Already prefixed by the PMU name. */ - if (!strncmp(name, pmu_name, strlen(pmu_name))) - return; - - config =3D strchr(name, '/'); - if (config) { - int len =3D config - name; - - if (config[1] =3D=3D '/') { - /* case: event// */ - ret =3D asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config += 2); - } else { - /* case: event/.../ */ - ret =3D asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config += 1); - } - } else { - config =3D strchr(name, ':'); - if (config) { - /* case: event:.. */ - int len =3D config - name; - - ret =3D asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config += 1); - } else { - /* case: event */ - ret =3D asprintf(&new_name, "%s/%s/", pmu_name, name); - } - } - if (ret > 0) { - free(counter->name); - counter->name =3D new_name; - } else { - /* ENOMEM from asprintf. */ - counter->uniquified_name =3D false; - } -} - /** * should_skip_zero_count() - Check if the event should print 0 values. * @config: The perf stat configuration (including aggregation mode). @@ -1069,8 +1014,6 @@ static void print_counter_aggrdata(struct perf_stat_c= onfig *config, if (counter->merged_stat) return; =20 - evsel__uniquify_counter(counter); - val =3D aggr->counts.val; ena =3D aggr->counts.ena; run =3D aggr->counts.run; @@ -1650,96 +1593,6 @@ static void print_cgroup_counter(struct perf_stat_co= nfig *config, struct evlist print_metric_end(config, os); } =20 -/* Should uniquify be disabled for the evlist? */ -static bool evlist__disable_uniquify(const struct evlist *evlist) -{ - struct evsel *counter; - struct perf_pmu *last_pmu =3D NULL; - bool first =3D true; - - evlist__for_each_entry(evlist, counter) { - /* If PMUs vary then uniquify can be useful. */ - if (!first && counter->pmu !=3D last_pmu) - return false; - first =3D false; - if (counter->pmu) { - /* Allow uniquify for uncore PMUs. */ - if (!counter->pmu->is_core) - return false; - /* Keep hybrid event names uniquified for clarity. */ - if (perf_pmus__num_core_pmus() > 1) - return false; - } - } - return true; -} - -static void evsel__set_needs_uniquify(struct evsel *counter, const struct = perf_stat_config *config) -{ - struct evsel *evsel; - - if (counter->merged_stat) { - /* Counter won't be shown. */ - return; - } - - if (counter->use_config_name || counter->is_libpfm_event) { - /* Original name will be used. */ - return; - } - - if (!config->hybrid_merge && evsel__is_hybrid(counter)) { - /* Unique hybrid counters necessary. */ - counter->needs_uniquify =3D true; - return; - } - - if (counter->core.attr.type < PERF_TYPE_MAX && counter->core.attr.type != =3D PERF_TYPE_RAW) { - /* Legacy event, don't uniquify. */ - return; - } - - if (counter->pmu && counter->pmu->is_core && - counter->alternate_hw_config !=3D PERF_COUNT_HW_MAX) { - /* A sysfs or json event replacing a legacy event, don't uniquify. */ - return; - } - - if (config->aggr_mode =3D=3D AGGR_NONE) { - /* Always unique with no aggregation. */ - counter->needs_uniquify =3D true; - return; - } - - /* - * Do other non-merged events in the evlist have the same name? If so - * uniquify is necessary. - */ - evlist__for_each_entry(counter->evlist, evsel) { - if (evsel =3D=3D counter || evsel->merged_stat) - continue; - - if (evsel__name_is(counter, evsel__name(evsel))) { - counter->needs_uniquify =3D true; - return; - } - } -} - -static void evlist__set_needs_uniquify(struct evlist *evlist, const struct= perf_stat_config *config) -{ - struct evsel *counter; - - if (evlist__disable_uniquify(evlist)) { - evlist__for_each_entry(evlist, counter) - counter->uniquified_name =3D true; - return; - } - - evlist__for_each_entry(evlist, counter) - evsel__set_needs_uniquify(counter, config); -} - void evlist__print_counters(struct evlist *evlist, struct perf_stat_config= *config, struct target *_target, struct timespec *ts, int argc, const char **argv) @@ -1751,7 +1604,7 @@ void evlist__print_counters(struct evlist *evlist, st= ruct perf_stat_config *conf .first =3D true, }; =20 - evlist__set_needs_uniquify(evlist, config); + evlist__uniquify_evsel_names(evlist, config); =20 if (config->iostat_run) evlist->selected =3D evlist__first(evlist); --=20 2.49.0.472.ge94155a9ec-goog From nobody Wed Dec 17 08:54:24 2025 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2496B1B6D08 for ; Thu, 27 Mar 2025 22:59:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743116386; cv=none; b=a6iu4n/e2r6J/68q6HYa2K+oWJqEXOoTWOhoNAHdqgdq+JRUv9X1d9kCU9kfexTg93NbFsIYcFg5NpSTpEyFsUb6dd+ufi6QTaeo8C9f75EHZfYSIHbi8F7I7dRGoQ2TbbxkXEcDZic3yfDb6Cipgq+w79hDO9Q8zkhXu3mO5lo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743116386; c=relaxed/simple; bh=rmW4xF3TxYslzByqTsfIwMF9FY3WunDP4/Pq4GC/Mw8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=GTjms4oCti/Y4MAEK05pcNsbv4+AgeI3+PaXDJfmEDAIiArdWecimppqwn742oCrwNLiemdOytA/pRmmCCvUjnHvMrq8UrhsGXEK9QpohiTylJxfIIrBTbUzgK6bIGFXQ0uFiEsdoTnQilzOYRmJ81GI1p92u8d032SKlEKS86s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ctshao.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qpW4iMlk; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ctshao.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qpW4iMlk" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-2ff8c5d185aso4145217a91.1 for ; Thu, 27 Mar 2025 15:59:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1743116383; x=1743721183; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=0/euh3tTrQt0cm2ZuVr18wpmd9WYjQe4EReQ858wpno=; b=qpW4iMlkpCAd8KyrKsDUzTzFEQmACCFiYJMYpRaGaMMdCx0RoO9m9zlzQH3gEty58M H74MQmricNGc+8/tSdgmQsX6mdBb5SBc4SUb3GNSAFhQshff5eYlBNXNsXcQXNDju9b1 jhs0jl9mFEuZoWIQNRFzp6bctsy0Mad3fH3UcjYEVxwRF4C5DPb5EEm6T9AAyCsIjTOs nq78VxZAEIvdVhydx6nltrmRO8llAWkfBWP8qWFYYSlGDFz+31ZtwWvMXEVPIqvnP79B mus+D5oOztrNIkYcHiD2OCBwVRoVKxBu2SwV2vGfWqcqfqKe+ggytW1po5liFjMfD43Y Nd4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1743116383; x=1743721183; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0/euh3tTrQt0cm2ZuVr18wpmd9WYjQe4EReQ858wpno=; b=NVREOZMFdRMHAtGZeymKJi4S8jnXhEcRxA0+wphuU5uE/AFGa5hfQ3VZnw4/EotQaX oozS7jyqEi/6wUzrdVjmB90g0GRR+dgGYReqM6FU8kr9tY20GBSxZBP+/ZWdFmT40qA2 tO4iM3PGCqhVC6wLoHeMiT1w7xqC0/2gL6rhh2KNoRseEVmCnVbim6grEQgJm1aBWxFf IiS8nvjv9p8IEpKspDhE3tHAu94TFrpxu9ZJZ6anJYrQ0X7FNrF5IehFPihLx31GYe7z 29MuTBeyYsWLwuG28t/ut3z/mczBvm/9lbDNkQvWFB3at5AmcoXr8U0vjAtKegGswAtB jmBQ== X-Gm-Message-State: AOJu0YzPychxGHM6lyiPIdJmyxRZx3/3zgV1RD/7YlNZFDjKZA1J/5Xb rG4sGedoaMgf0jPn8C9wTeQMdf+PdQmI4dLRGyVKcpxpg4aT77nFY1sOQO50J4hpEewIKwCtdDy vBkIZEkFuGikPK73yhQZS1Nbz/yuhvA2MVJAO4pVg2QM7aMhK1/3AveJ3pzPhbXO4NfnYuHV3V6 DwU7AAwRtVd4m2ZUWmLUgLfZ5fsrOmR6+Ll8DNrWVU X-Google-Smtp-Source: AGHT+IFcHJbzXzRJOMz9u1R+/BQOIeGBp4Au2HbdqNYsBssIiBpTnrkwZvY9oOMXCN7b6UKlBeJN8T9M+RQ= X-Received: from pjm14.prod.google.com ([2002:a17:90b:2fce:b0:2f5:63a:4513]) (user=ctshao job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:5824:b0:301:1bce:c25a with SMTP id 98e67ed59e1d1-303a7f70685mr7188872a91.20.1743116383392; Thu, 27 Mar 2025 15:59:43 -0700 (PDT) Date: Thu, 27 Mar 2025 15:48:17 -0700 In-Reply-To: <20250327225651.642965-1-ctshao@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250327225651.642965-1-ctshao@google.com> X-Mailer: git-send-email 2.49.0.472.ge94155a9ec-goog Message-ID: <20250327225651.642965-3-ctshao@google.com> Subject: [PATCH v2 2/3] perf parse-events: Use wildcard processing to set an event to merge into From: Chun-Tse Shao To: linux-kernel@vger.kernel.org Cc: Ian Rogers , Chun-Tse Shao , peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, kan.liang@linux.intel.com, ak@linux.intel.com, howardchu95@gmail.com, linux@treblig.org, yeoreum.yun@arm.com, james.clark@linaro.org, weilin.wang@intel.com, asmadeus@codewreck.org, linux-perf-users@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ian Rogers The merge stat code fails for uncore events if they are repeated twice, for example `perf stat -e clockticks,clockticks -I 1000` as the counts of the second set of uncore events will be merged into the first counter. Reimplement the logic to have a first_wildcard_match so that merged later events correctly merge into the first wildcard event that they will be aggregated into. Signed-off-by: Ian Rogers Tested-by: Chun-Tse Shao Tested-by: Ian Rogers --- tools/perf/util/evsel.c | 18 ++++--- tools/perf/util/evsel.h | 7 ++- tools/perf/util/parse-events.c | 86 ++++++++++++++++++++++++---------- tools/perf/util/stat-display.c | 11 ++++- tools/perf/util/stat.c | 40 ++-------------- 5 files changed, 90 insertions(+), 72 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f00cfff119aa..e360071c870d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -552,11 +552,11 @@ struct evsel *evsel__clone(struct evsel *dest, struct= evsel *orig) =20 evsel->exclude_GH =3D orig->exclude_GH; evsel->sample_read =3D orig->sample_read; - evsel->auto_merge_stats =3D orig->auto_merge_stats; evsel->collect_stat =3D orig->collect_stat; evsel->weak_group =3D orig->weak_group; evsel->use_config_name =3D orig->use_config_name; evsel->pmu =3D orig->pmu; + evsel->first_wildcard_match =3D orig->first_wildcard_match; =20 if (evsel__copy_config_terms(evsel, orig) < 0) goto out_err; @@ -3949,11 +3949,6 @@ bool evsel__set_needs_uniquify(struct evsel *counter= , const struct perf_stat_con return true; } =20 - if (counter->merged_stat) { - /* Counter won't be shown. */ - return false; - } - if (counter->use_config_name || counter->is_libpfm_event) { /* Original name will be used. */ return false; @@ -3982,12 +3977,21 @@ bool evsel__set_needs_uniquify(struct evsel *counte= r, const struct perf_stat_con return true; } =20 + if (counter->first_wildcard_match !=3D NULL) { + /* + * If stats are merged then only the first_wildcard_match is + * displayed, there is no need to uniquify this evsel as the + * name won't be shown. + */ + return false; + } + /* * Do other non-merged events in the evlist have the same name? If so * uniquify is necessary. */ evlist__for_each_entry(counter->evlist, evsel) { - if (evsel =3D=3D counter || evsel->merged_stat || evsel->pmu =3D=3D coun= ter->pmu) + if (evsel =3D=3D counter || evsel->first_wildcard_match || evsel->pmu = =3D=3D counter->pmu) continue; =20 if (evsel__name_is(counter, evsel__name(evsel))) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 76ccb7c7e8c2..2cc046894e30 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -70,6 +70,11 @@ struct evsel { const char *unit; struct cgroup *cgrp; const char *metric_id; + /* + * This point to the first evsel with the same name, intended to store t= he + * aggregated counts in aggregation mode. + */ + struct evsel *first_wildcard_match; /* parse modifier helper */ int exclude_GH; int sample_read; @@ -78,7 +83,6 @@ struct evsel { bool percore; bool precise_max; bool is_libpfm_event; - bool auto_merge_stats; bool collect_stat; bool weak_group; bool bpf_counter; @@ -115,7 +119,6 @@ struct evsel { bool ignore_missing_thread; bool forced_leader; bool cmdline_group_boundary; - bool merged_stat; bool reset_group; bool errored; bool needs_auxtrace_mmap; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5152fd5a6ead..233836c37e41 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -228,12 +228,32 @@ __add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, bool init_attr, const char *name, const char *metric_id, struct perf_pmu *pmu, - struct list_head *config_terms, bool auto_merge_stats, + struct list_head *config_terms, struct evsel *first_wildcard_match, struct perf_cpu_map *cpu_list, u64 alternate_hw_config) { struct evsel *evsel; struct perf_cpu_map *cpus =3D perf_cpu_map__is_empty(cpu_list) && pmu ? p= mu->cpus : cpu_list; =20 + /* + * Ensure the first_wildcard_match's PMU matches that of the new event + * being added. Otherwise try to match with another event further down + * the evlist. + */ + if (first_wildcard_match) { + struct evsel *pos =3D list_prev_entry(first_wildcard_match, core.node); + + first_wildcard_match =3D NULL; + list_for_each_entry_continue(pos, list, core.node) { + if (perf_pmu__name_no_suffix_match(pos->pmu, pmu->name)) { + first_wildcard_match =3D pos; + break; + } + if (pos->pmu->is_core && (!pmu || pmu->is_core)) { + first_wildcard_match =3D pos; + break; + } + } + } cpus =3D perf_cpu_map__get(cpus); if (pmu) perf_pmu__warn_invalid_formats(pmu); @@ -262,9 +282,9 @@ __add_event(struct list_head *list, int *idx, evsel->core.own_cpus =3D perf_cpu_map__get(cpus); evsel->core.requires_cpu =3D pmu ? pmu->is_uncore : false; evsel->core.is_pmu_core =3D pmu ? pmu->is_core : false; - evsel->auto_merge_stats =3D auto_merge_stats; evsel->pmu =3D pmu; evsel->alternate_hw_config =3D alternate_hw_config; + evsel->first_wildcard_match =3D first_wildcard_match; =20 if (name) evsel->name =3D strdup(name); @@ -287,7 +307,7 @@ struct evsel *parse_events__add_event(int idx, struct p= erf_event_attr *attr, { return __add_event(/*list=3D*/NULL, &idx, attr, /*init_attr=3D*/false, na= me, metric_id, pmu, /*config_terms=3D*/NULL, - /*auto_merge_stats=3D*/false, /*cpu_list=3D*/NULL, + /*first_wildcard_match=3D*/NULL, /*cpu_list=3D*/NULL, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX); } =20 @@ -298,7 +318,7 @@ static int add_event(struct list_head *list, int *idx, { return __add_event(list, idx, attr, /*init_attr*/true, name, metric_id, /*pmu=3D*/NULL, config_terms, - /*auto_merge_stats=3D*/false, /*cpu_list=3D*/NULL, + /*first_wildcard_match=3D*/NULL, /*cpu_list=3D*/NULL, alternate_hw_config) ? 0 : -ENOMEM; } =20 @@ -423,7 +443,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, u64 alternate_hw_config); + struct evsel *first_wildcard_match, u64 alternate_hw_config); =20 int parse_events_add_cache(struct list_head *list, int *idx, const char *n= ame, struct parse_events_state *parse_state, @@ -433,6 +453,7 @@ int parse_events_add_cache(struct list_head *list, int = *idx, const char *name, bool found_supported =3D false; const char *config_name =3D get_config_name(parsed_terms); const char *metric_id =3D get_config_metric_id(parsed_terms); + struct evsel *first_wildcard_match =3D NULL; =20 while ((pmu =3D perf_pmus__scan(pmu)) !=3D NULL) { LIST_HEAD(config_terms); @@ -449,10 +470,14 @@ int parse_events_add_cache(struct list_head *list, in= t *idx, const char *name, */ ret =3D parse_events_add_pmu(parse_state, list, pmu, parsed_terms, - perf_pmu__auto_merge_stats(pmu), + first_wildcard_match, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX); if (ret) return ret; + + if (first_wildcard_match =3D=3D NULL) + first_wildcard_match =3D + container_of(list->prev, struct evsel, core.node); continue; } =20 @@ -480,11 +505,13 @@ int parse_events_add_cache(struct list_head *list, in= t *idx, const char *name, } =20 if (__add_event(list, idx, &attr, /*init_attr*/true, config_name ?: name, - metric_id, pmu, &config_terms, /*auto_merge_stats=3D*/false, + metric_id, pmu, &config_terms, first_wildcard_match, /*cpu_list=3D*/NULL, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX) =3D=3D NULL) return -ENOMEM; =20 + if (first_wildcard_match =3D=3D NULL) + first_wildcard_match =3D container_of(list->prev, struct evsel, core.no= de); free_config_terms(&config_terms); } return found_supported ? 0 : -EINVAL; @@ -1335,7 +1362,8 @@ int parse_events_add_tracepoint(struct parse_events_s= tate *parse_state, static int __parse_events_add_numeric(struct parse_events_state *parse_sta= te, struct list_head *list, struct perf_pmu *pmu, u32 type, u32 extended_type, - u64 config, const struct parse_events_terms *head_config) + u64 config, const struct parse_events_terms *head_config, + struct evsel *first_wildcard_match) { struct perf_event_attr attr; LIST_HEAD(config_terms); @@ -1362,7 +1390,7 @@ static int __parse_events_add_numeric(struct parse_ev= ents_state *parse_state, name =3D get_config_name(head_config); metric_id =3D get_config_metric_id(head_config); ret =3D __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, na= me, - metric_id, pmu, &config_terms, /*auto_merge_stats=3D*/false, + metric_id, pmu, &config_terms, first_wildcard_match, /*cpu_list=3D*/NULL, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX ) =3D=3D NULL ? -ENOMEM : 0; free_config_terms(&config_terms); @@ -1380,6 +1408,8 @@ int parse_events_add_numeric(struct parse_events_stat= e *parse_state, =20 /* Wildcards on numeric values are only supported by core PMUs. */ if (wildcard && perf_pmus__supports_extended_type()) { + struct evsel *first_wildcard_match =3D NULL; + while ((pmu =3D perf_pmus__scan_core(pmu)) !=3D NULL) { int ret; =20 @@ -1389,15 +1419,21 @@ int parse_events_add_numeric(struct parse_events_st= ate *parse_state, =20 ret =3D __parse_events_add_numeric(parse_state, list, pmu, type, pmu->type, - config, head_config); + config, head_config, + first_wildcard_match); if (ret) return ret; + + if (first_wildcard_match =3D=3D NULL) + first_wildcard_match =3D + container_of(list->prev, struct evsel, core.node); } if (found_supported) return 0; } return __parse_events_add_numeric(parse_state, list, perf_pmus__find_by_t= ype(type), - type, /*extended_type=3D*/0, config, head_config); + type, /*extended_type=3D*/0, config, head_config, + /*first_wildcard_match=3D*/NULL); } =20 static bool config_term_percore(struct list_head *config_terms) @@ -1415,7 +1451,7 @@ static bool config_term_percore(struct list_head *con= fig_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, u64 alternate_hw_config) + struct evsel *first_wildcard_match, u64 alternate_hw_config) { struct perf_event_attr attr; struct perf_pmu_info info; @@ -1451,7 +1487,7 @@ static int parse_events_add_pmu(struct parse_events_s= tate *parse_state, evsel =3D __add_event(list, &parse_state->idx, &attr, /*init_attr=3D*/true, /*name=3D*/NULL, /*metric_id=3D*/NULL, pmu, - /*config_terms=3D*/NULL, auto_merge_stats, + /*config_terms=3D*/NULL, first_wildcard_match, /*cpu_list=3D*/NULL, alternate_hw_config); return evsel ? 0 : -ENOMEM; } @@ -1521,7 +1557,7 @@ static int parse_events_add_pmu(struct parse_events_s= tate *parse_state, evsel =3D __add_event(list, &parse_state->idx, &attr, /*init_attr=3D*/tru= e, get_config_name(&parsed_terms), get_config_metric_id(&parsed_terms), pmu, - &config_terms, auto_merge_stats, /*cpu_list=3D*/NULL, + &config_terms, first_wildcard_match, /*cpu_list=3D*/NULL, alternate_hw_config); if (!evsel) { parse_events_terms__exit(&parsed_terms); @@ -1554,6 +1590,7 @@ int parse_events_multi_pmu_add(struct parse_events_st= ate *parse_state, int ok =3D 0; const char *config; struct parse_events_terms parsed_terms; + struct evsel *first_wildcard_match =3D NULL; =20 *listp =3D NULL; =20 @@ -1586,17 +1623,14 @@ int parse_events_multi_pmu_add(struct parse_events_= state *parse_state, INIT_LIST_HEAD(list); =20 while ((pmu =3D perf_pmus__scan(pmu)) !=3D NULL) { - bool auto_merge_stats; - if (parse_events__filter_pmu(parse_state, pmu)) continue; =20 if (!perf_pmu__have_event(pmu, event_name)) continue; =20 - auto_merge_stats =3D perf_pmu__auto_merge_stats(pmu); if (!parse_events_add_pmu(parse_state, list, pmu, - &parsed_terms, auto_merge_stats, hw_config)) { + &parsed_terms, first_wildcard_match, hw_config)) { struct strbuf sb; =20 strbuf_init(&sb, /*hint=3D*/ 0); @@ -1605,11 +1639,13 @@ int parse_events_multi_pmu_add(struct parse_events_= state *parse_state, strbuf_release(&sb); ok++; } + if (first_wildcard_match =3D=3D NULL) + first_wildcard_match =3D container_of(list->prev, struct evsel, core.no= de); } =20 if (parse_state->fake_pmu) { if (!parse_events_add_pmu(parse_state, list, perf_pmus__fake_pmu(), &par= sed_terms, - /*auto_merge_stats=3D*/true, hw_config)) { + first_wildcard_match, hw_config)) { struct strbuf sb; =20 strbuf_init(&sb, /*hint=3D*/ 0); @@ -1640,6 +1676,7 @@ int parse_events_multi_pmu_add_or_add_pmu(struct pars= e_events_state *parse_state struct perf_pmu *pmu; int ok =3D 0; char *help; + struct evsel *first_wildcard_match =3D NULL; =20 *listp =3D malloc(sizeof(**listp)); if (!*listp) @@ -1650,14 +1687,14 @@ int parse_events_multi_pmu_add_or_add_pmu(struct pa= rse_events_state *parse_state /* Attempt to add to list assuming event_or_pmu is a PMU name. */ pmu =3D perf_pmus__find(event_or_pmu); if (pmu && !parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_t= erms, - /*auto_merge_stats=3D*/false, + first_wildcard_match, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX)) return 0; =20 if (parse_state->fake_pmu) { if (!parse_events_add_pmu(parse_state, *listp, perf_pmus__fake_pmu(), const_parsed_terms, - /*auto_merge_stats=3D*/false, + first_wildcard_match, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX)) return 0; } @@ -1667,15 +1704,16 @@ int parse_events_multi_pmu_add_or_add_pmu(struct pa= rse_events_state *parse_state while ((pmu =3D perf_pmus__scan(pmu)) !=3D NULL) { if (!parse_events__filter_pmu(parse_state, pmu) && perf_pmu__wildcard_match(pmu, event_or_pmu)) { - bool auto_merge_stats =3D perf_pmu__auto_merge_stats(pmu); - if (!parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms, - auto_merge_stats, + first_wildcard_match, /*alternate_hw_config=3D*/PERF_COUNT_HW_MAX)) { ok++; parse_state->wild_card_pmus =3D true; } + if (first_wildcard_match =3D=3D NULL) + first_wildcard_match =3D + container_of((*listp)->prev, struct evsel, core.node); } } if (ok) diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index d427e0ca98a1..91386429115d 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -1011,8 +1011,15 @@ static void print_counter_aggrdata(struct perf_stat_= config *config, os->evsel =3D counter; =20 /* Skip already merged uncore/hybrid events */ - if (counter->merged_stat) - return; + if (config->aggr_mode !=3D AGGR_NONE) { + if (evsel__is_hybrid(counter)) { + if (config->hybrid_merge && counter->first_wildcard_match !=3D NULL) + return; + } else { + if (counter->first_wildcard_match !=3D NULL) + return; + } + } =20 val =3D aggr->counts.val; ena =3D aggr->counts.ena; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 1f7abd8754c7..355a7d5c8ab8 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -535,35 +535,6 @@ static int evsel__merge_aggr_counters(struct evsel *ev= sel, struct evsel *alias) =20 return 0; } -/* - * Events should have the same name, scale, unit, cgroup but on different = core - * PMUs or on different but matching uncore PMUs. - */ -static bool evsel__is_alias(struct evsel *evsel_a, struct evsel *evsel_b) -{ - if (strcmp(evsel__name(evsel_a), evsel__name(evsel_b))) - return false; - - if (evsel_a->scale !=3D evsel_b->scale) - return false; - - if (evsel_a->cgrp !=3D evsel_b->cgrp) - return false; - - if (strcmp(evsel_a->unit, evsel_b->unit)) - return false; - - if (evsel__is_clock(evsel_a) !=3D evsel__is_clock(evsel_b)) - return false; - - if (evsel_a->pmu =3D=3D evsel_b->pmu || evsel_a->pmu =3D=3D NULL || evsel= _b->pmu =3D=3D NULL) - return false; - - if (evsel_a->pmu->is_core) - return evsel_b->pmu->is_core; - - return perf_pmu__name_no_suffix_match(evsel_a->pmu, evsel_b->pmu->name); -} =20 static void evsel__merge_aliases(struct evsel *evsel) { @@ -572,10 +543,9 @@ static void evsel__merge_aliases(struct evsel *evsel) =20 alias =3D list_prepare_entry(evsel, &(evlist->core.entries), core.node); list_for_each_entry_continue(alias, &evlist->core.entries, core.node) { - /* Merge the same events on different PMUs. */ - if (evsel__is_alias(evsel, alias)) { + if (alias->first_wildcard_match =3D=3D evsel) { + /* Merge the same events on different PMUs. */ evsel__merge_aggr_counters(evsel, alias); - alias->merged_stat =3D true; } } } @@ -588,11 +558,7 @@ static bool evsel__should_merge_hybrid(const struct ev= sel *evsel, =20 static void evsel__merge_stats(struct evsel *evsel, struct perf_stat_confi= g *config) { - /* this evsel is already merged */ - if (evsel->merged_stat) - return; - - if (evsel->auto_merge_stats || evsel__should_merge_hybrid(evsel, config)) + if (!evsel->pmu || !evsel->pmu->is_core || evsel__should_merge_hybrid(evs= el, config)) evsel__merge_aliases(evsel); } =20 --=20 2.49.0.472.ge94155a9ec-goog From nobody Wed Dec 17 08:54:24 2025 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C9722BB15 for ; Thu, 27 Mar 2025 23:01:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743116463; cv=none; b=jy8lrMvQSplVcp6Hgz/fghEFeJJT9vn4a9kyEnQof5Ql3TGGZ5Hca62QhxL7uYKQENpiax3HrDKTrFyYG0y3VZSzdHIkPTOFBtyx0Oz0Uq5wEA5AEBAJHa4qOlCAeHIcti+1YQxaOv5XcJDm7Cqa+eq0JxUFVu3gwtz4NUK5C6M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743116463; c=relaxed/simple; bh=waogitL51eHuaNon/BmGUZu6ef5FFSSmiVwnjx/u5lk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=vACYMU/Osx+E1nXAJL1aReLH+GgpvzpnWxp3HQhL35I2LU+rT8q0+BM56tQiy9HS4d5jfFruptbUVXyMOkNU2WAqaFZys+HSiSENpwhlGnZKWMTKfJVne5Iza8W0PUEryIWki48QB75bwqo0Go7l0RIF2fU2oc9ypgU//7qxGd0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ctshao.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=pEXkDcWU; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ctshao.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="pEXkDcWU" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-2ff6167e9ccso3432318a91.1 for ; Thu, 27 Mar 2025 16:01:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1743116461; x=1743721261; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=VwjNlJIwQzHOvZ74oRYXcY0TykbuQC3F2uOP0mvJUZA=; b=pEXkDcWUdKL1UMYgpgwSalp6OjL+HG/tfC/HxuzDHMwbnfiGVczvTscwLlyYLDzNgL RzDFhBCC0zmrlPZpwLm5I8XdJHrj27oJu0uhpjS6TV6INXiCB/I9hJCdtAIuoD0elZNh plgbAeQqbXiUP44HiGxx457bIDvvKQ/clxJhisGBOKHNv3x1oS5+YYp0R46Vc4W/3qWR qB+Yy7fbCvSylCHqvA+hVhaZ7jSpqQvXLUUqKkPuz0mSGAhyl6FrD3N8b6zJP9O40gXW FhLM4SObfxDEddsfV/MyQp/PY64la1enRRWpS95e7yd1odQxgBa4NGSBqs6j4CcsieHL 0/Yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1743116461; x=1743721261; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VwjNlJIwQzHOvZ74oRYXcY0TykbuQC3F2uOP0mvJUZA=; b=crwXjLuVkisdoVaw9hzfxBImZDUmqqRpQXq/AS78V4IFSK5dpUv21e93JSlwG/XMYo vonA8LLZUfpx6P75Ngo8k36InvnmUYf8VJCP71+b6FfP/2gXE5wwkTUP28Gb0NrOd3+I hsxJumJK+ZJue0TkCisQ/QrLSfNtrLV4EYCDUzPaZmHgSKrk+bgclAYJcf71D8vbi9tp chRQ2Fi1U32wYkp1OWFIwnsPHBWQMXQG615fl82CdMWC0kZ/5kTcoa6+uJU3uAJ4dTla jQSIetgzettoHGMvLM8+Qhd1vsuagtkOQF0GnTy6X6CTWPNrbGM5QXM4bhLOzmzh9GYQ 55VQ== X-Gm-Message-State: AOJu0Yy+qoGbhYM9GhBcSyZqTF2RUFMZmntM14v7U/BpeKiuqHm4qogt iVB5A/AcuoyTMVAbhsZ4NUEJgsbQ7AyiNS/eFZYmVrzyHOFwec06MDhJnO3mSFBBtTIVoiELUdh zyIhVKOCLyvJfF4nwuxDdN9sWPXG4i9i5unxKsK4oioxtcsgsfZKos4X/zzVPopNCWsVSTDRhNs dkfzHgC2leDOH5u3teboRNJLbrBMyvdz61NREq6Uso X-Google-Smtp-Source: AGHT+IEJImFJpf2gC6jGlLVpvY94WlXVA/jYO/cstjWAnHq9R2xWY4MKdztDxgrVGWB7rKXNaWXsyLHhodk= X-Received: from pjur15.prod.google.com ([2002:a17:90a:d40f:b0:301:b354:8d63]) (user=ctshao job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2d43:b0:2ee:fa0c:cebc with SMTP id 98e67ed59e1d1-303a8159f06mr7273786a91.20.1743116461541; Thu, 27 Mar 2025 16:01:01 -0700 (PDT) Date: Thu, 27 Mar 2025 15:48:18 -0700 In-Reply-To: <20250327225651.642965-1-ctshao@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250327225651.642965-1-ctshao@google.com> X-Mailer: git-send-email 2.49.0.472.ge94155a9ec-goog Message-ID: <20250327225651.642965-4-ctshao@google.com> Subject: [PATCH v2 3/3] perf test: Add stat uniquifying test From: Chun-Tse Shao To: linux-kernel@vger.kernel.org Cc: Chun-Tse Shao , peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, kan.liang@linux.intel.com, ak@linux.intel.com, howardchu95@gmail.com, linux@treblig.org, yeoreum.yun@arm.com, james.clark@linaro.org, weilin.wang@intel.com, asmadeus@codewreck.org, linux-perf-users@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The `stat+uniquify.sh` test retrieves all uniquified `clockticks` events from `perf list -v clockticks` and check if `perf stat -e clockticks -A` contains all of them. Signed-off-by: Chun-Tse Shao Tested-by: Ian Rogers --- .../tests/shell/stat+event_uniquifying.sh | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 tools/perf/tests/shell/stat+event_uniquifying.sh diff --git a/tools/perf/tests/shell/stat+event_uniquifying.sh b/tools/perf/= tests/shell/stat+event_uniquifying.sh new file mode 100755 index 000000000000..5ec35c52b7d9 --- /dev/null +++ b/tools/perf/tests/shell/stat+event_uniquifying.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# perf stat events uniquifying +# SPDX-License-Identifier: GPL-2.0 + +set -e + +stat_output=3D$(mktemp /tmp/__perf_test.stat_output.XXXXX) +perf_tool=3Dperf +err=3D0 + +test_event_uniquifying() { + # We use `clockticks` to verify the uniquify behavior. + event=3D"clockticks" + + # If the `-A` option is added, the event should be uniquified. + # + # $perf list -v clockticks + # + # List of pre-defined events (to be used in -e or -M): + # + # uncore_imc_0/clockticks/ [Kernel PMU event] + # uncore_imc_1/clockticks/ [Kernel PMU event] + # uncore_imc_2/clockticks/ [Kernel PMU event] + # uncore_imc_3/clockticks/ [Kernel PMU event] + # uncore_imc_4/clockticks/ [Kernel PMU event] + # uncore_imc_5/clockticks/ [Kernel PMU event] + # + # ... + # + # $perf stat -e clockticks -A -- true + # + # Performance counter stats for 'system wide': + # + # CPU0 3,773,018 uncore_imc_0/clockticks/ + # CPU0 3,609,025 uncore_imc_1/clockticks/ + # CPU0 0 uncore_imc_2/clockticks/ + # CPU0 3,230,009 uncore_imc_3/clockticks/ + # CPU0 3,049,897 uncore_imc_4/clockticks/ + # CPU0 0 uncore_imc_5/clockticks/ + # + # 0.002029828 seconds time elapsed + + echo "stat event uniquifying test" + uniquified_event_array=3D() + + # Check how many uniquified events. + while IFS=3D read -r line; do + uniquified_event=3D$(echo "$line" | awk '{print $1}') + uniquified_event_array+=3D("${uniquified_event}") + done < <(${perf_tool} list -v ${event} | grep "\[Kernel PMU event\]") + + perf_command=3D"${perf_tool} stat -e $event -A -o ${stat_output} -- true" + $perf_command + + # Check the output contains all uniquified events. + for uniquified_event in "${uniquified_event_array[@]}"; do + if ! cat "${stat_output}" | grep -q "${uniquified_event}"; then + echo "Event is not uniquified [Failed]" + echo "${perf_command}" + cat "${stat_output}" + err=3D1 + break + fi + done +} + +test_event_uniquifying +rm -f "${stat_output}" +exit $err --=20 2.49.0.472.ge94155a9ec-goog