diff options
Diffstat (limited to 'tools/perf/util/metricgroup.c')
-rw-r--r-- | tools/perf/util/metricgroup.c | 142 |
1 files changed, 110 insertions, 32 deletions
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 5e9c657dd3f7..a6a5ed44a679 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -11,7 +11,7 @@ #include "evsel.h" #include "strbuf.h" #include "pmu.h" -#include "pmu-hybrid.h" +#include "pmus.h" #include "print-events.h" #include "smt.h" #include "expr.h" @@ -79,6 +79,7 @@ static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused, return NULL; memcpy(me, entry, sizeof(struct metric_event)); me->evsel = ((struct metric_event *)entry)->evsel; + me->is_default = false; INIT_LIST_HEAD(&me->head); return &me->nd; } @@ -123,6 +124,7 @@ struct metric { * within the expression. */ struct expr_parse_ctx *pctx; + const char *pmu; /** The name of the metric such as "IPC". */ const char *metric_name; /** Modifier on the metric such as "u" or NULL for none. */ @@ -136,6 +138,11 @@ struct metric { * output. */ const char *metric_unit; + /** + * Optional name of the metric group reported + * if the Default metric group is being processed. + */ + const char *default_metricgroup_name; /** Optional null terminated array of referenced metrics. */ struct metric_ref *metric_refs; /** @@ -216,7 +223,9 @@ static struct metric *metric__new(const struct pmu_metric *pm, if (!m->pctx) goto out_err; + m->pmu = pm->pmu ?: "cpu"; m->metric_name = pm->metric_name; + m->default_metricgroup_name = pm->default_metricgroup_name; m->modifier = NULL; if (modifier) { m->modifier = strdup(modifier); @@ -259,11 +268,12 @@ static bool contains_metric_id(struct evsel **metric_events, int num_events, /** * setup_metric_events - Find a group of events in metric_evlist that correspond * to the IDs from a parsed metric expression. + * @pmu: The PMU for the IDs. * @ids: the metric IDs to match. * @metric_evlist: the list of perf events. * @out_metric_events: holds the created metric events array. */ -static int setup_metric_events(struct hashmap *ids, +static int setup_metric_events(const char *pmu, struct hashmap *ids, struct evlist *metric_evlist, struct evsel ***out_metric_events) { @@ -271,6 +281,7 @@ static int setup_metric_events(struct hashmap *ids, const char *metric_id; struct evsel *ev; size_t ids_size, matched_events, i; + bool all_pmus = !strcmp(pmu, "all") || perf_pmus__num_core_pmus() == 1 || !is_pmu_core(pmu); *out_metric_events = NULL; ids_size = hashmap__size(ids); @@ -283,6 +294,10 @@ static int setup_metric_events(struct hashmap *ids, 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_name && evsel__is_hybrid(ev) && + strcmp(ev->pmu_name, pmu)) + continue; /* * Check for duplicate events with the same name. For * example, uncore_imc/cas_count_read/ will turn into 6 @@ -298,6 +313,7 @@ static int setup_metric_events(struct hashmap *ids, * 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)); metric_events[matched_events++] = ev; if (matched_events >= ids_size) @@ -355,8 +371,13 @@ static bool match_metric(const char *n, const char *list) return false; } -static bool match_pm_metric(const struct pmu_metric *pm, const char *metric) +static bool match_pm_metric(const struct pmu_metric *pm, const char *pmu, const char *metric) { + const char *pm_pmu = pm->pmu ?: "cpu"; + + if (strcmp(pmu, "all") && strcmp(pm_pmu, pmu)) + return false; + return match_metric(pm->metric_group, metric) || match_metric(pm->metric_name, metric); } @@ -475,7 +496,7 @@ static int metricgroup__sys_event_iter(const struct pmu_metric *pm, if (!pm->metric_expr || !pm->compat) return 0; - while ((pmu = perf_pmu__scan(pmu))) { + while ((pmu = perf_pmus__scan(pmu))) { if (!pmu->id || strcmp(pmu->id, pm->compat)) continue; @@ -766,6 +787,7 @@ struct visited_metric { struct metricgroup_add_iter_data { struct list_head *metric_list; + const char *pmu; const char *metric_name; const char *modifier; int *ret; @@ -779,7 +801,8 @@ struct metricgroup_add_iter_data { const struct pmu_metrics_table *table; }; -static bool metricgroup__find_metric(const char *metric, +static bool metricgroup__find_metric(const char *pmu, + const char *metric, const struct pmu_metrics_table *table, struct pmu_metric *pm); @@ -798,6 +821,7 @@ static int add_metric(struct list_head *metric_list, * resolve_metric - Locate metrics within the root metric and recursively add * references to them. * @metric_list: The list the metric is added to. + * @pmu: The PMU name to resolve metrics on, or "all" for all PMUs. * @modifier: if non-null event modifiers like "u". * @metric_no_group: Should events written to events be grouped "{}" or * global. Grouping is the default but due to multiplexing the @@ -813,6 +837,7 @@ static int add_metric(struct list_head *metric_list, * architecture perf is running upon. */ static int resolve_metric(struct list_head *metric_list, + const char *pmu, const char *modifier, bool metric_no_group, bool metric_no_threshold, @@ -842,7 +867,7 @@ static int resolve_metric(struct list_head *metric_list, hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) { struct pmu_metric pm; - if (metricgroup__find_metric(cur->pkey, table, &pm)) { + if (metricgroup__find_metric(pmu, cur->pkey, table, &pm)) { pending = realloc(pending, (pending_cnt + 1) * sizeof(struct to_resolve)); if (!pending) @@ -993,9 +1018,12 @@ static int __add_metric(struct list_head *metric_list, } if (!ret) { /* Resolve referenced metrics. */ - ret = resolve_metric(metric_list, modifier, metric_no_group, + const char *pmu = pm->pmu ?: "cpu"; + + ret = resolve_metric(metric_list, pmu, modifier, metric_no_group, metric_no_threshold, user_requested_cpu_list, - system_wide, root_metric, &visited_node, table); + system_wide, root_metric, &visited_node, + table); } if (ret) { if (is_root) @@ -1008,6 +1036,7 @@ static int __add_metric(struct list_head *metric_list, } struct metricgroup__find_metric_data { + const char *pmu; const char *metric; struct pmu_metric *pm; }; @@ -1017,6 +1046,10 @@ static int metricgroup__find_metric_callback(const struct pmu_metric *pm, void *vdata) { struct metricgroup__find_metric_data *data = vdata; + const char *pm_pmu = pm->pmu ?: "cpu"; + + if (strcmp(data->pmu, "all") && strcmp(pm_pmu, data->pmu)) + return 0; if (!match_metric(pm->metric_name, data->metric)) return 0; @@ -1025,11 +1058,13 @@ static int metricgroup__find_metric_callback(const struct pmu_metric *pm, return 1; } -static bool metricgroup__find_metric(const char *metric, +static bool metricgroup__find_metric(const char *pmu, + const char *metric, const struct pmu_metrics_table *table, struct pmu_metric *pm) { struct metricgroup__find_metric_data data = { + .pmu = pmu, .metric = metric, .pm = pm, }; @@ -1083,7 +1118,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_metric *pm, struct metricgroup_add_iter_data *d = data; int ret; - if (!match_pm_metric(pm, d->metric_name)) + if (!match_pm_metric(pm, d->pmu, d->metric_name)) return 0; ret = add_metric(d->metric_list, pm, d->modifier, d->metric_no_group, @@ -1126,8 +1161,28 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, return right_count - left_count; } +/** + * default_metricgroup_cmp - Implements complex key for the Default metricgroup + * that first sorts by default_metricgroup_name, then + * metric_name. + */ +static int default_metricgroup_cmp(void *priv __maybe_unused, + const struct list_head *l, + const struct list_head *r) +{ + const struct metric *left = container_of(l, struct metric, nd); + const struct metric *right = container_of(r, struct metric, nd); + int diff = strcmp(right->default_metricgroup_name, left->default_metricgroup_name); + + if (diff) + return diff; + + return strcmp(right->metric_name, left->metric_name); +} + struct metricgroup__add_metric_data { struct list_head *list; + const char *pmu; const char *metric_name; const char *modifier; const char *user_requested_cpu_list; @@ -1144,9 +1199,9 @@ static int metricgroup__add_metric_callback(const struct pmu_metric *pm, struct metricgroup__add_metric_data *data = vdata; int ret = 0; - if (pm->metric_expr && match_pm_metric(pm, data->metric_name)) { + if (pm->metric_expr && match_pm_metric(pm, data->pmu, data->metric_name)) { bool metric_no_group = data->metric_no_group || - match_metric(data->metric_name, pm->metricgroup_no_group); + match_metric(pm->metricgroup_no_group, data->metric_name); data->has_match = true; ret = add_metric(data->list, pm, data->modifier, metric_no_group, @@ -1159,6 +1214,7 @@ static int metricgroup__add_metric_callback(const struct pmu_metric *pm, /** * metricgroup__add_metric - Find and add a metric, or a metric group. + * @pmu: The PMU name to search for metrics on, or "all" for all PMUs. * @metric_name: The name of the metric or metric group. For example, "IPC" * could be the name of a metric and "TopDownL1" the name of a * metric group. @@ -1172,7 +1228,7 @@ static int metricgroup__add_metric_callback(const struct pmu_metric *pm, * @table: The table that is searched for metrics, most commonly the table for the * architecture perf is running upon. */ -static int metricgroup__add_metric(const char *metric_name, const char *modifier, +static int metricgroup__add_metric(const char *pmu, const char *metric_name, const char *modifier, bool metric_no_group, bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, @@ -1186,6 +1242,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier { struct metricgroup__add_metric_data data = { .list = &list, + .pmu = pmu, .metric_name = metric_name, .modifier = modifier, .metric_no_group = metric_no_group, @@ -1210,6 +1267,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier .fn = metricgroup__add_metric_sys_event_iter, .data = (void *) &(struct metricgroup_add_iter_data) { .metric_list = &list, + .pmu = pmu, .metric_name = metric_name, .modifier = modifier, .metric_no_group = metric_no_group, @@ -1239,6 +1297,7 @@ out: /** * metricgroup__add_metric_list - Find and add metrics, or metric groups, * specified in a list. + * @pmu: A pmu to restrict the metrics to, or "all" for all PMUS. * @list: the list of metrics or metric groups. For example, "IPC,CPI,TopDownL1" * would match the IPC and CPI metrics, and TopDownL1 would match all * the metrics in the TopDownL1 group. @@ -1251,7 +1310,8 @@ out: * @table: The table that is searched for metrics, most commonly the table for the * architecture perf is running upon. */ -static int metricgroup__add_metric_list(const char *list, bool metric_no_group, +static int metricgroup__add_metric_list(const char *pmu, const char *list, + bool metric_no_group, bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct list_head *metric_list, @@ -1270,7 +1330,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group, if (modifier) *modifier++ = '\0'; - ret = metricgroup__add_metric(metric_name, modifier, + ret = metricgroup__add_metric(pmu, metric_name, modifier, metric_no_group, metric_no_threshold, user_requested_cpu_list, system_wide, metric_list, table); @@ -1441,8 +1501,8 @@ static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, } pr_debug("Parsing metric events '%s'\n", events.buf); parse_events_error__init(&parse_error); - ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu, - /*warn_if_reordered=*/false); + ret = __parse_events(parsed_evlist, events.buf, /*pmu_filter=*/NULL, + &parse_error, fake_pmu, /*warn_if_reordered=*/false); if (ret) { parse_events_error__print(&parse_error, events.buf); goto err_out; @@ -1460,7 +1520,8 @@ err_out: return ret; } -static int parse_groups(struct evlist *perf_evlist, const char *str, +static int parse_groups(struct evlist *perf_evlist, + const char *pmu, const char *str, bool metric_no_group, bool metric_no_merge, bool metric_no_threshold, @@ -1474,11 +1535,12 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, LIST_HEAD(metric_list); struct metric *m; bool tool_events[PERF_TOOL_MAX] = {false}; + bool is_default = !strcmp(str, "Default"); int ret; if (metric_events_list->nr_entries == 0) metricgroup__rblist_init(metric_events_list); - ret = metricgroup__add_metric_list(str, metric_no_group, metric_no_threshold, + ret = metricgroup__add_metric_list(pmu, str, metric_no_group, metric_no_threshold, user_requested_cpu_list, system_wide, &metric_list, table); if (ret) @@ -1508,6 +1570,9 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, goto out; } + if (is_default) + list_sort(NULL, &metric_list, default_metricgroup_cmp); + list_for_each_entry(m, &metric_list, nd) { struct metric_event *me; struct evsel **metric_events; @@ -1535,6 +1600,11 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, strcmp(m->modifier, n->modifier))) continue; + if ((!m->pmu && n->pmu) || + (m->pmu && !n->pmu) || + (m->pmu && n->pmu && strcmp(m->pmu, n->pmu))) + continue; + if (expr__subset_of_ids(n->pctx, m->pctx)) { pr_debug("Events in '%s' fully contained within '%s'\n", m->metric_name, n->metric_name); @@ -1552,9 +1622,10 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, metric_evlist = m->evlist; } - ret = setup_metric_events(m->pctx->ids, metric_evlist, &metric_events); + ret = setup_metric_events(fake_pmu ? "all" : m->pmu, m->pctx->ids, + metric_evlist, &metric_events); if (ret) { - pr_debug("Cannot resolve IDs for %s: %s\n", + pr_err("Cannot resolve IDs for %s: %s\n", m->metric_name, m->metric_expr); goto out; } @@ -1590,6 +1661,8 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, expr->metric_unit = m->metric_unit; expr->metric_events = metric_events; expr->runtime = m->pctx->sctx.runtime; + expr->default_metricgroup_name = m->default_metricgroup_name; + me->is_default = is_default; list_add(&expr->nd, &me->head); } @@ -1610,6 +1683,7 @@ out: } int metricgroup__parse_groups(struct evlist *perf_evlist, + const char *pmu, const char *str, bool metric_no_group, bool metric_no_merge, @@ -1623,7 +1697,7 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, if (!table) return -EINVAL; - return parse_groups(perf_evlist, str, metric_no_group, metric_no_merge, + return parse_groups(perf_evlist, pmu, str, metric_no_group, metric_no_merge, metric_no_threshold, user_requested_cpu_list, system_wide, /*fake_pmu=*/NULL, metric_events, table); } @@ -1633,7 +1707,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist, const char *str, struct rblist *metric_events) { - return parse_groups(evlist, str, + return parse_groups(evlist, "all", str, /*metric_no_group=*/false, /*metric_no_merge=*/false, /*metric_no_threshold=*/false, @@ -1642,28 +1716,32 @@ int metricgroup__parse_groups_test(struct evlist *evlist, &perf_pmu__fake, metric_events, table); } +struct metricgroup__has_metric_data { + const char *pmu; + const char *metric; +}; static int metricgroup__has_metric_callback(const struct pmu_metric *pm, const struct pmu_metrics_table *table __maybe_unused, void *vdata) { - const char *metric = vdata; + struct metricgroup__has_metric_data *data = vdata; - if (match_metric(pm->metric_name, metric) || - match_metric(pm->metric_group, metric)) - return 1; - - return 0; + return match_pm_metric(pm, data->pmu, data->metric) ? 1 : 0; } -bool metricgroup__has_metric(const char *metric) +bool metricgroup__has_metric(const char *pmu, const char *metric) { const struct pmu_metrics_table *table = pmu_metrics_table__find(); + struct metricgroup__has_metric_data data = { + .pmu = pmu, + .metric = metric, + }; if (!table) return false; - return pmu_metrics_table_for_each_metric(table, metricgroup__has_metric_callback, - (void *)metric) ? true : false; + return pmu_metrics_table_for_each_metric(table, metricgroup__has_metric_callback, &data) + ? true : false; } static int metricgroup__topdown_max_level_callback(const struct pmu_metric *pm, |