366 lines
14 KiB
Diff
366 lines
14 KiB
Diff
From af2d642045c3d5f3a7ab5a25c95b119f065cb94e Mon Sep 17 00:00:00 2001
|
|
From: Ian Rogers <irogers@google.com>
|
|
Date: Wed, 20 May 2020 11:20:10 -0700
|
|
Subject: [PATCH 084/201] perf metricgroup: Add options to not group or merge
|
|
|
|
mainline inclusion
|
|
from mainline-v5.8-rc1
|
|
commit 05530a7921c0f5149a01e34c4e031c5b18bdc1cc
|
|
category: feature
|
|
bugzilla: https://gitee.com/openeuler/kernel/issues/I8C0CX
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=05530a7921c0f5149a01e34c4e031c5b18bdc1cc
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Add --metric-no-group that causes all events within metrics to not be
|
|
grouped. This can allow the event to get more time when multiplexed, but
|
|
may also lower accuracy.
|
|
Add --metric-no-merge option. By default events in different metrics may
|
|
be shared if the group of events for one metric is the same or larger
|
|
than that of the second. Sharing may increase or lower accuracy and so
|
|
is now configurable.
|
|
|
|
Signed-off-by: Ian Rogers <irogers@google.com>
|
|
Acked-by: Jiri Olsa <jolsa@redhat.com>
|
|
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
|
Cc: Andi Kleen <ak@linux.intel.com>
|
|
Cc: Andrii Nakryiko <andriin@fb.com>
|
|
Cc: Cong Wang <xiyou.wangcong@gmail.com>
|
|
Cc: Jin Yao <yao.jin@linux.intel.com>
|
|
Cc: John Garry <john.garry@huawei.com>
|
|
Cc: Kajol Jain <kjain@linux.ibm.com>
|
|
Cc: Kan Liang <kan.liang@linux.intel.com>
|
|
Cc: Kim Phillips <kim.phillips@amd.com>
|
|
Cc: Mark Rutland <mark.rutland@arm.com>
|
|
Cc: Namhyung Kim <namhyung@kernel.org>
|
|
Cc: Paul Clarke <pc@us.ibm.com>
|
|
Cc: Peter Zijlstra <peterz@infradead.org>
|
|
Cc: Song Liu <songliubraving@fb.com>
|
|
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
|
|
Cc: Stephane Eranian <eranian@google.com>
|
|
Cc: Vince Weaver <vincent.weaver@maine.edu>
|
|
Cc: bpf@vger.kernel.org
|
|
Cc: netdev@vger.kernel.org
|
|
Link: http://lore.kernel.org/lkml/20200520182011.32236-7-irogers@google.com
|
|
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Signed-off-by: hongrongxuan <hongrongxuan@huawei.com>
|
|
|
|
Conflicts:
|
|
tools/perf/util/metricgroup.c
|
|
tools/perf/util/stat.h
|
|
---
|
|
tools/perf/Documentation/perf-stat.txt | 19 +++++++
|
|
tools/perf/builtin-stat.c | 11 ++++-
|
|
tools/perf/util/metricgroup.c | 68 ++++++++++++++++++++------
|
|
tools/perf/util/metricgroup.h | 6 ++-
|
|
tools/perf/util/stat.h | 20 ++++----
|
|
5 files changed, 96 insertions(+), 28 deletions(-)
|
|
|
|
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
|
|
index b10a90b6a718..a5c61d03db59 100644
|
|
--- a/tools/perf/Documentation/perf-stat.txt
|
|
+++ b/tools/perf/Documentation/perf-stat.txt
|
|
@@ -217,6 +217,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 0d8943ead576..56f62a9d0f0d 100644
|
|
--- a/tools/perf/builtin-stat.c
|
|
+++ b/tools/perf/builtin-stat.c
|
|
@@ -1981,7 +1981,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[] = {
|
|
@@ -2054,6 +2057,10 @@ static struct option stat_options[] = {
|
|
"ms to wait before starting measurement after program start"),
|
|
OPT_CALLBACK_NOOPT(0, "metric-only", &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,
|
|
@@ -2437,6 +2444,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 65f96cfa4183..249233acb715 100644
|
|
--- a/tools/perf/util/metricgroup.c
|
|
+++ b/tools/perf/util/metricgroup.c
|
|
@@ -101,11 +101,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
|
|
@@ -115,6 +119,7 @@ struct egroup {
|
|
*/
|
|
static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
|
|
struct expr_parse_ctx *pctx,
|
|
+ bool metric_no_merge,
|
|
bool has_constraint,
|
|
struct perf_evsel **metric_events,
|
|
unsigned long *evlist_used)
|
|
@@ -138,6 +143,9 @@ static struct perf_evsel *find_evsel_group(struct perf_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
|
|
@@ -148,8 +156,23 @@ static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
|
|
sizeof(struct perf_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;
|
|
}
|
|
@@ -181,6 +204,7 @@ static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
|
|
}
|
|
|
|
static int metricgroup__setup_events(struct list_head *groups,
|
|
+ bool metric_no_merge,
|
|
struct perf_evlist *perf_evlist,
|
|
struct rblist *metric_events_list)
|
|
{
|
|
@@ -206,8 +230,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);
|
|
@@ -530,7 +555,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;
|
|
|
|
@@ -543,7 +570,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);
|
|
@@ -570,7 +597,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);
|
|
@@ -600,7 +628,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 {
|
|
@@ -615,7 +645,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;
|
|
}
|
|
@@ -637,7 +668,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;
|
|
@@ -652,7 +684,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);
|
|
@@ -679,8 +712,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 perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value;
|
|
@@ -690,7 +725,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);
|
|
@@ -701,8 +737,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 f2a17a05eb81..b6dfd7d09b9c 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 perf_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 8a7d8425acf8..fbbc47ed5d3f 100644
|
|
--- a/tools/perf/util/stat.h
|
|
+++ b/tools/perf/util/stat.h
|
|
@@ -85,15 +85,17 @@ struct runtime_stat {
|
|
};
|
|
|
|
struct perf_stat_config {
|
|
- enum aggr_mode aggr_mode;
|
|
- bool scale;
|
|
- FILE *output;
|
|
- unsigned int interval;
|
|
- unsigned int timeout;
|
|
- int times;
|
|
- struct runtime_stat *stats;
|
|
- int stats_num;
|
|
- struct rblist metric_events;
|
|
+ enum aggr_mode aggr_mode;
|
|
+ bool scale;
|
|
+ bool metric_no_group;
|
|
+ bool metric_no_merge;
|
|
+ FILE *output;
|
|
+ unsigned int interval;
|
|
+ unsigned int timeout;
|
|
+ int times;
|
|
+ struct runtime_stat *stats;
|
|
+ int stats_num;
|
|
+ struct rblist metric_events;
|
|
};
|
|
|
|
void update_stats(struct stats *stats, u64 val);
|
|
--
|
|
2.27.0
|
|
|