summaryrefslogtreecommitdiff
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2022-08-12 16:09:45 -0700
committerArnaldo Carvalho de Melo <acme@redhat.com>2022-08-13 15:01:31 -0300
commit660842e468dcefb5d1d4fb40ed3abe4d1388dff7 (patch)
tree1f440d77fef497cee8c1a71bc8cf3d4f1bec69af /tools/perf/util
parent7ae5c03a27934bee9daaeede1b0b1d4bada61ffd (diff)
perf pmu-events: Don't assume pmu_event is an array
The current code assumes that a struct pmu_event can be iterated over forward until a NULL pmu_event is encountered. This makes it difficult to refactor pmu_event. Add a loop function taking a callback function that's passed the struct pmu_event. This way the pmu_event is only needed for one element and not an entire array. Switch existing code iterating over the pmu_event arrays to use the new loop function pmu_events_table_for_each_event. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@arm.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.garry@huawei.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mike Leach <mike.leach@linaro.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Stephane Eranian <eranian@google.com> Cc: Will Deacon <will@kernel.org> Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com> Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20220812230949.683239-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/metricgroup.c181
-rw-r--r--tools/perf/util/pmu.c65
-rw-r--r--tools/perf/util/s390-sample-raw.c42
3 files changed, 192 insertions, 96 deletions
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8d994539d6ea..cae97b6dc5bc 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -538,12 +538,40 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
d->details, d->groups, d->metriclist);
}
+struct metricgroup_print_data {
+ const char *pmu_name;
+ struct strlist *metriclist;
+ char *filter;
+ struct rblist *groups;
+ bool metricgroups;
+ bool raw;
+ bool details;
+};
+
+static int metricgroup__print_callback(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *vdata)
+{
+ struct metricgroup_print_data *data = vdata;
+
+ if (!pe->metric_expr)
+ return 0;
+
+ if (data->pmu_name && perf_pmu__is_hybrid(pe->pmu) && strcmp(data->pmu_name, pe->pmu))
+ return 0;
+
+ return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter,
+ data->raw, data->details, data->groups,
+ data->metriclist);
+}
+
void metricgroup__print(bool metrics, bool metricgroups, char *filter,
bool raw, bool details, const char *pmu_name)
{
struct rblist groups;
struct rb_node *node, *next;
struct strlist *metriclist = NULL;
+ const struct pmu_event *table;
if (!metricgroups) {
metriclist = strlist__new(NULL, NULL);
@@ -555,22 +583,22 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
groups.node_new = mep_new;
groups.node_cmp = mep_cmp;
groups.node_delete = mep_delete;
- for (const struct pmu_event *pe = pmu_events_table__find(); pe; pe++) {
+ table = pmu_events_table__find();
+ if (table) {
+ struct metricgroup_print_data data = {
+ .pmu_name = pmu_name,
+ .metriclist = metriclist,
+ .metricgroups = metricgroups,
+ .filter = filter,
+ .raw = raw,
+ .details = details,
+ .groups = &groups,
+ };
- if (!pe->name && !pe->metric_group && !pe->metric_name)
- break;
- if (!pe->metric_expr)
- continue;
- if (pmu_name && perf_pmu__is_hybrid(pe->pmu) &&
- strcmp(pmu_name, pe->pmu)) {
- continue;
- }
- if (metricgroup__print_pmu_event(pe, metricgroups, filter,
- raw, details, &groups,
- metriclist) < 0)
- return;
+ pmu_events_table_for_each_event(table,
+ metricgroup__print_callback,
+ &data);
}
-
{
struct metricgroup_iter_data data = {
.fn = metricgroup__print_sys_event_iter,
@@ -1043,30 +1071,35 @@ static int __add_metric(struct list_head *metric_list,
return ret;
}
-#define table_for_each_event(__pe, __idx, __table) \
- if (__table) \
- for (__idx = 0, __pe = &__table[__idx]; \
- __pe->name || __pe->metric_group || __pe->metric_name; \
- __pe = &__table[++__idx])
+struct metricgroup__find_metric_data {
+ const char *metric;
+ const struct pmu_event *pe;
+};
+
+static int metricgroup__find_metric_callback(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *vdata)
+{
+ struct metricgroup__find_metric_data *data = vdata;
+
+ if (!match_metric(pe->metric_name, data->metric))
+ return 0;
-#define table_for_each_metric(__pe, __idx, __table, __metric) \
- table_for_each_event(__pe, __idx, __table) \
- if (__pe->metric_expr && \
- (match_metric(__pe->metric_group, __metric) || \
- match_metric(__pe->metric_name, __metric)))
+ data->pe = pe;
+ return -1;
+}
const struct pmu_event *metricgroup__find_metric(const char *metric,
const struct pmu_event *table)
{
- const struct pmu_event *pe;
- int i;
+ struct metricgroup__find_metric_data data = {
+ .metric = metric,
+ .pe = NULL,
+ };
- table_for_each_event(pe, i, table) {
- if (match_metric(pe->metric_name, metric))
- return pe;
- }
+ pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data);
- return NULL;
+ return data.pe;
}
static int add_metric(struct list_head *metric_list,
@@ -1151,6 +1184,33 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
return right_count - left_count;
}
+struct metricgroup__add_metric_data {
+ struct list_head *list;
+ const char *metric_name;
+ const char *modifier;
+ bool metric_no_group;
+ bool has_match;
+};
+
+static int metricgroup__add_metric_callback(const struct pmu_event *pe,
+ const struct pmu_event *table,
+ void *vdata)
+{
+ struct metricgroup__add_metric_data *data = vdata;
+ int ret = 0;
+
+ if (pe->metric_expr &&
+ (match_metric(pe->metric_group, data->metric_name) ||
+ match_metric(pe->metric_name, data->metric_name))) {
+
+ data->has_match = true;
+ ret = add_metric(data->list, pe, data->modifier, data->metric_no_group,
+ /*root_metric=*/NULL,
+ /*visited_metrics=*/NULL, table);
+ }
+ return ret;
+}
+
/**
* metricgroup__add_metric - Find and add a metric, or a metric group.
* @metric_name: The name of the metric or metric group. For example, "IPC"
@@ -1169,24 +1229,29 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
struct list_head *metric_list,
const struct pmu_event *table)
{
- const struct pmu_event *pe;
LIST_HEAD(list);
- int i, ret;
+ int ret;
bool has_match = false;
- /*
- * Iterate over all metrics seeing if metric matches either the name or
- * group. When it does add the metric to the list.
- */
- table_for_each_metric(pe, i, table, metric_name) {
- has_match = true;
- ret = add_metric(&list, pe, modifier, metric_no_group,
- /*root_metric=*/NULL,
- /*visited_metrics=*/NULL, table);
+ {
+ struct metricgroup__add_metric_data data = {
+ .list = &list,
+ .metric_name = metric_name,
+ .modifier = modifier,
+ .metric_no_group = metric_no_group,
+ .has_match = false,
+ };
+ /*
+ * Iterate over all metrics seeing if metric matches either the
+ * name or group. When it does add the metric to the list.
+ */
+ ret = pmu_events_table_for_each_event(table, metricgroup__add_metric_callback,
+ &data);
if (ret)
goto out;
- }
+ has_match = data.has_match;
+ }
{
struct metricgroup_iter_data data = {
.fn = metricgroup__add_metric_sys_event_iter,
@@ -1602,26 +1667,30 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
metric_no_merge, &perf_pmu__fake, metric_events, table);
}
+static int metricgroup__has_metric_callback(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *vdata)
+{
+ const char *metric = vdata;
+
+ if (!pe->metric_expr)
+ return 0;
+
+ if (match_metric(pe->metric_name, metric))
+ return 1;
+
+ return 0;
+}
+
bool metricgroup__has_metric(const char *metric)
{
const struct pmu_event *table = pmu_events_table__find();
- const struct pmu_event *pe;
- int i;
if (!table)
return false;
- for (i = 0; ; i++) {
- pe = &table[i];
-
- if (!pe->name && !pe->metric_group && !pe->metric_name)
- break;
- if (!pe->metric_expr)
- continue;
- if (match_metric(pe->metric_name, metric))
- return true;
- }
- return false;
+ return pmu_events_table_for_each_event(table, metricgroup__has_metric_callback,
+ (void *)metric) ? true : false;
}
int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index f117324eb5f0..dd1e171d7480 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -791,6 +791,36 @@ out:
return res;
}
+struct pmu_add_cpu_aliases_map_data {
+ struct list_head *head;
+ const char *name;
+ const char *cpu_name;
+ struct perf_pmu *pmu;
+};
+
+static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *vdata)
+{
+ struct pmu_add_cpu_aliases_map_data *data = vdata;
+ const char *pname = pe->pmu ? pe->pmu : data->cpu_name;
+
+ if (!pe->name)
+ return 0;
+
+ if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name))
+ goto new_alias;
+
+ if (strcmp(pname, data->name))
+ return 0;
+
+new_alias:
+ /* need type casts to override 'const' */
+ __perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc,
+ (char *)pe->event, pe);
+ return 0;
+}
+
/*
* From the pmu_events_map, find the table of PMU events that corresponds
* to the current running CPU. Then, add all PMU events from that table
@@ -799,35 +829,14 @@ out:
void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu,
const struct pmu_event *table)
{
- int i;
- const char *name = pmu->name;
- /*
- * Found a matching PMU events table. Create aliases
- */
- i = 0;
- while (1) {
- const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
- const struct pmu_event *pe = &table[i++];
- const char *pname = pe->pmu ? pe->pmu : cpu_name;
-
- if (!pe->name) {
- if (pe->metric_group || pe->metric_name)
- continue;
- break;
- }
-
- if (pmu->is_uncore && pmu_uncore_alias_match(pname, name))
- goto new_alias;
-
- if (strcmp(pname, name))
- continue;
+ struct pmu_add_cpu_aliases_map_data data = {
+ .head = head,
+ .name = pmu->name,
+ .cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu",
+ .pmu = pmu,
+ };
-new_alias:
- /* need type casts to override 'const' */
- __perf_pmu__new_alias(head, NULL, (char *)pe->name,
- (char *)pe->desc, (char *)pe->event,
- pe);
- }
+ pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data);
}
static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index dddd2be59827..235319d45d02 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -129,6 +129,28 @@ static int get_counterset_start(int setnr)
}
}
+struct get_counter_name_data {
+ int wanted;
+ const char *result;
+};
+
+static int get_counter_name_callback(const struct pmu_event *evp,
+ const struct pmu_event *table __maybe_unused,
+ void *vdata)
+{
+ struct get_counter_name_data *data = vdata;
+ int rc, event_nr;
+
+ if (evp->name == NULL || evp->event == NULL)
+ return 0;
+ rc = sscanf(evp->event, "event=%x", &event_nr);
+ if (rc == 1 && event_nr == data->wanted) {
+ data->result = evp->name;
+ return 1; /* Terminate the search. */
+ }
+ return 0;
+}
+
/* Scan the PMU table and extract the logical name of a counter from the
* PMU events table. Input is the counter set and counter number with in the
* set. Construct the event number and use this as key. If they match return
@@ -137,20 +159,16 @@ static int get_counterset_start(int setnr)
*/
static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
{
- int rc, event_nr, wanted = get_counterset_start(set) + nr;
+ struct get_counter_name_data data = {
+ .wanted = get_counterset_start(set) + nr,
+ .result = NULL,
+ };
- if (table) {
- const struct pmu_event *evp = table;
+ if (!table)
+ return NULL;
- for (; evp->name || evp->event || evp->desc; ++evp) {
- if (evp->name == NULL || evp->event == NULL)
- continue;
- rc = sscanf(evp->event, "event=%x", &event_nr);
- if (rc == 1 && event_nr == wanted)
- return evp->name;
- }
- }
- return NULL;
+ pmu_events_table_for_each_event(table, get_counter_name_callback, &data);
+ return data.result;
}
static void s390_cpumcfdg_dump(struct perf_sample *sample)