310 lines
8.2 KiB
Diff
310 lines
8.2 KiB
Diff
From 2b09c4be3626223ad986b311085f7c5d8a26d975 Mon Sep 17 00:00:00 2001
|
|
From: Jiri Olsa <jolsa@kernel.org>
|
|
Date: Sun, 19 Jul 2020 20:13:09 +0200
|
|
Subject: [PATCH 114/201] perf metric: Collect referenced metrics in struct
|
|
metric_ref_node
|
|
|
|
mainline inclusion
|
|
from mainline-v5.9-rc1
|
|
commit a29c164aa3163f8ffbc36db3e57296eff95a8087
|
|
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=a29c164aa3163f8ffbc36db3e57296eff95a8087
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Collecting referenced metrics in struct metric_ref_node object,
|
|
so we can process them later on.
|
|
|
|
The change will parse nested metric names out of expression and
|
|
'resolve' them.
|
|
|
|
All referenced metrics are dissolved into one context, meaning all
|
|
nested metrics events and added to the parent context.
|
|
|
|
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
|
|
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
|
Cc: Andi Kleen <ak@linux.intel.com>
|
|
Cc: John Garry <john.garry@huawei.com>
|
|
Cc: Michael Petlan <mpetlan@redhat.com>
|
|
Cc: Namhyung Kim <namhyung@kernel.org>
|
|
Cc: Paul Clarke <pc@us.ibm.com>
|
|
Cc: Peter Zijlstra <peterz@infradead.org>
|
|
Cc: Stephane Eranian <eranian@google.com>
|
|
Link: http://lore.kernel.org/lkml/20200719181320.785305-9-jolsa@kernel.org
|
|
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Signed-off-by: hongrongxuan <hongrongxuan@huawei.com>
|
|
---
|
|
tools/perf/util/metricgroup.c | 188 +++++++++++++++++++++++++++++++---
|
|
1 file changed, 172 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
|
|
index 4081999a05af..9bb402fc03ab 100644
|
|
--- a/tools/perf/util/metricgroup.c
|
|
+++ b/tools/perf/util/metricgroup.c
|
|
@@ -108,12 +108,25 @@ void metricgroup__rblist_exit(struct rblist *metric_events)
|
|
rblist__exit(metric_events);
|
|
}
|
|
|
|
+/*
|
|
+ * A node in the list of referenced metrics. metric_expr
|
|
+ * is held as a convenience to avoid a search through the
|
|
+ * metric list.
|
|
+ */
|
|
+struct metric_ref_node {
|
|
+ const char *metric_name;
|
|
+ const char *metric_expr;
|
|
+ struct list_head list;
|
|
+};
|
|
+
|
|
struct egroup {
|
|
struct list_head nd;
|
|
struct expr_parse_ctx pctx;
|
|
const char *metric_name;
|
|
const char *metric_expr;
|
|
const char *metric_unit;
|
|
+ struct list_head metric_refs;
|
|
+ int metric_refs_cnt;
|
|
int runtime;
|
|
bool has_constraint;
|
|
};
|
|
@@ -581,27 +594,72 @@ int __weak arch_get_runtimeparam(void)
|
|
static int __add_metric(struct list_head *group_list,
|
|
struct pmu_event *pe,
|
|
bool metric_no_group,
|
|
- int runtime)
|
|
+ int runtime,
|
|
+ struct egroup **egp)
|
|
{
|
|
+ struct metric_ref_node *ref;
|
|
struct egroup *eg;
|
|
|
|
- eg = malloc(sizeof(*eg));
|
|
- if (!eg)
|
|
- return -ENOMEM;
|
|
+ if (*egp == NULL) {
|
|
+ /*
|
|
+ * We got in here for the parent group,
|
|
+ * allocate it and put it on the list.
|
|
+ */
|
|
+ eg = malloc(sizeof(*eg));
|
|
+ if (!eg)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ expr__ctx_init(&eg->pctx);
|
|
+ eg->metric_name = pe->metric_name;
|
|
+ eg->metric_expr = pe->metric_expr;
|
|
+ eg->metric_unit = pe->unit;
|
|
+ eg->runtime = runtime;
|
|
+ eg->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
|
|
+ INIT_LIST_HEAD(&eg->metric_refs);
|
|
+ eg->metric_refs_cnt = 0;
|
|
+ *egp = eg;
|
|
+ } else {
|
|
+ /*
|
|
+ * We got here for the referenced metric, via the
|
|
+ * recursive metricgroup__add_metric call, add
|
|
+ * it to the parent group.
|
|
+ */
|
|
+ eg = *egp;
|
|
+
|
|
+ ref = malloc(sizeof(*ref));
|
|
+ if (!ref)
|
|
+ return -ENOMEM;
|
|
|
|
- expr__ctx_init(&eg->pctx);
|
|
- eg->metric_name = pe->metric_name;
|
|
- eg->metric_expr = pe->metric_expr;
|
|
- eg->metric_unit = pe->unit;
|
|
- eg->runtime = runtime;
|
|
- eg->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
|
|
+ /*
|
|
+ * Intentionally passing just const char pointers,
|
|
+ * from 'pe' object, so they never go away. We don't
|
|
+ * need to change them, so there's no need to create
|
|
+ * our own copy.
|
|
+ */
|
|
+ ref->metric_name = pe->metric_name;
|
|
+ ref->metric_expr = pe->metric_expr;
|
|
+
|
|
+ list_add(&ref->list, &eg->metric_refs);
|
|
+ eg->metric_refs_cnt++;
|
|
+ }
|
|
|
|
+ /*
|
|
+ * For both the parent and referenced metrics, we parse
|
|
+ * all the metric's IDs and add it to the parent context.
|
|
+ */
|
|
if (expr__find_other(pe->metric_expr, NULL, &eg->pctx, runtime) < 0) {
|
|
expr__ctx_clear(&eg->pctx);
|
|
free(eg);
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ /*
|
|
+ * We add new group only in the 'parent' call,
|
|
+ * so bail out for referenced metric case.
|
|
+ */
|
|
+ if (eg->metric_refs_cnt)
|
|
+ return 0;
|
|
+
|
|
if (list_empty(group_list))
|
|
list_add(&eg->nd, group_list);
|
|
else {
|
|
@@ -632,16 +690,94 @@ static int __add_metric(struct list_head *group_list,
|
|
(match_metric(__pe->metric_group, __metric) || \
|
|
match_metric(__pe->metric_name, __metric)))
|
|
|
|
+static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *map)
|
|
+{
|
|
+ struct pmu_event *pe;
|
|
+ int i;
|
|
+
|
|
+ map_for_each_event(pe, i, map) {
|
|
+ if (match_metric(pe->metric_name, metric))
|
|
+ return pe;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static int add_metric(struct list_head *group_list,
|
|
struct pmu_event *pe,
|
|
- bool metric_no_group)
|
|
+ bool metric_no_group,
|
|
+ struct egroup **egp);
|
|
+
|
|
+static int __resolve_metric(struct egroup *eg,
|
|
+ bool metric_no_group,
|
|
+ struct list_head *group_list,
|
|
+ struct pmu_events_map *map)
|
|
{
|
|
+ struct hashmap_entry *cur;
|
|
+ size_t bkt;
|
|
+ bool all;
|
|
+ int ret;
|
|
+
|
|
+ /*
|
|
+ * Iterate all the parsed IDs and if there's metric,
|
|
+ * add it to the context.
|
|
+ */
|
|
+ do {
|
|
+ all = true;
|
|
+ hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
|
|
+ struct pmu_event *pe;
|
|
+
|
|
+ pe = find_metric(cur->key, map);
|
|
+ if (!pe)
|
|
+ continue;
|
|
+
|
|
+ all = false;
|
|
+ /* The metric key itself needs to go out.. */
|
|
+ expr__del_id(&eg->pctx, cur->key);
|
|
+
|
|
+ /* ... and it gets resolved to the parent context. */
|
|
+ ret = add_metric(group_list, pe, metric_no_group, &eg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /*
|
|
+ * We added new metric to hashmap, so we need
|
|
+ * to break the iteration and start over.
|
|
+ */
|
|
+ break;
|
|
+ }
|
|
+ } while (!all);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int resolve_metric(bool metric_no_group,
|
|
+ struct list_head *metric_list,
|
|
+ struct pmu_events_map *map)
|
|
+{
|
|
+ struct egroup *eg;
|
|
+ int err;
|
|
+
|
|
+ list_for_each_entry(eg, metric_list, nd) {
|
|
+ err = __resolve_metric(eg, metric_no_group, metric_list, map);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int add_metric(struct list_head *group_list,
|
|
+ struct pmu_event *pe,
|
|
+ bool metric_no_group,
|
|
+ struct egroup **egp)
|
|
+{
|
|
+ struct egroup *orig = *egp;
|
|
int ret = 0;
|
|
|
|
pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
|
|
|
|
if (!strstr(pe->metric_expr, "?")) {
|
|
- ret = __add_metric(group_list, pe, metric_no_group, 1);
|
|
+ ret = __add_metric(group_list, pe, metric_no_group, 1, egp);
|
|
} else {
|
|
int j, count;
|
|
|
|
@@ -652,9 +788,8 @@ static int add_metric(struct list_head *group_list,
|
|
* those events to group_list.
|
|
*/
|
|
|
|
- for (j = 0; j < count && !ret; j++) {
|
|
- ret = __add_metric(group_list, pe, metric_no_group, j);
|
|
- }
|
|
+ for (j = 0; j < count && !ret; j++, *egp = orig)
|
|
+ ret = __add_metric(group_list, pe, metric_no_group, j, egp);
|
|
}
|
|
|
|
return ret;
|
|
@@ -672,8 +807,18 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
|
|
|
|
map_for_each_metric(pe, i, map, metric) {
|
|
has_match = true;
|
|
+ eg = NULL;
|
|
+
|
|
+ ret = add_metric(group_list, pe, metric_no_group, &eg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
- ret = add_metric(group_list, pe, metric_no_group);
|
|
+ /*
|
|
+ * Process any possible referenced metrics
|
|
+ * included in the expression.
|
|
+ */
|
|
+ ret = resolve_metric(metric_no_group,
|
|
+ group_list, map);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
@@ -730,11 +875,22 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
|
|
return ret;
|
|
}
|
|
|
|
+static void egroup__free_refs(struct egroup *egroup)
|
|
+{
|
|
+ struct metric_ref_node *ref, *tmp;
|
|
+
|
|
+ list_for_each_entry_safe(ref, tmp, &egroup->metric_refs, list) {
|
|
+ list_del(&ref->list);
|
|
+ free(ref);
|
|
+ }
|
|
+}
|
|
+
|
|
static void metricgroup__free_egroups(struct list_head *group_list)
|
|
{
|
|
struct egroup *eg, *egtmp;
|
|
|
|
list_for_each_entry_safe (eg, egtmp, group_list, nd) {
|
|
+ egroup__free_refs(eg);
|
|
expr__ctx_clear(&eg->pctx);
|
|
list_del_init(&eg->nd);
|
|
free(eg);
|
|
--
|
|
2.27.0
|
|
|