From: Ian Rogers <irogers@google.com>
To: linux-perf-users@vger.kernel.org,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>
Cc: linux-kernel@vger.kernel.org,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>, Jiri Olsa <jolsa@kernel.org>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>,
Kan Liang <kan.liang@linux.intel.com>,
Dapeng Mi <dapeng1.mi@linux.intel.com>,
Thomas Falcon <thomas.falcon@intel.com>,
John Garry <john.garry@linux.dev>, Will Deacon <will@kernel.org>,
Leo Yan <leo.yan@arm.com>,
Athira Rajeev <atrajeev@linux.ibm.com>,
Thomas Richter <tmricht@linux.ibm.com>,
Ravi Bangoria <ravi.bangoria@amd.com>,
Sandipan Das <sandipan.das@amd.com>,
Ian Rogers <irogers@google.com>
Subject: [PATCH v1 17/41] perf evsel: Generalize metric_id to a set of metric_ids
Date: Tue, 3 Nov 2026 15:44:33 -0800 [thread overview]
Message-ID: <20261103234502.1008382-18-irogers@google.com> (raw)
In-Reply-To: <20261103234502.1008382-1-irogers@google.com>
When computing a metric the value of each of its events is added to the
expression context using the event's metric_id. When metrics are matched
to events read from a perf.data file, different metrics may refer to the
same recorded event by different names, for example "instructions" and
"cpu_core@INST_RETIRED.ANY@", but an evsel previously stored only a
single metric_id.
Replace evsel::metric_id with a NULL-terminated evsel::metric_ids set of
unique identifier strings. Keep the representation private to evsel.c
behind helpers: evsel__add_metric_id(), evsel__copy_metric_ids(),
evsel__has_metric_id(), evsel__shares_metric_id() and
evsel__for_each_metric_id(), a callback based iterator. Use the iterator
in prepare_metric() to populate the expression parse context with all
metric_ids of each metric event. The metric_ids are freed by
evsel__exit(), so make the __add_event() error path use evsel__put()
rather than freeing the evsel's strings itself.
Remove evsel__metric_id() as returning a single identifier from the set
is error prone. Its uses either iterate over the set, test membership,
or, when finding duplicate events for a metric leader, test whether two
evsels share an identifier. Tool events without an explicit metric-id
keep their tool event name as an implicit identifier, other events
without a metric-id no longer have the identifier "unknown".
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evsel.c | 172 ++++++++++++++++++++++++++++++---
tools/perf/util/evsel.h | 10 +-
tools/perf/util/metricgroup.c | 98 ++++++++++++-------
tools/perf/util/parse-events.c | 8 +-
tools/perf/util/python.c | 34 +++++--
tools/perf/util/stat-shadow.c | 37 +++++--
6 files changed, 291 insertions(+), 68 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 4053a80d3ba7..e73a84e6d59d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -577,11 +577,8 @@ struct evsel *evsel__clone(struct evsel *orig)
if (evsel->filter == NULL)
goto out_err;
}
- if (orig->metric_id) {
- evsel->metric_id = strdup(orig->metric_id);
- if (evsel->metric_id == NULL)
- goto out_err;
- }
+ if (evsel__copy_metric_ids(evsel, orig))
+ goto out_err;
evsel->cgrp = cgroup__get(orig->cgrp);
#ifdef HAVE_LIBTRACEEVENT
if (orig->tp_sys) {
@@ -1029,15 +1026,166 @@ bool evsel__name_is(struct evsel *evsel, const char *name)
return !strcmp(evsel__name(evsel), name);
}
-const char *evsel__metric_id(const struct evsel *evsel)
+/*
+ * Tool events, such as duration_time, are identified by their tool event name.
+ * Other events without a metric-id have no identifier. The evsel's PMU may not
+ * be set yet, such as during parsing or cloning, so check the attribute's type
+ * rather than using evsel__is_tool().
+ */
+static const char *evsel__implicit_metric_id(const struct evsel *evsel)
{
- if (evsel->metric_id)
- return evsel->metric_id;
+ if (evsel->core.attr.type != PERF_PMU_TYPE_TOOL)
+ return NULL;
- if (evsel__is_tool(evsel))
- return evsel__tool_pmu_event_name(evsel);
+ return evsel__tool_pmu_event_name(evsel);
+}
- return "unknown";
+/**
+ * evsel__for_each_metric_id - Call @cb for each metric identifier of @evsel.
+ * @evsel: The evsel holding the metric identifiers.
+ * @cb: Callback passed each identifier, a non-zero return stops the iteration.
+ * @data: Passed to @cb.
+ *
+ * Explicit identifiers are visited in the order they were added, followed by
+ * the tool event name for tool events. Tool events without explicit
+ * identifiers have their tool event name as the only identifier.
+ *
+ * Return: 0 or the first non-zero value returned by @cb.
+ */
+int evsel__for_each_metric_id(const struct evsel *evsel,
+ int (*cb)(const char *metric_id, void *data),
+ void *data)
+{
+ const char *implicit_id;
+
+ if (!evsel->metric_ids) {
+ implicit_id = evsel__implicit_metric_id(evsel);
+ return implicit_id ? cb(implicit_id, data) : 0;
+ }
+
+ for (size_t i = 0; evsel->metric_ids[i]; i++) {
+ int ret = cb(evsel->metric_ids[i], data);
+
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int metric_id_equal_cb(const char *metric_id, void *data)
+{
+ return !strcmp(metric_id, data);
+}
+
+/**
+ * evsel__has_metric_id - Is @metric_id an identifier of @evsel?
+ * @evsel: The evsel holding the metric identifiers.
+ * @metric_id: The identifier to search for, may be NULL.
+ *
+ * Return: true if @metric_id is in the set of metric identifiers of @evsel.
+ */
+bool evsel__has_metric_id(const struct evsel *evsel, const char *metric_id)
+{
+ if (!metric_id)
+ return false;
+
+ return evsel__for_each_metric_id(evsel, metric_id_equal_cb, (void *)metric_id);
+}
+
+static int has_metric_id_cb(const char *metric_id, void *data)
+{
+ const struct evsel *evsel = data;
+
+ return evsel__has_metric_id(evsel, metric_id);
+}
+
+/**
+ * evsel__shares_metric_id - Do two evsels have a metric identifier in common?
+ * @a: The first evsel.
+ * @b: The second evsel.
+ *
+ * Return: true if the intersection of the metric identifier sets of @a and @b
+ * isn't empty.
+ */
+bool evsel__shares_metric_id(const struct evsel *a, const struct evsel *b)
+{
+ return evsel__for_each_metric_id(a, has_metric_id_cb, (void *)b);
+}
+
+/**
+ * evsel__add_metric_id - Add an identifier to the metric identifiers of @evsel.
+ * @evsel: The evsel to add the metric identifier to.
+ * @metric_id: The identifier to add, ignored if NULL or already present.
+ *
+ * The first explicit identifier added to a tool event is followed by the tool
+ * event name so that the tool event name remains an identifier.
+ *
+ * Return: 0 on success or -ENOMEM.
+ */
+int evsel__add_metric_id(struct evsel *evsel, const char *metric_id)
+{
+ const char *implicit_id;
+ char **new_ids;
+ size_t nr = 0;
+
+ if (!metric_id || evsel__has_metric_id(evsel, metric_id))
+ return 0;
+
+ implicit_id = evsel->metric_ids ? NULL : evsel__implicit_metric_id(evsel);
+ while (evsel->metric_ids && evsel->metric_ids[nr])
+ nr++;
+
+ new_ids = realloc(evsel->metric_ids, (nr + 3) * sizeof(*new_ids));
+ if (!new_ids)
+ return -ENOMEM;
+ evsel->metric_ids = new_ids;
+
+ new_ids[nr] = strdup(metric_id);
+ if (!new_ids[nr])
+ goto out_err;
+ new_ids[nr + 1] = NULL;
+ if (implicit_id) {
+ new_ids[nr + 1] = strdup(implicit_id);
+ if (!new_ids[nr + 1])
+ goto out_err;
+ new_ids[nr + 2] = NULL;
+ }
+ return 0;
+out_err:
+ zfree(&new_ids[nr]);
+ if (!nr)
+ zfree(&evsel->metric_ids);
+ return -ENOMEM;
+}
+
+static int add_metric_id_cb(const char *metric_id, void *data)
+{
+ struct evsel *evsel = data;
+
+ return evsel__add_metric_id(evsel, metric_id);
+}
+
+/**
+ * evsel__copy_metric_ids - Add the metric identifiers of @src to @dst.
+ * @dst: The evsel to add the metric identifiers to.
+ * @src: The evsel whose metric identifiers are copied.
+ *
+ * Return: 0 on success or -ENOMEM.
+ */
+int evsel__copy_metric_ids(struct evsel *dst, const struct evsel *src)
+{
+ return evsel__for_each_metric_id(src, add_metric_id_cb, dst);
+}
+
+/**
+ * evsel__free_metric_ids - Free the metric identifiers of @evsel.
+ * @evsel: The evsel whose metric identifiers are freed.
+ */
+static void evsel__free_metric_ids(struct evsel *evsel)
+{
+ for (size_t i = 0; evsel->metric_ids && evsel->metric_ids[i]; i++)
+ zfree(&evsel->metric_ids[i]);
+ zfree(&evsel->metric_ids);
}
const char *evsel__group_name(struct evsel *evsel)
@@ -2092,7 +2240,7 @@ static void evsel__exit(struct evsel *evsel)
zfree(&evsel->filter);
zfree(&evsel->group_pmu_name);
zfree(&evsel->unit);
- zfree(&evsel->metric_id);
+ evsel__free_metric_ids(evsel);
evsel__zero_per_pkg(evsel);
hashmap__free(evsel->per_pkg_mask);
evsel->per_pkg_mask = NULL;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 53f3641b66e1..e776ca60a9a5 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -74,7 +74,7 @@ struct evsel {
double scale;
const char *unit;
struct cgroup *cgrp;
- const char *metric_id;
+ char **metric_ids;
/* The PMU the event is from. Used for missing_features, PMU name, etc. */
struct perf_pmu *pmu;
@@ -336,7 +336,13 @@ int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size);
int __evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size);
const char *evsel__name(struct evsel *evsel);
bool evsel__name_is(struct evsel *evsel, const char *name);
-const char *evsel__metric_id(const struct evsel *evsel);
+int evsel__for_each_metric_id(const struct evsel *evsel,
+ int (*cb)(const char *metric_id, void *data),
+ void *data);
+bool evsel__has_metric_id(const struct evsel *evsel, const char *metric_id);
+bool evsel__shares_metric_id(const struct evsel *a, const struct evsel *b);
+int evsel__add_metric_id(struct evsel *evsel, const char *metric_id);
+int evsel__copy_metric_ids(struct evsel *dst, const struct evsel *src);
static inline bool evsel__is_retire_lat(const struct evsel *evsel)
{
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index b4a978794cc8..e87da791fd1e 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -275,12 +275,34 @@ static bool contains_metric_id(struct evsel **metric_events, int num_events,
int i;
for (i = 0; i < num_events; i++) {
- if (!strcmp(evsel__metric_id(metric_events[i]), metric_id))
+ if (evsel__has_metric_id(metric_events[i], metric_id))
return true;
}
return false;
}
+struct match_metric_id_args {
+ /* The events already matched to IDs of the metric. */
+ struct evsel **metric_events;
+ size_t num_events;
+ /* The metric IDs to match. */
+ struct hashmap *ids;
+ /* The newly matched ID. */
+ const char *matched_id;
+};
+
+static int match_metric_id_cb(const char *metric_id, void *data)
+{
+ struct match_metric_id_args *args = data;
+
+ if (contains_metric_id(args->metric_events, args->num_events, metric_id))
+ return 0;
+ if (!hashmap__find(args->ids, metric_id, NULL))
+ return 0;
+ args->matched_id = metric_id;
+ return 1;
+}
+
/**
* setup_metric_events - Find a group of events in metric_evlist that correspond
* to the IDs from a parsed metric expression.
@@ -293,8 +315,8 @@ static int setup_metric_events(const char *pmu, struct hashmap *ids,
struct evlist *metric_evlist,
struct evsel ***out_metric_events)
{
+ struct match_metric_id_args args = { .ids = ids, };
struct evsel **metric_events;
- const char *metric_id;
struct evsel *ev;
size_t ids_size, matched_events, i;
struct perf_pmus *pmus = perf_env__pmus(evlist__env(metric_evlist) ?: host_env());
@@ -310,9 +332,8 @@ static int setup_metric_events(const char *pmu, struct hashmap *ids,
return -ENOMEM;
matched_events = 0;
+ args.metric_events = metric_events;
evlist__for_each_entry(metric_evlist, ev) {
- struct expr_id_data *val_ptr;
-
/* Don't match events for the wrong hybrid PMU. */
if (!all_pmus && ev->pmu && evsel__is_hybrid(ev) &&
strcmp(ev->pmu->name, pmu))
@@ -323,21 +344,19 @@ static int setup_metric_events(const char *pmu, struct hashmap *ids,
* events per socket on skylakex. Only the first such
* event is placed in metric_events.
*/
- metric_id = evsel__metric_id(ev);
- if (contains_metric_id(metric_events, matched_events, metric_id))
- continue;
/*
* Does this event belong to the parse context? For
* combined or shared groups, this metric may not care
* about this event.
*/
- if (hashmap__find(ids, metric_id, &val_ptr)) {
- pr_debug("Matched metric-id %s to %s\n", metric_id, evsel__name(ev));
+ args.num_events = matched_events;
+ if (evsel__for_each_metric_id(ev, match_metric_id_cb, &args)) {
+ pr_debug("Matched metric-id %s to %s\n",
+ args.matched_id, evsel__name(ev));
metric_events[matched_events++] = ev;
-
- if (matched_events >= ids_size)
- break;
}
+ if (matched_events >= ids_size)
+ break;
}
if (matched_events < ids_size) {
free(metric_events);
@@ -359,9 +378,8 @@ static int setup_metric_events(const char *pmu, struct hashmap *ids,
* of such events to be the event that appears in
* metric_events.
*/
- metric_id = evsel__metric_id(ev);
evlist__for_each_entry_continue(metric_evlist, ev) {
- if (!strcmp(evsel__metric_id(ev), metric_id))
+ if (evsel__shares_metric_id(ev, metric_events[i]))
ev->metric_leader = metric_events[i];
}
}
@@ -469,13 +487,6 @@ static struct evsel *map_metric_evsel_to_evlist(struct evlist *data_evlist,
continue;
if (metric_evsel->core.attr.config != data_evsel->core.attr.config)
continue;
- /* Skip if the data event has a metric_id that doesn't match. */
- if (data_evsel->metric_id &&
- strcmp(evsel__metric_id(metric_evsel), evsel__metric_id(data_evsel))) {
- pr_debug("Skipping matching evsel due to differing metric ids '%s' vs '%s'\n",
- evsel__metric_id(metric_evsel), evsel__metric_id(data_evsel));
- continue;
- }
return data_evsel;
}
return NULL;
@@ -516,9 +527,8 @@ static int find_matching_metrics_cb(const struct pmu_metric *pm,
struct evsel *new_metric_leader;
if (!data_evsel) {
- pr_debug("Skipping metric '%s' as evsel '%s' / '%s' is missing\n",
- pm->metric_name, evsel__name(metric_evsel),
- evsel__metric_id(metric_evsel));
+ pr_debug("Skipping metric '%s' as evsel '%s' is missing\n",
+ pm->metric_name, evsel__name(metric_evsel));
goto out;
}
@@ -535,8 +545,8 @@ static int find_matching_metrics_cb(const struct pmu_metric *pm,
/* Mismatching evsel leaders. */
if (data_evsel->metric_leader != new_metric_leader) {
pr_debug("Skipping metric '%s' due to mismatching evsel metric leaders '%s' vs '%s'\n",
- pm->metric_name, evsel__metric_id(metric_evsel),
- evsel__metric_id(data_evsel));
+ pm->metric_name, evsel__name(metric_evsel),
+ evsel__name(data_evsel));
goto out;
}
}
@@ -552,10 +562,8 @@ static int find_matching_metrics_cb(const struct pmu_metric *pm,
metric_evsel,
/*create=*/false);
- if (data_evsel->metric_id == NULL) {
- data_evsel->metric_id = metric_evsel->metric_id;
- metric_evsel->metric_id = NULL;
- }
+ if (evsel__copy_metric_ids(data_evsel, metric_evsel))
+ goto out;
if (data_evsel->metric_leader == NULL) {
if (metric_evsel->metric_leader == metric_evsel) {
@@ -610,6 +618,17 @@ int metricgroup__add_matching_metrics(struct evlist *evlist, bool system_wide)
find_matching_metrics_cb, &args);
}
+static int append_metric_id_cb(const char *metric_id, void *data)
+{
+ struct strbuf *sb = data;
+
+ /*
+ * Stop after the first, the metric-id of a parsed metric event is its
+ * first identifier.
+ */
+ return strbuf_addstr(sb, metric_id) ?: 1;
+}
+
/*
* The metric events are parsed with a metric-id holding the identifier used in
* the metric expression. If the evsel name is just the parsed event, which
@@ -626,16 +645,19 @@ static int set_metric_event_names(struct evlist *perf_evlist, const char *modifi
evlist__for_each_entry(perf_evlist, ev) {
bool has_slash = false;
- if (!ev->metric_id || !strstr(ev->name, "metric-id="))
+ if (!strstr(ev->name, "metric-id="))
continue;
ret = strbuf_setlen(&sb, 0);
if (ret)
break;
- ret = strbuf_addstr(&sb, ev->metric_id);
- if (ret)
+ ret = evsel__for_each_metric_id(ev, append_metric_id_cb, &sb);
+ if (ret < 0)
break;
+ if (ret == 0)
+ continue;
+ ret = 0;
zfree(&ev->name);
for (cur = strchr(sb.buf, '@') ; cur; cur = strchr(++cur, '@')) {
@@ -1470,15 +1492,21 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
return ret;
}
+static int pctx_has_metric_id_cb(const char *metric_id, void *data)
+{
+ struct hashmap *ids = data;
+
+ return hashmap__find(ids, metric_id, NULL) ? 1 : 0;
+}
+
/* How many times will a given evsel be used in a set of metrics? */
static int count_uses(struct list_head *metric_list, struct evsel *evsel)
{
- const char *metric_id = evsel__metric_id(evsel);
struct metric *m;
int uses = 0;
list_for_each_entry(m, metric_list, nd) {
- if (hashmap__find(m->pctx->ids, metric_id, NULL))
+ if (evsel__for_each_metric_id(evsel, pctx_has_metric_id_cb, m->pctx->ids))
uses++;
}
return uses;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1c02c2b90684..1cda7dc4d00f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -332,9 +332,9 @@ __add_event(struct list_head *list, int *idx,
int ret = parse_events__decode_metric_id(&sb, metric_id);
if (!ret)
- evsel->metric_id = strdup(sb.buf);
+ ret = evsel__add_metric_id(evsel, sb.buf);
strbuf_release(&sb);
- if (!evsel->metric_id)
+ if (ret)
goto out_err;
}
@@ -362,9 +362,7 @@ __add_event(struct list_head *list, int *idx,
out_err:
perf_cpu_map__put(cpus);
perf_cpu_map__put(pmu_cpus);
- zfree(&evsel->name);
- zfree(&evsel->metric_id);
- free(evsel);
+ evsel__put(evsel);
return NULL;
}
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 065742a7431b..cdd12557d065 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -3073,6 +3073,27 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
return list;
}
+struct add_metric_id_val_args {
+ struct expr_parse_ctx *pctx;
+ double val;
+ int source_count;
+};
+
+static int add_metric_id_val_cb(const char *metric_id, void *data)
+{
+ struct add_metric_id_val_args *args = data;
+ char *n = strdup(metric_id);
+ int ret;
+
+ if (!n)
+ return -ENOMEM;
+
+ ret = expr__add_id_val_source_count(args->pctx, n, args->val, args->source_count);
+ if (ret)
+ free(n);
+ return ret;
+}
+
static int prepare_metric(const struct metric_expr *mexp,
const struct evsel *evsel,
struct expr_parse_ctx *pctx,
@@ -3080,6 +3101,7 @@ static int prepare_metric(const struct metric_expr *mexp,
{
struct evsel * const *metric_events = mexp->metric_events;
struct metric_ref *metric_refs = mexp->metric_refs;
+ struct add_metric_id_val_args args = { .pctx = pctx, };
for (int i = 0; metric_events[i]; i++) {
struct evsel *cur = metric_events[i];
@@ -3127,15 +3149,11 @@ static int prepare_metric(const struct metric_expr *mexp,
if (ena != run && run != 0)
val = val * ena / run;
- char *n = strdup(evsel__metric_id(cur));
-
- if (!n)
- return -ENOMEM;
- ret = expr__add_id_val_source_count(pctx, n, val, source_count);
- if (ret) {
- free(n);
+ args.val = val;
+ args.source_count = source_count;
+ ret = evsel__for_each_metric_id(cur, add_metric_id_val_cb, &args);
+ if (ret)
return ret;
- }
}
for (int i = 0; metric_refs && metric_refs[i].metric_name; i++) {
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index f5ae399bf336..587db3e2a05b 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -45,6 +45,29 @@ static bool tool_pmu__is_time_event(const struct perf_stat_config *config,
return true;
}
+struct add_metric_id_val_args {
+ struct expr_parse_ctx *pctx;
+ double val;
+ int source_count;
+ int aggr_nr;
+};
+
+static int add_metric_id_val_cb(const char *metric_id, void *data)
+{
+ struct add_metric_id_val_args *args = data;
+ char *n = strdup(metric_id);
+ int ret;
+
+ if (!n)
+ return -ENOMEM;
+
+ ret = expr__add_id_val_source_count_aggr_nr(args->pctx, n, args->val,
+ args->source_count, args->aggr_nr);
+ if (ret)
+ free(n);
+ return ret;
+}
+
static int prepare_metric(struct perf_stat_config *config,
const struct metric_expr *mexp,
const struct evsel *evsel,
@@ -53,15 +76,16 @@ static int prepare_metric(struct perf_stat_config *config,
{
struct evsel * const *metric_events = mexp->metric_events;
struct metric_ref *metric_refs = mexp->metric_refs;
+ struct add_metric_id_val_args args = { .pctx = pctx, };
int i;
for (i = 0; metric_events[i]; i++) {
int source_count = 0, tool_aggr_idx;
int aggr_nr = 1;
+ int ret;
bool is_tool_time =
tool_pmu__is_time_event(config, metric_events[i], &tool_aggr_idx);
struct perf_stat_evsel *ps = metric_events[i]->stats;
- char *n;
double val;
/*
@@ -114,11 +138,12 @@ static int prepare_metric(struct perf_stat_config *config,
aggr_nr = aggr->nr ?: 1;
}
}
- n = strdup(evsel__metric_id(metric_events[i]));
- if (!n)
- return -ENOMEM;
-
- expr__add_id_val_source_count_aggr_nr(pctx, n, val, source_count, aggr_nr);
+ args.val = val;
+ args.source_count = source_count;
+ args.aggr_nr = aggr_nr;
+ ret = evsel__for_each_metric_id(metric_events[i], add_metric_id_val_cb, &args);
+ if (ret)
+ return ret;
}
for (int j = 0; metric_refs && metric_refs[j].metric_name; j++) {
--
2.56.0.385.gac671c819a-goog
next prev parent reply other threads:[~2026-11-03 23:45 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 23:44 [PATCH v1 00/41] perf: Per-env PMUs, recorded event metrics, and perf sysinfo Ian Rogers
2026-11-03 23:44 ` [PATCH v1 01/41] perf env: Make lazy perf_env initialization thread-safe Ian Rogers
2026-11-03 23:44 ` [PATCH v1 02/41] perf env: Add host_env() singleton Ian Rogers
2026-11-03 23:44 ` [PATCH v1 03/41] perf pmu: Add from_env parameter to perf_pmu__init() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 04/41] perf pmus: Introduce struct perf_pmus and perf_env__pmus() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 05/41] perf pmus: Pass struct perf_pmus to find helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 06/41] perf pmus: Pass struct perf_pmus to scan helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 07/41] perf pmu-events: Add e_machine to struct pmu_events_map Ian Rogers
2026-11-03 23:44 ` [PATCH v1 08/41] perf pmu-events: Pass e_machine to find_core_*_table() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 09/41] perf header: Pass e_machine to strcmp_cpuid_str() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 10/41] perf header: Support CPUID matching across all architectures Ian Rogers
2026-11-03 23:44 ` [PATCH v1 11/41] perf test: Make the CPUID matching test architecture independent Ian Rogers
2026-11-03 23:44 ` [PATCH v1 12/41] perf test: Add CPUID matching tests for other architectures Ian Rogers
2026-11-03 23:44 ` [PATCH v1 13/41] perf pmus: Add perf_pmus__read_from_env() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 14/41] perf metricgroup: Pass struct perf_pmus to metricgroup__for_each_metric() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 15/41] perf metricgroup: Move matching of metrics to recorded events from perf script Ian Rogers
2026-11-03 23:44 ` [PATCH v1 16/41] perf parse-events: Decode metric-id terms when adding events Ian Rogers
2026-11-03 23:44 ` Ian Rogers [this message]
2026-11-03 23:44 ` [PATCH v1 18/41] perf pmu: Add perf_pmu__for_each_name_from_config() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 19/41] perf metricgroup: Improve matching of metrics to recorded events Ian Rogers
2026-11-03 23:44 ` [PATCH v1 20/41] perf metricgroup: Add metricgroup__add_recorded_metrics() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 21/41] perf script: Fix metrics computed from samples Ian Rogers
2026-11-03 23:44 ` [PATCH v1 22/41] perf script: Don't drop metric samples for CPUs missing from the evsel Ian Rogers
2026-11-03 23:44 ` [PATCH v1 23/41] perf stat report: Display metrics for recorded events Ian Rogers
2026-11-03 23:44 ` [PATCH v1 24/41] perf script: Display metrics for perf stat record data Ian Rogers
2026-11-03 23:44 ` [PATCH v1 25/41] perf test: Add stat record metrics test Ian Rogers
2026-11-03 23:44 ` [PATCH v1 26/41] perf pmus: Expose duplicate uncore PMU scanning helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 27/41] perf mem-events: Expose PMU init and name formatting helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 28/41] perf pmu: Add perf_pmu__probe() for basic open, counting, and sampling Ian Rogers
2026-11-03 23:44 ` [PATCH v1 29/41] perf pmu: Probe supported sample_type flags Ian Rogers
2026-11-03 23:44 ` [PATCH v1 30/41] perf pmu: Probe precise_ip levels Ian Rogers
2026-11-03 23:44 ` [PATCH v1 31/41] perf pmu: Probe privilege exclusion modifiers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 32/41] perf pmu: Probe execution and AUX area features Ian Rogers
2026-11-03 23:44 ` [PATCH v1 33/41] perf pmu: Probe event group size limits Ian Rogers
2026-11-03 23:44 ` [PATCH v1 34/41] perf pmu: Probe user and interrupt sample register masks Ian Rogers
2026-11-03 23:44 ` [PATCH v1 35/41] perf pmu: Probe interrupt registers that require precise sampling Ian Rogers
2026-11-03 23:44 ` [PATCH v1 36/41] perf pmu: Probe memory profiling events and sample formats Ian Rogers
2026-11-03 23:44 ` [PATCH v1 37/41] perf pmu: Probe user-space mmap capabilities Ian Rogers
2026-11-03 23:44 ` [PATCH v1 38/41] perf pmu: Probe branch instruction skid Ian Rogers
2026-11-03 23:44 ` [PATCH v1 39/41] perf sysinfo: Add sysinfo subcommand Ian Rogers
2026-11-03 23:44 ` [PATCH v1 40/41] perf docs: Add perf-sysinfo man page Ian Rogers
2026-11-03 23:44 ` [PATCH v1 41/41] perf test: Add perf sysinfo shell test Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261103234502.1008382-18-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=atrajeev@linux.ibm.com \
--cc=dapeng1.mi@linux.intel.com \
--cc=james.clark@linaro.org \
--cc=john.garry@linux.dev \
--cc=jolsa@kernel.org \
--cc=kan.liang@linux.intel.com \
--cc=leo.yan@arm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=ravi.bangoria@amd.com \
--cc=sandipan.das@amd.com \
--cc=thomas.falcon@intel.com \
--cc=tmricht@linux.ibm.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®