diff options
-rw-r--r-- | tools/perf/Documentation/perf-stat.txt | 19 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 11 | ||||
-rw-r--r-- | tools/perf/util/metricgroup.c | 68 | ||||
-rw-r--r-- | tools/perf/util/metricgroup.h | 6 | ||||
-rw-r--r-- | tools/perf/util/stat.h | 2 |
5 files changed, 87 insertions, 19 deletions
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 77081283856d..498bead1ef3b 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -236,6 +236,25 @@ filter out the startup phase of the program, which is often very different. Print statistics of transactional execution if supported. +--metric-no-group:: +By default, events to compute a metric are placed in weak groups. The +group tries to enforce scheduling all or none of the events. The +--metric-no-group option places events outside of groups and may +increase the chance of the event being scheduled - leading to more +accuracy. However, as events may not be scheduled together accuracy +for metrics like instructions per cycle can be lower - as both metrics +may no longer be being measured at the same time. + +--metric-no-merge:: +By default metric events in different weak groups can be shared if one +group contains all the events needed by another. In such cases one +group will be eliminated reducing event multiplexing and making it so +that certain groups of metrics sum to 100%. A downside to sharing a +group is that the group may require multiplexing and so accuracy for a +small group that need not have multiplexing is lowered. This option +forbids the event merging logic from sharing events between groups and +may be used to increase accuracy in this case. + STAT RECORD ----------- Stores stat data into perf data file. diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 377e575f9645..f789103d8306 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -910,7 +910,10 @@ static int parse_metric_groups(const struct option *opt, const char *str, int unset __maybe_unused) { - return metricgroup__parse_groups(opt, str, &stat_config.metric_events); + return metricgroup__parse_groups(opt, str, + stat_config.metric_no_group, + stat_config.metric_no_merge, + &stat_config.metric_events); } static struct option stat_options[] = { @@ -988,6 +991,10 @@ static struct option stat_options[] = { "ms to wait before starting measurement after program start"), OPT_CALLBACK_NOOPT(0, "metric-only", &stat_config.metric_only, NULL, "Only print computed metrics. No raw values", enable_metric_only), + OPT_BOOLEAN(0, "metric-no-group", &stat_config.metric_no_group, + "don't group metric events, impacts multiplexing"), + OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge, + "don't try to share events between metrics in a group"), OPT_BOOLEAN(0, "topdown", &topdown_run, "measure topdown level 1 statistics"), OPT_BOOLEAN(0, "smi-cost", &smi_cost, @@ -1512,6 +1519,8 @@ static int add_default_attributes(void) struct option opt = { .value = &evsel_list }; return metricgroup__parse_groups(&opt, "transaction", + stat_config.metric_no_group, + stat_config.metric_no_merge, &stat_config.metric_events); } diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 9036419cc377..8f8f527eb75f 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -95,11 +95,15 @@ struct egroup { /** * Find a group of events in perf_evlist that correpond to those from a parsed - * metric expression. + * metric expression. Note, as find_evsel_group is called in the same order as + * perf_evlist was constructed, metric_no_merge doesn't need to test for + * underfilling a group. * @perf_evlist: a list of events something like: {metric1 leader, metric1 * sibling, metric1 sibling}:W,duration_time,{metric2 leader, metric2 sibling, * metric2 sibling}:W,duration_time * @pctx: the parse context for the metric expression. + * @metric_no_merge: don't attempt to share events for the metric with other + * metrics. * @has_constraint: is there a contraint on the group of events? In which case * the events won't be grouped. * @metric_events: out argument, null terminated array of evsel's associated @@ -109,6 +113,7 @@ struct egroup { */ static struct evsel *find_evsel_group(struct evlist *perf_evlist, struct expr_parse_ctx *pctx, + bool metric_no_merge, bool has_constraint, struct evsel **metric_events, unsigned long *evlist_used) @@ -132,6 +137,9 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, */ if (has_constraint && ev->weak_group) continue; + /* Ignore event if already used and merging is disabled. */ + if (metric_no_merge && test_bit(ev->idx, evlist_used)) + continue; if (!has_constraint && ev->leader != current_leader) { /* * Start of a new group, discard the whole match and @@ -142,8 +150,23 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, sizeof(struct evsel *) * idnum); current_leader = ev->leader; } - if (hashmap__find(&pctx->ids, ev->name, (void **)&val_ptr)) + if (hashmap__find(&pctx->ids, ev->name, (void **)&val_ptr)) { + if (has_constraint) { + /* + * Events aren't grouped, ensure the same event + * isn't matched from two groups. + */ + for (i = 0; i < matched_events; i++) { + if (!strcmp(ev->name, + metric_events[i]->name)) { + break; + } + } + if (i != matched_events) + continue; + } metric_events[matched_events++] = ev; + } if (matched_events == events_to_match) break; } @@ -175,6 +198,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, } static int metricgroup__setup_events(struct list_head *groups, + bool metric_no_merge, struct evlist *perf_evlist, struct rblist *metric_events_list) { @@ -200,8 +224,9 @@ static int metricgroup__setup_events(struct list_head *groups, break; } evsel = find_evsel_group(perf_evlist, &eg->pctx, - eg->has_constraint, metric_events, - evlist_used); + metric_no_merge, + eg->has_constraint, metric_events, + evlist_used); if (!evsel) { pr_debug("Cannot resolve %s: %s\n", eg->metric_name, eg->metric_expr); @@ -523,7 +548,9 @@ int __weak arch_get_runtimeparam(void) } static int __metricgroup__add_metric(struct list_head *group_list, - struct pmu_event *pe, int runtime) + struct pmu_event *pe, + bool metric_no_group, + int runtime) { struct egroup *eg; @@ -536,7 +563,7 @@ static int __metricgroup__add_metric(struct list_head *group_list, eg->metric_expr = pe->metric_expr; eg->metric_unit = pe->unit; eg->runtime = runtime; - eg->has_constraint = metricgroup__has_constraint(pe); + eg->has_constraint = metric_no_group || metricgroup__has_constraint(pe); if (expr__find_other(pe->metric_expr, NULL, &eg->pctx, runtime) < 0) { expr__ctx_clear(&eg->pctx); @@ -563,7 +590,8 @@ static int __metricgroup__add_metric(struct list_head *group_list, return 0; } -static int metricgroup__add_metric(const char *metric, struct strbuf *events, +static int metricgroup__add_metric(const char *metric, bool metric_no_group, + struct strbuf *events, struct list_head *group_list) { struct pmu_events_map *map = perf_pmu__find_map(NULL); @@ -593,7 +621,9 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events, if (!strstr(pe->metric_expr, "?")) { ret = __metricgroup__add_metric(group_list, - pe, 1); + pe, + metric_no_group, + 1); if (ret) return ret; } else { @@ -608,7 +638,8 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events, for (j = 0; j < count; j++) { ret = __metricgroup__add_metric( - group_list, pe, j); + group_list, pe, + metric_no_group, j); if (ret) return ret; } @@ -630,7 +661,8 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events, return 0; } -static int metricgroup__add_metric_list(const char *list, struct strbuf *events, +static int metricgroup__add_metric_list(const char *list, bool metric_no_group, + struct strbuf *events, struct list_head *group_list) { char *llist, *nlist, *p; @@ -645,7 +677,8 @@ static int metricgroup__add_metric_list(const char *list, struct strbuf *events, strbuf_addf(events, "%s", ""); while ((p = strsep(&llist, ",")) != NULL) { - ret = metricgroup__add_metric(p, events, group_list); + ret = metricgroup__add_metric(p, metric_no_group, events, + group_list); if (ret == -EINVAL) { fprintf(stderr, "Cannot find metric or group `%s'\n", p); @@ -672,8 +705,10 @@ static void metricgroup__free_egroups(struct list_head *group_list) } int metricgroup__parse_groups(const struct option *opt, - const char *str, - struct rblist *metric_events) + const char *str, + bool metric_no_group, + bool metric_no_merge, + struct rblist *metric_events) { struct parse_events_error parse_error; struct evlist *perf_evlist = *(struct evlist **)opt->value; @@ -683,7 +718,8 @@ int metricgroup__parse_groups(const struct option *opt, if (metric_events->nr_entries == 0) metricgroup__rblist_init(metric_events); - ret = metricgroup__add_metric_list(str, &extra_events, &group_list); + ret = metricgroup__add_metric_list(str, metric_no_group, + &extra_events, &group_list); if (ret) return ret; pr_debug("adding %s\n", extra_events.buf); @@ -694,8 +730,8 @@ int metricgroup__parse_groups(const struct option *opt, goto out; } strbuf_release(&extra_events); - ret = metricgroup__setup_events(&group_list, perf_evlist, - metric_events); + ret = metricgroup__setup_events(&group_list, metric_no_merge, + perf_evlist, metric_events); out: metricgroup__free_egroups(&group_list); return ret; diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 6b09eb30b4ec..287850bcdeca 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -29,8 +29,10 @@ struct metric_event *metricgroup__lookup(struct rblist *metric_events, struct evsel *evsel, bool create); int metricgroup__parse_groups(const struct option *opt, - const char *str, - struct rblist *metric_events); + const char *str, + bool metric_no_group, + bool metric_no_merge, + struct rblist *metric_events); void metricgroup__print(bool metrics, bool groups, char *filter, bool raw, bool details); diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index ddf188cda631..f75ae679eb28 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -111,6 +111,8 @@ struct perf_stat_config { bool all_user; bool percore_show_thread; bool summary; + bool metric_no_group; + bool metric_no_merge; FILE *output; unsigned int interval; unsigned int timeout; |