From nobody Wed Dec 17 09:17:00 2025 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (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 1620518027 for ; Wed, 26 Mar 2025 23:52:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743033164; cv=none; b=LZAhc8oe1jZitlVlywbiaYPxNdf1kJwcMpZDj8tXEQTNlCz3deHRyM6yw3L7cVpMN4dzD+TM0M1iO4QkGjUnRNjTWoDTiE6Wl/lUSjceJWHTjIYpwOhvyI/wKJMKCSFzwiIpuLUeBCfjXgYRXRAWPF/i6jsLFUCNzJotQTe1Egc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743033164; c=relaxed/simple; bh=xVp2QMfLt7PK7AmAqU2aS2o/Vv+VexUF9/S5FnYX/LM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Ss7Q+DQZcdk5/AMOw1CrvqbQCcdp2w6HVe5hRx2ho/Paw+4sZPo4u1ByAeIx8EJrxRzSvkvBOdOeyRy6inShXUE/MSu4G6V2Oy2hyws0xiOf6xDNs7oyZnjakKOkgLXKROGNj6Bn7ti9wlgr332WwBv482Abnfshh3/cLVpJqxE= 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=oUpqypyi; arc=none smtp.client-ip=209.85.214.202 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="oUpqypyi" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2254bdd4982so9161075ad.1 for ; Wed, 26 Mar 2025 16:52:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1743033162; x=1743637962; 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=x90XvYEzFqcvfnyhuh/NjS2NoQXwJjkpKyy6gPyPFcE=; b=oUpqypyiplWGtGdCn03TTocyRV2GD3pVROePObteUVslQXF8t/GdWo33SwQWBVN30A d1bm2HwAHRIB+ADFMyQ/r6k5w9F6fiUKmwa+GO8wpspEnN2m1eIbxyGzDJXGdHV9XpKx ea5ftE6P2eiDgB0O18VVIdMYLXv4WVwvJgGRrAMbCF0Fvk5k+Kf8kgc3B3j7tdkZHi8I xLB+DCJG2brd3mVXfEj/PYcPEMOmS8Ecr3bcLoozVc40Dyt3YVU5Gom++7VQaADe8nTc 6nkRTZPQ6xpY7V+CiDYANMu3GWzKZjlDAb/EyBOeGLUzHUFROp41YJznsEDM7g68zDC/ NWjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1743033162; x=1743637962; 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=x90XvYEzFqcvfnyhuh/NjS2NoQXwJjkpKyy6gPyPFcE=; b=Gakqa+IWUw/HbphxlUtNcWCQ2oDF8AG+yWnk2d225qUQ7pckRMG++lV9XzdFwwKgum dCHj56SVg+EAMWKxsqAt2pSnsNmFI5TNtZ3OvSL8EXqSStsBSwqLnbn2J/eigi4VmEb+ 6PtxOa0cfOudlDjHm5mC1XcVutrUYczhuN2zdkrOTwv6JTJmOjkdANbWs88l0l1tpyJ8 h/N5Z66OmM2kmW/daU3B1ZMgWxKbDbumOqkYYdIhrBiiYEFyrcdLYneBN0j8vSuWFJeY tJHxGZjMxDMtnqxdRFZCk1CFZit9x8j7/blOrZTR/UFQ2EiBAspDfgW7CzBau4W9PdqX lETg== X-Gm-Message-State: AOJu0Yyn4kvctM/LJnJi8x6emMREqzvL1HazKRu6goLnikxCY6iyC3ne 0zsNm8vqpK6YIncIEEwUmvqiCrDbPyeNH05BsgfpSrihDYxGHkA1pveu4AXozCEmhIhj7ttRdbl PeOyH6xb4ZT7M14EM6aqQb9E9rPhCSD7jarI+TavRfPfxvmVZqQjBZh+tCCnHtwTTxV8G/JwmoS 75H4GNdLbdz5N52X1s9G6zuqRdyLQStWxYcwfJp5De X-Google-Smtp-Source: AGHT+IHDXEo6LkpH675QoZfsVFOYEDRrNppU08Rfa+cGSrzioV6wNeqQmVyyBL+VZB8bDIo624XJIuSnL5Q= X-Received: from plqt12.prod.google.com ([2002:a17:902:a5cc:b0:21f:14cc:68b0]) (user=ctshao job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:f548:b0:223:6455:8752 with SMTP id d9443c01a7336-2280498703dmr18329665ad.43.1743033162148; Wed, 26 Mar 2025 16:52:42 -0700 (PDT) Date: Wed, 26 Mar 2025 16:42:36 -0700 In-Reply-To: <20250326234758.480431-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: <20250326234758.480431-1-ctshao@google.com> X-Mailer: git-send-email 2.49.0.472.ge94155a9ec-goog Message-ID: <20250326234758.480431-3-ctshao@google.com> Subject: [PATCH v1 2/2] 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, james.clark@linaro.org, howardchu95@gmail.com, weilin.wang@intel.com, yeoreum.yun@arm.com, linux@treblig.org, ak@linux.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 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 --- tools/perf/util/evsel.c | 15 ++++++------ tools/perf/util/evsel.h | 7 ++++-- tools/perf/util/parse-events.c | 45 ++++++++++++++++++++-------------- tools/perf/util/stat-display.c | 2 +- tools/perf/util/stat.c | 40 +++--------------------------- 5 files changed, 44 insertions(+), 65 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f00cfff119aa..84e56691c49f 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; @@ -3980,6 +3975,12 @@ bool evsel__set_needs_uniquify(struct evsel *counter= , const struct perf_stat_con /* Always unique with no aggregation. */ counter->needs_uniquify =3D true; return true; + } else if (counter->first_wildcard_match !=3D NULL) { + /* + * It is under aggregation mode and the counter won't be shown (the coun= ts should be + * aggreated to the `first_wildcard_match` evsel) + */ + return false; } =20 /* @@ -3987,7 +3988,7 @@ bool evsel__set_needs_uniquify(struct evsel *counter,= const struct perf_stat_con * 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..0985fea17a26 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -228,7 +228,7 @@ __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; @@ -262,9 +262,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); @@ -423,7 +423,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 +433,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 +450,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 +485,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; @@ -1415,7 +1422,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 +1458,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 +1528,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 +1561,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 +1594,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 +1610,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 +1647,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 +1658,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 +1675,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..7e2ec33e8c99 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -1011,7 +1011,7 @@ static void print_counter_aggrdata(struct perf_stat_c= onfig *config, os->evsel =3D counter; =20 /* Skip already merged uncore/hybrid events */ - if (counter->merged_stat) + if (config->aggr_mode !=3D AGGR_NONE && counter->first_wildcard_match) return; =20 val =3D aggr->counts.val; 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