linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv3 00/19] perf metric: Add support to reuse metric
@ 2020-07-19 18:13 Jiri Olsa
  2020-07-19 18:13 ` [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function Jiri Olsa
                   ` (20 more replies)
  0 siblings, 21 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

hi,
this patchset is adding the support to reused metric in
another metric.

For example, to define IPC by using CPI with change like:

     {
         "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
-        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricExpr": "1/CPI",
         "MetricGroup": "TopDownL1",
         "MetricName": "IPC"
     },

I won't be able to find all the possible places we could
use this at, so I wonder you guys (who was asking for this)
would try it and come up with comments if there's something
missing or we could already use it at some places.

It's based on Arnaldo's tmp.perf/core.

v3 changes:
  - added some acks
  - some patches got merged
  - added missing zalloc include [John Garry]
  - added ids array outside the egroup object [Ian]
  - removed wrong m->has_constraint assignment [Ian]
  - renamed 'list' to 'metric_list' [Ian]
  - fixed group metric and added test for it [Paul A. Clarke]
  - fixed memory leak [Arnaldo]
  - using lowercase keys for metrics in hashmap, because jevents
    converts metric_expr to lowercase

Also available in here:
  git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
  perf/metric

thanks,
jirka


---
Jiri Olsa (19):
      perf metric: Fix memory leak in expr__add_id function
      perf metric: Add expr__add_id function
      perf metric: Change expr__get_id to return struct expr_id_data
      perf metric: Add expr__del_id function
      perf metric: Add macros for iterating map events
      perf metric: Add add_metric function
      perf metric: Rename __metricgroup__add_metric to __add_metric
      perf metric: Collect referenced metrics in struct metric_ref_node
      perf metric: Collect referenced metrics in struct metric_expr
      perf metric: Add referenced metrics to hash data
      perf metric: Compute referenced metrics
      perf metric: Add events for the current list
      perf metric: Add cache_miss_cycles to metric parse test
      perf metric: Add DCache_L2 to metric parse test
      perf metric: Add recursion check when processing nested metrics
      perf metric: Make compute_single function more precise
      perf metric: Add metric group test
      perf metric: Rename struct egroup to metric
      perf metric: Rename group_list to metric_list

 tools/perf/tests/parse-metric.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++----
 tools/perf/util/expr.c          | 143 ++++++++++++++++++++++++++++++++-----
 tools/perf/util/expr.h          |  30 +++++++-
 tools/perf/util/expr.y          |  16 +++--
 tools/perf/util/metricgroup.c   | 466 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
 tools/perf/util/metricgroup.h   |   6 ++
 tools/perf/util/stat-shadow.c   |  20 ++++--
 7 files changed, 751 insertions(+), 136 deletions(-)


^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 21:41   ` Ian Rogers
  2020-07-19 18:13 ` [PATCH 02/19] perf metric: Add " Jiri Olsa
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers

Arnaldo found that we don't release value data in case the
hashmap__set fails. Releasing it in case of an error.

Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/expr.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 5d05f9765ed8..578a173d4873 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -47,6 +47,8 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
 	}
 	ret = hashmap__set(&ctx->ids, id, data_ptr,
 			   (const void **)&old_key, (void **)&old_data);
+	if (ret)
+		free(data_ptr);
 	free(old_key);
 	free(old_data);
 	return ret;
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 02/19] perf metric: Add expr__add_id function
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
  2020-07-19 18:13 ` [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:16   ` kajoljain
  2020-07-19 18:13 ` [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data Jiri Olsa
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Adding expr__add_id function to data for ID
with zero value, which is used when scanning
the expression for IDs.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/expr.c | 31 +++++++++++++++++++++++++------
 tools/perf/util/expr.h |  1 +
 tools/perf/util/expr.y |  2 +-
 3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 578a173d4873..9228f60e2a20 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -32,6 +32,26 @@ static bool key_equal(const void *key1, const void *key2,
 	return !strcmp((const char *)key1, (const char *)key2);
 }
 
+/* Caller must make sure id is allocated */
+int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
+{
+	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
+	char *old_key = NULL;
+	int ret;
+
+	data_ptr = malloc(sizeof(*data_ptr));
+	if (!data_ptr)
+		return -ENOMEM;
+
+	ret = hashmap__set(&ctx->ids, id, data_ptr,
+			   (const void **)&old_key, (void **)&old_data);
+	if (ret)
+		free(data_ptr);
+	free(old_key);
+	free(old_data);
+	return ret;
+}
+
 /* Caller must make sure id is allocated */
 int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
 {
@@ -39,12 +59,11 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
 	char *old_key = NULL;
 	int ret;
 
-	if (val != 0.0) {
-		data_ptr = malloc(sizeof(*data_ptr));
-		if (!data_ptr)
-			return -ENOMEM;
-		data_ptr->val = val;
-	}
+	data_ptr = malloc(sizeof(*data_ptr));
+	if (!data_ptr)
+		return -ENOMEM;
+	data_ptr->val = val;
+
 	ret = hashmap__set(&ctx->ids, id, data_ptr,
 			   (const void **)&old_key, (void **)&old_data);
 	if (ret)
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 21fe5bd85718..ac32cda42006 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -26,6 +26,7 @@ struct expr_scanner_ctx {
 
 void expr__ctx_init(struct expr_parse_ctx *ctx);
 void expr__ctx_clear(struct expr_parse_ctx *ctx);
+int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
 int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
 int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr);
 int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index b2b3420ea6ec..8befe4a46f87 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -69,7 +69,7 @@ all_other: all_other other
 
 other: ID
 {
-	expr__add_id_val(ctx, $1, 0.0);
+	expr__add_id(ctx, $1);
 }
 |
 MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ','
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
  2020-07-19 18:13 ` [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function Jiri Olsa
  2020-07-19 18:13 ` [PATCH 02/19] perf metric: Add " Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:17   ` kajoljain
  2020-07-19 18:13 ` [PATCH 04/19] perf metric: Add expr__del_id function Jiri Olsa
                   ` (17 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Changing expr__get_id to use and return struct expr_id_data
pointer as value for the ID. This way we can access data other
than value for given ID in following changes.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/expr.c | 10 +++-------
 tools/perf/util/expr.h |  3 ++-
 tools/perf/util/expr.y | 14 +++++++++-----
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 9228f60e2a20..4e5a6533dfce 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -73,14 +73,10 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
 	return ret;
 }
 
-int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr)
+int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
+		 struct expr_id_data **data)
 {
-	struct expr_id_data *data;
-
-	if (!hashmap__find(&ctx->ids, id, (void **)&data))
-		return -1;
-	*val_ptr = (data == NULL) ?  0.0 : data->val;
-	return 0;
+	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
 }
 
 void expr__ctx_init(struct expr_parse_ctx *ctx)
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index ac32cda42006..f38292fdab19 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -28,7 +28,8 @@ void expr__ctx_init(struct expr_parse_ctx *ctx);
 void expr__ctx_clear(struct expr_parse_ctx *ctx);
 int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
 int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
-int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr);
+int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
+		 struct expr_id_data **data);
 int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
 		const char *expr, int runtime);
 int expr__find_other(const char *expr, const char *one,
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index 8befe4a46f87..0d4f5d324be7 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -85,12 +85,16 @@ if_expr:
 	;
 
 expr:	  NUMBER
-	| ID			{ if (expr__get_id(ctx, $1, &$$)) {
-					pr_debug("%s not found\n", $1);
+	| ID			{
+					struct expr_id_data *data;
+
+					if (expr__get_id(ctx, $1, &data) || !data) {
+						pr_debug("%s not found\n", $1);
+						free($1);
+						YYABORT;
+					}
+					$$ = data->val;
 					free($1);
-					YYABORT;
-				  }
-				  free($1);
 				}
 	| expr '|' expr		{ $$ = (long)$1 | (long)$3; }
 	| expr '&' expr		{ $$ = (long)$1 & (long)$3; }
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 04/19] perf metric: Add expr__del_id function
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (2 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:17   ` kajoljain
  2020-07-19 18:13 ` [PATCH 05/19] perf metric: Add macros for iterating map events Jiri Olsa
                   ` (16 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Adding expr__del_id function to remove ID from hashmap.
It will save us few lines in following changes.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/expr.c | 21 +++++++++++++--------
 tools/perf/util/expr.h |  1 +
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 4e5a6533dfce..f726211f49d4 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -79,6 +79,17 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
 }
 
+void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
+{
+	struct expr_id_data *old_val = NULL;
+	char *old_key = NULL;
+
+	hashmap__delete(&ctx->ids, id,
+			(const void **)&old_key, (void **)&old_val);
+	free(old_key);
+	free(old_val);
+}
+
 void expr__ctx_init(struct expr_parse_ctx *ctx)
 {
 	hashmap__init(&ctx->ids, key_hash, key_equal, NULL);
@@ -136,16 +147,10 @@ int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
 int expr__find_other(const char *expr, const char *one,
 		     struct expr_parse_ctx *ctx, int runtime)
 {
-	struct expr_id_data *old_val = NULL;
-	char *old_key = NULL;
 	int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime);
 
-	if (one) {
-		hashmap__delete(&ctx->ids, one,
-				(const void **)&old_key, (void **)&old_val);
-		free(old_key);
-		free(old_val);
-	}
+	if (one)
+		expr__del_id(ctx, one);
 
 	return ret;
 }
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index f38292fdab19..2462abd0ac65 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -26,6 +26,7 @@ struct expr_scanner_ctx {
 
 void expr__ctx_init(struct expr_parse_ctx *ctx);
 void expr__ctx_clear(struct expr_parse_ctx *ctx);
+void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
 int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
 int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
 int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 05/19] perf metric: Add macros for iterating map events
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (3 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 04/19] perf metric: Add expr__del_id function Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 21:46   ` Ian Rogers
  2020-07-26  9:17   ` kajoljain
  2020-07-19 18:13 ` [PATCH 06/19] perf metric: Add add_metric function Jiri Olsa
                   ` (15 subsequent siblings)
  20 siblings, 2 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Adding following macros to iterate events and metric:
  map_for_each_event(__pe, __idx, __map)
    - iterates over all pmu_events_map events
  map_for_each_metric(__pe, __idx, __map, __metric)
    - iterates over all metrics that match __metric argument

and use it in metricgroup__add_metric function. Macros
will be be used from other places in following changes.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 77 ++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 37 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index df0356ec120d..b37008fc253c 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -614,6 +614,17 @@ static int __metricgroup__add_metric(struct list_head *group_list,
 	return 0;
 }
 
+#define map_for_each_event(__pe, __idx, __map)				\
+	for (__idx = 0, __pe = &__map->table[__idx];			\
+	     __pe->name || __pe->metric_group || __pe->metric_name;	\
+	     __pe = &__map->table[++__idx])
+
+#define map_for_each_metric(__pe, __idx, __map, __metric)		\
+	map_for_each_event(__pe, __idx, __map)				\
+		if (__pe->metric_expr &&				\
+		    (match_metric(__pe->metric_group, __metric) ||	\
+		     match_metric(__pe->metric_name, __metric)))
+
 static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 				   struct strbuf *events,
 				   struct list_head *group_list,
@@ -624,49 +635,41 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 	int i, ret;
 	bool has_match = false;
 
-	for (i = 0; ; i++) {
-		pe = &map->table[i];
-
-		if (!pe->name && !pe->metric_group && !pe->metric_name) {
-			/* End of pmu events. */
-			if (!has_match)
-				return -EINVAL;
-			break;
-		}
-		if (!pe->metric_expr)
-			continue;
-		if (match_metric(pe->metric_group, metric) ||
-		    match_metric(pe->metric_name, metric)) {
-			has_match = true;
-			pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
-
-			if (!strstr(pe->metric_expr, "?")) {
-				ret = __metricgroup__add_metric(group_list,
-								pe,
-								metric_no_group,
-								1);
-				if (ret)
-					return ret;
-			} else {
-				int j, count;
+	map_for_each_metric(pe, i, map, metric) {
+		pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
+		has_match = true;
+
+		if (!strstr(pe->metric_expr, "?")) {
+			ret = __metricgroup__add_metric(group_list,
+							pe,
+							metric_no_group,
+							1);
+			if (ret)
+				return ret;
+		} else {
+			int j, count;
 
-				count = arch_get_runtimeparam();
+			count = arch_get_runtimeparam();
 
-				/* This loop is added to create multiple
-				 * events depend on count value and add
-				 * those events to group_list.
-				 */
+			/* This loop is added to create multiple
+			 * events depend on count value and add
+			 * those events to group_list.
+			 */
 
-				for (j = 0; j < count; j++) {
-					ret = __metricgroup__add_metric(
-						group_list, pe,
-						metric_no_group, j);
-					if (ret)
-						return ret;
-				}
+			for (j = 0; j < count; j++) {
+				ret = __metricgroup__add_metric(
+					group_list, pe,
+					metric_no_group, j);
+				if (ret)
+					return ret;
 			}
 		}
 	}
+
+	/* End of pmu events. */
+	if (!has_match)
+		return -EINVAL;
+
 	list_for_each_entry(eg, group_list, nd) {
 		if (events->len > 0)
 			strbuf_addf(events, ",");
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 06/19] perf metric: Add add_metric function
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (4 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 05/19] perf metric: Add macros for iterating map events Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:17   ` kajoljain
  2020-07-19 18:13 ` [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric Jiri Olsa
                   ` (14 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Decouple metric adding logging into add_metric function,
so it can be used from other places in following changes.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 62 ++++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 26 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index b37008fc253c..4096be7a7a9e 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -625,6 +625,39 @@ static int __metricgroup__add_metric(struct list_head *group_list,
 		    (match_metric(__pe->metric_group, __metric) ||	\
 		     match_metric(__pe->metric_name, __metric)))
 
+static int add_metric(struct list_head *group_list,
+		      struct pmu_event *pe,
+		      bool metric_no_group)
+{
+	int ret = 0;
+
+	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
+
+	if (!strstr(pe->metric_expr, "?")) {
+		ret = __metricgroup__add_metric(group_list,
+						pe,
+						metric_no_group,
+						1);
+	} else {
+		int j, count;
+
+		count = arch_get_runtimeparam();
+
+		/* This loop is added to create multiple
+		 * events depend on count value and add
+		 * those events to group_list.
+		 */
+
+		for (j = 0; j < count && !ret; j++) {
+			ret = __metricgroup__add_metric(
+				group_list, pe,
+				metric_no_group, j);
+		}
+	}
+
+	return ret;
+}
+
 static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 				   struct strbuf *events,
 				   struct list_head *group_list,
@@ -636,34 +669,11 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 	bool has_match = false;
 
 	map_for_each_metric(pe, i, map, metric) {
-		pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
 		has_match = true;
 
-		if (!strstr(pe->metric_expr, "?")) {
-			ret = __metricgroup__add_metric(group_list,
-							pe,
-							metric_no_group,
-							1);
-			if (ret)
-				return ret;
-		} else {
-			int j, count;
-
-			count = arch_get_runtimeparam();
-
-			/* This loop is added to create multiple
-			 * events depend on count value and add
-			 * those events to group_list.
-			 */
-
-			for (j = 0; j < count; j++) {
-				ret = __metricgroup__add_metric(
-					group_list, pe,
-					metric_no_group, j);
-				if (ret)
-					return ret;
-			}
-		}
+		ret = add_metric(group_list, pe, metric_no_group);
+		if (ret)
+			return ret;
 	}
 
 	/* End of pmu events. */
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (5 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 06/19] perf metric: Add add_metric function Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:18   ` kajoljain
  2020-07-19 18:13 ` [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node Jiri Olsa
                   ` (13 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Renaming __metricgroup__add_metric to __add_metric
to fit in the current function names.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 4096be7a7a9e..ccd80538a6ae 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -571,10 +571,10 @@ int __weak arch_get_runtimeparam(void)
 	return 1;
 }
 
-static int __metricgroup__add_metric(struct list_head *group_list,
-				     struct pmu_event *pe,
-				     bool metric_no_group,
-				     int runtime)
+static int __add_metric(struct list_head *group_list,
+			struct pmu_event *pe,
+			bool metric_no_group,
+			int runtime)
 {
 	struct egroup *eg;
 
@@ -634,10 +634,7 @@ static int add_metric(struct list_head *group_list,
 	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
 
 	if (!strstr(pe->metric_expr, "?")) {
-		ret = __metricgroup__add_metric(group_list,
-						pe,
-						metric_no_group,
-						1);
+		ret = __add_metric(group_list, pe, metric_no_group, 1);
 	} else {
 		int j, count;
 
@@ -649,9 +646,7 @@ static int add_metric(struct list_head *group_list,
 		 */
 
 		for (j = 0; j < count && !ret; j++) {
-			ret = __metricgroup__add_metric(
-				group_list, pe,
-				metric_no_group, j);
+			ret = __add_metric(group_list, pe, metric_no_group, j);
 		}
 	}
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (6 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 22:18   ` Ian Rogers
  2020-07-19 18:13 ` [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr Jiri Olsa
                   ` (12 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

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>
---
 tools/perf/util/metricgroup.c | 170 +++++++++++++++++++++++++++++++---
 1 file changed, 156 insertions(+), 14 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index ccd80538a6ae..d1b2c1aa436f 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -102,12 +102,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;
 };
@@ -574,27 +587,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;
+
+		/*
+		 * 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;
 
-	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);
+		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 {
@@ -625,16 +683,78 @@ 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,
+		      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 add_metric(struct list_head *group_list,
 		      struct pmu_event *pe,
-		      bool metric_no_group)
+		      bool metric_no_group,
+		      struct egroup **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;
 
@@ -646,7 +766,7 @@ static int add_metric(struct list_head *group_list,
 		 */
 
 		for (j = 0; j < count && !ret; j++) {
-			ret = __add_metric(group_list, pe, metric_no_group, j);
+			ret = __add_metric(group_list, pe, metric_no_group, j, egp);
 		}
 	}
 
@@ -657,6 +777,7 @@ 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)
+
 {
 	struct pmu_event *pe;
 	struct egroup *eg;
@@ -665,8 +786,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);
+		ret = add_metric(group_list, pe, metric_no_group, &eg);
+		if (ret)
+			return ret;
+
+		/*
+		 * Process any possible referenced metrics
+		 * included in the expression.
+		 */
+		ret = resolve_metric(eg, metric_no_group,
+				     group_list, map);
 		if (ret)
 			return ret;
 	}
@@ -723,11 +854,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.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (7 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:18   ` kajoljain
  2020-07-19 18:13 ` [PATCH 10/19] perf metric: Add referenced metrics to hash data Jiri Olsa
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Add referenced metrics into struct metric_expr object,
so they are accessible when computing the metric.

Storing just name and expression itself, so the metric
can be resolved and computed.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 32 ++++++++++++++++++++++++++++++++
 tools/perf/util/metricgroup.h |  6 ++++++
 2 files changed, 38 insertions(+)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index d1b2c1aa436f..bb5757b9419d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -83,6 +83,7 @@ static void metric_event_delete(struct rblist *rblist __maybe_unused,
 	struct metric_expr *expr, *tmp;
 
 	list_for_each_entry_safe(expr, tmp, &me->head, nd) {
+		free(expr->metric_refs);
 		free(expr);
 	}
 
@@ -248,6 +249,7 @@ static int metricgroup__setup_events(struct list_head *groups,
 
 	list_for_each_entry (eg, groups, nd) {
 		struct evsel **metric_events;
+		struct metric_ref *metric_refs = NULL;
 
 		metric_events = calloc(sizeof(void *),
 				hashmap__size(&eg->pctx.ids) + 1);
@@ -279,6 +281,36 @@ static int metricgroup__setup_events(struct list_head *groups,
 			free(metric_events);
 			break;
 		}
+
+		/*
+		 * Collect and store collected nested expressions
+		 * for metric processing.
+		 */
+		if (eg->metric_refs_cnt) {
+			struct metric_ref_node *ref;
+
+			metric_refs = zalloc(sizeof(struct metric_ref) * (eg->metric_refs_cnt + 1));
+			if (!metric_refs) {
+				ret = -ENOMEM;
+				free(metric_events);
+				break;
+			}
+
+			i = 0;
+			list_for_each_entry(ref, &eg->metric_refs, list) {
+				/*
+				 * Intentionally passing just const char pointers,
+				 * originally from 'struct pmu_event' object.
+				 * We don't need to change them, so there's no
+				 * need to create our own copy.
+				 */
+				metric_refs[i].metric_name = ref->metric_name;
+				metric_refs[i].metric_expr = ref->metric_expr;
+				i++;
+			}
+		};
+
+		expr->metric_refs = metric_refs;
 		expr->metric_expr = eg->metric_expr;
 		expr->metric_name = eg->metric_name;
 		expr->metric_unit = eg->metric_unit;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 8315bd1a7da4..62623a39cbec 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -18,12 +18,18 @@ struct metric_event {
 	struct list_head head; /* list of metric_expr */
 };
 
+struct metric_ref {
+	const char *metric_name;
+	const char *metric_expr;
+};
+
 struct metric_expr {
 	struct list_head nd;
 	const char *metric_expr;
 	const char *metric_name;
 	const char *metric_unit;
 	struct evsel **metric_events;
+	struct metric_ref *metric_refs;
 	int runtime;
 };
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 10/19] perf metric: Add referenced metrics to hash data
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (8 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 22:32   ` Ian Rogers
  2020-07-19 18:13 ` [PATCH 11/19] perf metric: Compute referenced metrics Jiri Olsa
                   ` (10 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Adding referenced metrics to the parsing context so they
can be resolved during the metric processing.

Adding expr__add_ref function to store referenced metrics
into parse context.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/expr.c        | 54 +++++++++++++++++++++++++++++++++++
 tools/perf/util/expr.h        | 13 ++++++++-
 tools/perf/util/stat-shadow.c | 20 +++++++++----
 3 files changed, 80 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index f726211f49d4..d3997c2b4a90 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -4,10 +4,14 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include "metricgroup.h"
+#include "debug.h"
 #include "expr.h"
 #include "expr-bison.h"
 #include "expr-flex.h"
 #include <linux/kernel.h>
+#include <linux/zalloc.h>
+#include <ctype.h>
 
 #ifdef PARSER_DEBUG
 extern int expr_debug;
@@ -63,6 +67,7 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
 	if (!data_ptr)
 		return -ENOMEM;
 	data_ptr->val = val;
+	data_ptr->is_ref = false;
 
 	ret = hashmap__set(&ctx->ids, id, data_ptr,
 			   (const void **)&old_key, (void **)&old_data);
@@ -73,6 +78,55 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
 	return ret;
 }
 
+int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
+{
+	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
+	char *old_key = NULL;
+	char *name, *p;
+	int ret;
+
+	data_ptr = zalloc(sizeof(*data_ptr));
+	if (!data_ptr)
+		return -ENOMEM;
+
+	name = strdup(ref->metric_name);
+	if (!name) {
+		free(data_ptr);
+		return -ENOMEM;
+	}
+
+	/*
+	 * The jevents tool converts all metric expressions
+	 * to lowercase, including metric references, hence
+	 * we need to add lowercase name for metric, so it's
+	 * properly found.
+	 */
+	for (p = name; *p; p++)
+		*p = tolower(*p);
+
+	/*
+	 * Intentionally passing just const char pointers,
+	 * originally from 'struct pmu_event' object.
+	 * We don't need to change them, so there's no
+	 * need to create our own copy.
+	 */
+	data_ptr->ref.metric_name = ref->metric_name;
+	data_ptr->ref.metric_expr = ref->metric_expr;
+	data_ptr->is_ref = true;
+
+	ret = hashmap__set(&ctx->ids, name, data_ptr,
+			   (const void **)&old_key, (void **)&old_data);
+	if (ret)
+		free(data_ptr);
+
+	pr_debug2("adding ref metric %s: %s\n",
+		  ref->metric_name, ref->metric_expr);
+
+	free(old_key);
+	free(old_data);
+	return ret;
+}
+
 int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 		 struct expr_id_data **data)
 {
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 2462abd0ac65..81d04ff7f857 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -11,12 +11,22 @@
 #include "util/hashmap.h"
 //#endif
 
+struct metric_ref;
+
 struct expr_parse_ctx {
 	struct hashmap ids;
 };
 
 struct expr_id_data {
-	double	val;
+	union {
+		double val;
+		struct {
+			const char *metric_name;
+			const char *metric_expr;
+		} ref;
+	};
+
+	bool is_ref;
 };
 
 struct expr_scanner_ctx {
@@ -29,6 +39,7 @@ void expr__ctx_clear(struct expr_parse_ctx *ctx);
 void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
 int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
 int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
+int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
 int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 		 struct expr_id_data **data);
 int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index fc9ac4b4218e..e1ba6c1b916a 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -731,13 +731,14 @@ static void print_smi_cost(struct perf_stat_config *config,
 }
 
 static int prepare_metric(struct evsel **metric_events,
+			  struct metric_ref *metric_refs,
 			  struct expr_parse_ctx *pctx,
 			  int cpu,
 			  struct runtime_stat *st)
 {
 	double scale;
 	char *n, *pn;
-	int i;
+	int i, j, ret;
 
 	expr__ctx_init(pctx);
 	for (i = 0; metric_events[i]; i++) {
@@ -778,12 +779,19 @@ static int prepare_metric(struct evsel **metric_events,
 			expr__add_id_val(pctx, n, avg_stats(stats)*scale);
 	}
 
+	for (j = 0; metric_refs && metric_refs[j].metric_name; j++) {
+		ret = expr__add_ref(pctx, &metric_refs[j]);
+		if (ret)
+			return ret;
+	}
+
 	return i;
 }
 
 static void generic_metric(struct perf_stat_config *config,
 			   const char *metric_expr,
 			   struct evsel **metric_events,
+			   struct metric_ref *metric_refs,
 			   char *name,
 			   const char *metric_name,
 			   const char *metric_unit,
@@ -798,7 +806,7 @@ static void generic_metric(struct perf_stat_config *config,
 	int i;
 	void *ctxp = out->ctx;
 
-	i = prepare_metric(metric_events, &pctx, cpu, st);
+	i = prepare_metric(metric_events, metric_refs, &pctx, cpu, st);
 	if (i < 0)
 		return;
 
@@ -847,7 +855,7 @@ double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_sta
 	struct expr_parse_ctx pctx;
 	double ratio;
 
-	if (prepare_metric(mexp->metric_events, &pctx, cpu, st) < 0)
+	if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0)
 		return 0.;
 
 	if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1))
@@ -1064,8 +1072,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 		else
 			print_metric(config, ctxp, NULL, NULL, name, 0);
 	} else if (evsel->metric_expr) {
-		generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name,
-				evsel->metric_name, NULL, 1, cpu, out, st);
+		generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
+				evsel->name, evsel->metric_name, NULL, 1, cpu, out, st);
 	} else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) {
 		char unit = 'M';
 		char unit_buf[10];
@@ -1093,7 +1101,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 			if (num++ > 0)
 				out->new_line(config, ctxp);
 			generic_metric(config, mexp->metric_expr, mexp->metric_events,
-					evsel->name, mexp->metric_name,
+					mexp->metric_refs, evsel->name, mexp->metric_name,
 					mexp->metric_unit, mexp->runtime, cpu, out, st);
 		}
 	}
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 11/19] perf metric: Compute referenced metrics
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (9 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 10/19] perf metric: Add referenced metrics to hash data Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:19   ` kajoljain
  2020-07-19 18:13 ` [PATCH 12/19] perf metric: Add events for the current list Jiri Olsa
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Adding computation (expr__parse call) of referenced metric at
the point when it needs to be resolved during the parent metric
computation.

Once the inner metric is computed, the result is stored and
used if there's another usage of that metric.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/expr.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/util/expr.h |  3 +++
 tools/perf/util/expr.y |  4 ++--
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index d3997c2b4a90..a346ca590513 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -112,6 +112,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
 	 */
 	data_ptr->ref.metric_name = ref->metric_name;
 	data_ptr->ref.metric_expr = ref->metric_expr;
+	data_ptr->ref.counted = false;
 	data_ptr->is_ref = true;
 
 	ret = hashmap__set(&ctx->ids, name, data_ptr,
@@ -133,6 +134,34 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
 }
 
+int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
+		     struct expr_id_data **datap)
+{
+	struct expr_id_data *data;
+
+	if (expr__get_id(ctx, id, datap) || !*datap) {
+		pr_debug("%s not found\n", id);
+		return -1;
+	}
+
+	data = *datap;
+
+	pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n",
+		  data->is_ref, data->ref.counted, data->val, id);
+
+	if (data->is_ref && !data->ref.counted) {
+		data->ref.counted = true;
+		pr_debug("processing metric: %s ENTRY\n", id);
+		if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) {
+			pr_debug("%s failed to count\n", id);
+			return -1;
+		}
+		pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
+	}
+
+	return 0;
+}
+
 void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
 {
 	struct expr_id_data *old_val = NULL;
@@ -173,6 +202,8 @@ __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
 	void *scanner;
 	int ret;
 
+	pr_debug2("parsing metric: %s\n", expr);
+
 	ret = expr_lex_init_extra(&scanner_ctx, &scanner);
 	if (ret)
 		return ret;
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 81d04ff7f857..9ed208d93418 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -23,6 +23,7 @@ struct expr_id_data {
 		struct {
 			const char *metric_name;
 			const char *metric_expr;
+			bool counted;
 		} ref;
 	};
 
@@ -42,6 +43,8 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
 int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
 int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 		 struct expr_id_data **data);
+int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
+		     struct expr_id_data **datap);
 int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
 		const char *expr, int runtime);
 int expr__find_other(const char *expr, const char *one,
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index 0d4f5d324be7..d34b370391c6 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -88,11 +88,11 @@ expr:	  NUMBER
 	| ID			{
 					struct expr_id_data *data;
 
-					if (expr__get_id(ctx, $1, &data) || !data) {
-						pr_debug("%s not found\n", $1);
+					if (expr__resolve_id(ctx, $1, &data)) {
 						free($1);
 						YYABORT;
 					}
+
 					$$ = data->val;
 					free($1);
 				}
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 12/19] perf metric: Add events for the current list
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (10 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 11/19] perf metric: Compute referenced metrics Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 22:34   ` Ian Rogers
  2020-07-19 18:13 ` [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test Jiri Olsa
                   ` (8 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

There's no need to iterate the whole list of groups,
when adding new events. The currently created groups
are the ones we want to add.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index bb5757b9419d..332414d93f7a 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -813,6 +813,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 {
 	struct pmu_event *pe;
 	struct egroup *eg;
+	LIST_HEAD(list);
 	int i, ret;
 	bool has_match = false;
 
@@ -820,7 +821,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		has_match = true;
 		eg = NULL;
 
-		ret = add_metric(group_list, pe, metric_no_group, &eg);
+		ret = add_metric(&list, pe, metric_no_group, &eg);
 		if (ret)
 			return ret;
 
@@ -829,7 +830,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		 * included in the expression.
 		 */
 		ret = resolve_metric(eg, metric_no_group,
-				     group_list, map);
+				     &list, map);
 		if (ret)
 			return ret;
 	}
@@ -838,7 +839,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 	if (!has_match)
 		return -EINVAL;
 
-	list_for_each_entry(eg, group_list, nd) {
+	list_for_each_entry(eg, &list, nd) {
 		if (events->len > 0)
 			strbuf_addf(events, ",");
 
@@ -850,6 +851,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 							   &eg->pctx);
 		}
 	}
+
+	list_splice(&list, group_list);
 	return 0;
 }
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (11 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 12/19] perf metric: Add events for the current list Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:19   ` kajoljain
  2020-07-19 18:13 ` [PATCH 14/19] perf metric: Add DCache_L2 " Jiri Olsa
                   ` (7 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Adding test that compute metric with other metrics in it.

  cache_miss_cycles = metric:dcache_miss_cpi + metric:icache_miss_cycles

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/tests/parse-metric.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 8c48251425e1..28f33893338b 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -11,6 +11,8 @@
 #include "debug.h"
 #include "expr.h"
 #include "stat.h"
+#include <perf/cpumap.h>
+#include <perf/evlist.h>
 
 static struct pmu_event pme_test[] = {
 {
@@ -22,6 +24,18 @@ static struct pmu_event pme_test[] = {
 			  "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
 	.metric_name	= "Frontend_Bound_SMT",
 },
+{
+	.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
+	.metric_name	= "dcache_miss_cpi",
+},
+{
+	.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
+	.metric_name	= "icache_miss_cycles",
+},
+{
+	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
+	.metric_name	= "cache_miss_cycles",
+},
 };
 
 static struct pmu_events_map map = {
@@ -162,9 +176,28 @@ static int test_frontend(void)
 	return 0;
 }
 
+static int test_cache_miss_cycles(void)
+{
+	double ratio;
+	struct value vals[] = {
+		{ .event = "l1d-loads-misses",  .val = 300 },
+		{ .event = "l1i-loads-misses",  .val = 200 },
+		{ .event = "inst_retired.any",  .val = 400 },
+		{ 0 },
+	};
+
+	TEST_ASSERT_VAL("failed to compute metric",
+			compute_metric("cache_miss_cycles", vals, &ratio) == 0);
+
+	TEST_ASSERT_VAL("cache_miss_cycles failed, wrong ratio",
+			ratio == 1.25);
+	return 0;
+}
+
 int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
 {
 	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
 	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
+	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
 	return 0;
 }
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 14/19] perf metric: Add DCache_L2 to metric parse test
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (12 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:19   ` kajoljain
  2020-07-19 18:13 ` [PATCH 15/19] perf metric: Add recursion check when processing nested metrics Jiri Olsa
                   ` (6 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Adding test that compute DCache_L2 metrics with other related metrics in it.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/tests/parse-metric.c | 71 +++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 28f33893338b..aa4d5a9f09a8 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -36,6 +36,27 @@ static struct pmu_event pme_test[] = {
 	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
 	.metric_name	= "cache_miss_cycles",
 },
+{
+	.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+	.metric_name	= "DCache_L2_All_Hits",
+},
+{
+	.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
+			  "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+	.metric_name	= "DCache_L2_All_Miss",
+},
+{
+	.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
+	.metric_name	= "DCache_L2_All",
+},
+{
+	.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+	.metric_name	= "DCache_L2_Hits",
+},
+{
+	.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+	.metric_name	= "DCache_L2_Misses",
+},
 };
 
 static struct pmu_events_map map = {
@@ -194,10 +215,60 @@ static int test_cache_miss_cycles(void)
 	return 0;
 }
 
+
+/*
+ * DCache_L2_All_Hits = l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hi
+ * DCache_L2_All_Miss = max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) +
+ *                      l2_rqsts.pf_miss + l2_rqsts.rfo_miss
+ * DCache_L2_All      = dcache_l2_all_hits + dcache_l2_all_miss
+ * DCache_L2_Hits     = d_ratio(dcache_l2_all_hits, dcache_l2_all)
+ * DCache_L2_Misses   = d_ratio(dcache_l2_all_miss, dcache_l2_all)
+ *
+ * l2_rqsts.demand_data_rd_hit = 100
+ * l2_rqsts.pf_hit             = 200
+ * l2_rqsts.rfo_hi             = 300
+ * l2_rqsts.all_demand_data_rd = 400
+ * l2_rqsts.pf_miss            = 500
+ * l2_rqsts.rfo_miss           = 600
+ *
+ * DCache_L2_All_Hits = 600
+ * DCache_L2_All_Miss = MAX(400 - 100, 0) + 500 + 600 = 1400
+ * DCache_L2_All      = 600 + 1400  = 2000
+ * DCache_L2_Hits     = 600 / 2000  = 0.3
+ * DCache_L2_Misses   = 1400 / 2000 = 0.7
+ */
+static int test_dcache_l2(void)
+{
+	double ratio;
+	struct value vals[] = {
+		{ .event = "l2_rqsts.demand_data_rd_hit", .val = 100 },
+		{ .event = "l2_rqsts.pf_hit",             .val = 200 },
+		{ .event = "l2_rqsts.rfo_hit",            .val = 300 },
+		{ .event = "l2_rqsts.all_demand_data_rd", .val = 400 },
+		{ .event = "l2_rqsts.pf_miss",            .val = 500 },
+		{ .event = "l2_rqsts.rfo_miss",           .val = 600 },
+		{ 0 },
+	};
+
+	TEST_ASSERT_VAL("failed to compute metric",
+			compute_metric("DCache_L2_Hits", vals, &ratio) == 0);
+
+	TEST_ASSERT_VAL("DCache_L2_Hits failed, wrong ratio",
+			ratio == 0.3);
+
+	TEST_ASSERT_VAL("failed to compute metric",
+			compute_metric("DCache_L2_Misses", vals, &ratio) == 0);
+
+	TEST_ASSERT_VAL("DCache_L2_Misses failed, wrong ratio",
+			ratio == 0.7);
+	return 0;
+}
+
 int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
 {
 	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
 	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
 	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
+	TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
 	return 0;
 }
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 15/19] perf metric: Add recursion check when processing nested metrics
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (13 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 14/19] perf metric: Add DCache_L2 " Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 22:40   ` Ian Rogers
  2020-07-19 18:13 ` [PATCH 16/19] perf metric: Make compute_single function more precise Jiri Olsa
                   ` (5 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Keeping the stack of nested metrics via 'struct expr_id' objects
and checking if we are in recursion via already processed metric.

The stack is implemented as static array within the struct egroup
with 100 entries, which should be enough nesting depth for any
metric we have or plan to have at the moment.

Adding test that simulates the recursion and checks we can
detect it.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/tests/parse-metric.c |  34 +++++++++-
 tools/perf/util/expr.c          |   2 +
 tools/perf/util/expr.h          |   9 ++-
 tools/perf/util/metricgroup.c   | 117 +++++++++++++++++++++++++++++---
 4 files changed, 149 insertions(+), 13 deletions(-)

diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index aa4d5a9f09a8..01370ccb9ed9 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -57,6 +57,18 @@ static struct pmu_event pme_test[] = {
 	.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
 	.metric_name	= "DCache_L2_Misses",
 },
+{
+	.metric_expr	= "ipc + m2",
+	.metric_name	= "M1",
+},
+{
+	.metric_expr	= "ipc + m1",
+	.metric_name	= "M2",
+},
+{
+	.metric_expr	= "1/m3",
+	.metric_name	= "M3",
+}
 };
 
 static struct pmu_events_map map = {
@@ -139,8 +151,8 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
 	err = metricgroup__parse_groups_test(evlist, &map, name,
 					     false, false,
 					     &metric_events);
-
-	TEST_ASSERT_VAL("failed to parse metric", err == 0);
+	if (err)
+		return err;
 
 	if (perf_evlist__alloc_stats(evlist, false))
 		return -1;
@@ -264,11 +276,29 @@ static int test_dcache_l2(void)
 	return 0;
 }
 
+static int test_recursion_fail(void)
+{
+	double ratio;
+	struct value vals[] = {
+		{ .event = "inst_retired.any",        .val = 300 },
+		{ .event = "cpu_clk_unhalted.thread", .val = 200 },
+		{ 0 },
+	};
+
+	TEST_ASSERT_VAL("failed to find recursion",
+			compute_metric("M1", vals, &ratio) == -1);
+
+	TEST_ASSERT_VAL("failed to find recursion",
+			compute_metric("M3", vals, &ratio) == -1);
+	return 0;
+}
+
 int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
 {
 	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
 	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
 	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
 	TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
+	TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
 	return 0;
 }
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index a346ca590513..53482ef53c41 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -47,6 +47,8 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
 	if (!data_ptr)
 		return -ENOMEM;
 
+	data_ptr->parent = ctx->parent;
+
 	ret = hashmap__set(&ctx->ids, id, data_ptr,
 			   (const void **)&old_key, (void **)&old_data);
 	if (ret)
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 9ed208d93418..fc2b5e824a66 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -13,8 +13,14 @@
 
 struct metric_ref;
 
+struct expr_id {
+	char		*id;
+	struct expr_id	*parent;
+};
+
 struct expr_parse_ctx {
-	struct hashmap ids;
+	struct hashmap	 ids;
+	struct expr_id	*parent;
 };
 
 struct expr_id_data {
@@ -25,6 +31,7 @@ struct expr_id_data {
 			const char *metric_expr;
 			bool counted;
 		} ref;
+		struct expr_id	*parent;
 	};
 
 	bool is_ref;
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 332414d93f7a..2a45ee94fd61 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -24,6 +24,7 @@
 #include <subcmd/parse-options.h>
 #include <api/fs/fs.h>
 #include "util.h"
+#include <asm/bug.h>
 
 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
 					 struct evsel *evsel,
@@ -126,6 +127,28 @@ struct egroup {
 	bool has_constraint;
 };
 
+#define RECURSION_ID_MAX 100
+
+struct expr_ids {
+	struct expr_id	id[RECURSION_ID_MAX];
+	int		cnt;
+};
+
+static struct expr_id *expr_ids__alloc(struct expr_ids *ids)
+{
+	if (ids->cnt >= RECURSION_ID_MAX)
+		return NULL;
+	return &ids->id[ids->cnt++];
+}
+
+static void expr_ids__exit(struct expr_ids *ids)
+{
+	int i;
+
+	for (i = 0; i < ids->cnt; i++)
+		free(ids->id[i].id);
+}
+
 /**
  * Find a group of events in perf_evlist that correpond to those from a parsed
  * metric expression. Note, as find_evsel_group is called in the same order as
@@ -620,7 +643,9 @@ static int __add_metric(struct list_head *group_list,
 			struct pmu_event *pe,
 			bool metric_no_group,
 			int runtime,
-		        struct egroup **egp)
+			struct egroup **egp,
+			struct expr_id *parent,
+		        struct expr_ids *ids)
 {
 	struct metric_ref_node *ref;
 	struct egroup *eg;
@@ -630,7 +655,7 @@ static int __add_metric(struct list_head *group_list,
 		 * We got in here for the parent group,
 		 * allocate it and put it on the list.
 		 */
-		eg = malloc(sizeof(*eg));
+		eg = zalloc(sizeof(*eg));
 		if (!eg)
 			return -ENOMEM;
 
@@ -643,6 +668,18 @@ static int __add_metric(struct list_head *group_list,
 		INIT_LIST_HEAD(&eg->metric_refs);
 		eg->metric_refs_cnt = 0;
 		*egp = eg;
+
+		parent = expr_ids__alloc(ids);
+		if (!parent) {
+			free(eg);
+			return -EINVAL;
+		}
+
+		parent->id = strdup(pe->metric_name);
+		if (!parent->id) {
+			free(eg);
+			return -ENOMEM;
+		}
 	} else {
 		/*
 		 * We got here for the referenced metric, via the
@@ -668,6 +705,10 @@ static int __add_metric(struct list_head *group_list,
 		eg->metric_refs_cnt++;
 	}
 
+	/* Force all found IDs in metric to have us as parent ID. */
+	WARN_ON_ONCE(!parent);
+	eg->pctx.parent = parent;
+
 	/*
 	 * For both the parent and referenced metrics, we parse
 	 * all the metric's IDs and add it to the parent context.
@@ -728,15 +769,62 @@ static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *
 	return NULL;
 }
 
+static int recursion_check(struct egroup *eg, const char *id, struct expr_id **parent,
+			   struct expr_ids *ids)
+{
+	struct expr_id_data *data;
+	struct expr_id *p;
+	int ret;
+
+	/*
+	 * We get the parent referenced by 'id' argument and
+	 * traverse through all the parent object IDs to check
+	 * if we already processed 'id', if we did, it's recursion
+	 * and we fail.
+	 */
+	ret = expr__get_id(&eg->pctx, id, &data);
+	if (ret)
+		return ret;
+
+	p = data->parent;
+
+	while (p->parent) {
+		if (!strcmp(p->id, id)) {
+			pr_err("failed: recursion detected for %s\n", id);
+			return -1;
+		}
+		p = p->parent;
+	}
+
+	/*
+	 * If we are over the limit of static entris, the metric
+	 * is too difficult/nested to process, fail as well.
+	 */
+	p = expr_ids__alloc(ids);
+	if (!p) {
+		pr_err("failed: too many nested metrics\n");
+		return -EINVAL;
+	}
+
+	p->id     = strdup(id);
+	p->parent = data->parent;
+	*parent   = p;
+
+	return p->id ? 0 : -ENOMEM;
+}
+
 static int add_metric(struct list_head *group_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
-		      struct egroup **egp);
+		      struct egroup **egp,
+		      struct expr_id *parent,
+		      struct expr_ids *ids);
 
 static int resolve_metric(struct egroup *eg,
 			  bool metric_no_group,
 			  struct list_head *group_list,
-			  struct pmu_events_map *map)
+			  struct pmu_events_map *map,
+			  struct expr_ids *ids)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -750,18 +838,23 @@ static int resolve_metric(struct egroup *eg,
 	do {
 		all = true;
 		hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
+			struct expr_id *parent;
 			struct pmu_event *pe;
 
 			pe = find_metric(cur->key, map);
 			if (!pe)
 				continue;
 
+			ret = recursion_check(eg, cur->key, &parent, ids);
+			if (ret)
+				return ret;
+
 			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);
+			ret = add_metric(group_list, pe, metric_no_group, &eg, parent, ids);
 			if (ret)
 				return ret;
 
@@ -779,14 +872,16 @@ static int resolve_metric(struct egroup *eg,
 static int add_metric(struct list_head *group_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
-		      struct egroup **egp)
+		      struct egroup **egp,
+		      struct expr_id *parent,
+		      struct expr_ids *ids)
 {
 	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, egp);
+		ret = __add_metric(group_list, pe, metric_no_group, 1, egp, parent, ids);
 	} else {
 		int j, count;
 
@@ -798,7 +893,7 @@ static int add_metric(struct list_head *group_list,
 		 */
 
 		for (j = 0; j < count && !ret; j++) {
-			ret = __add_metric(group_list, pe, metric_no_group, j, egp);
+			ret = __add_metric(group_list, pe, metric_no_group, j, egp, parent, ids);
 		}
 	}
 
@@ -811,6 +906,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 				   struct pmu_events_map *map)
 
 {
+	struct expr_ids ids = { 0 };
 	struct pmu_event *pe;
 	struct egroup *eg;
 	LIST_HEAD(list);
@@ -821,7 +917,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		has_match = true;
 		eg = NULL;
 
-		ret = add_metric(&list, pe, metric_no_group, &eg);
+		ret = add_metric(&list, pe, metric_no_group, &eg, NULL, &ids);
 		if (ret)
 			return ret;
 
@@ -830,7 +926,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		 * included in the expression.
 		 */
 		ret = resolve_metric(eg, metric_no_group,
-				     &list, map);
+				     &list, map, &ids);
 		if (ret)
 			return ret;
 	}
@@ -853,6 +949,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 	}
 
 	list_splice(&list, group_list);
+	expr_ids__exit(&ids);
 	return 0;
 }
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 16/19] perf metric: Make compute_single function more precise
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (14 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 15/19] perf metric: Add recursion check when processing nested metrics Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-28 12:36   ` Arnaldo Carvalho de Melo
  2020-07-19 18:13 ` [PATCH 17/19] perf metric: Add metric group test Jiri Olsa
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

So far compute_single function relies on the fact, that
there's only single metric defined within evlist in all
tests. In following patch we will add test for metric
group, so we need to be able to compute metric by given
name.

Adding the name argument to compute_single and iterating
evlist and evsel's expression to find the given metric.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/tests/parse-metric.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 01370ccb9ed9..5ac32f80f8ea 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -108,17 +108,21 @@ static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist,
 }
 
 static double compute_single(struct rblist *metric_events, struct evlist *evlist,
-			     struct runtime_stat *st)
+			     struct runtime_stat *st, const char *name)
 {
-	struct evsel *evsel = evlist__first(evlist);
+	struct metric_expr *mexp;
 	struct metric_event *me;
+	struct evsel *evsel;
 
-	me = metricgroup__lookup(metric_events, evsel, false);
-	if (me != NULL) {
-		struct metric_expr *mexp;
-
-		mexp = list_first_entry(&me->head, struct metric_expr, nd);
-		return test_generic_metric(mexp, 0, st);
+	evlist__for_each_entry(evlist, evsel) {
+		me = metricgroup__lookup(metric_events, evsel, false);
+		if (me != NULL) {
+			list_for_each_entry (mexp, &me->head, nd) {
+				if (strcmp(mexp->metric_name, name))
+					continue;
+				return test_generic_metric(mexp, 0, st);
+			}
+		}
 	}
 	return 0.;
 }
@@ -162,7 +166,7 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
 	load_runtime_stat(&st, evlist, vals);
 
 	/* And execute the metric */
-	*ratio = compute_single(&metric_events, evlist, &st);
+	*ratio = compute_single(&metric_events, evlist, &st, name);
 
 	/* ... clenup. */
 	metricgroup__rblist_exit(&metric_events);
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 17/19] perf metric: Add metric group test
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (15 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 16/19] perf metric: Make compute_single function more precise Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 22:41   ` Ian Rogers
  2020-07-19 18:13 ` [PATCH 18/19] perf metric: Rename struct egroup to metric Jiri Olsa
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Adding test for metric group plus compute_metric_group
function to get metrics values within the group.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/tests/parse-metric.c | 48 +++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 5ac32f80f8ea..f2ba5b2c5557 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -18,6 +18,7 @@ static struct pmu_event pme_test[] = {
 {
 	.metric_expr	= "inst_retired.any / cpu_clk_unhalted.thread",
 	.metric_name	= "IPC",
+	.metric_group	= "group1",
 },
 {
 	.metric_expr	= "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
@@ -35,6 +36,7 @@ static struct pmu_event pme_test[] = {
 {
 	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
 	.metric_name	= "cache_miss_cycles",
+	.metric_group	= "group1",
 },
 {
 	.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
@@ -127,7 +129,9 @@ static double compute_single(struct rblist *metric_events, struct evlist *evlist
 	return 0.;
 }
 
-static int compute_metric(const char *name, struct value *vals, double *ratio)
+static int __compute_metric(const char *name, struct value *vals,
+			    const char *name1, double *ratio1,
+			    const char *name2, double *ratio2)
 {
 	struct rblist metric_events = {
 		.nr_entries = 0,
@@ -166,7 +170,10 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
 	load_runtime_stat(&st, evlist, vals);
 
 	/* And execute the metric */
-	*ratio = compute_single(&metric_events, evlist, &st, name);
+	if (name1 && ratio1)
+		*ratio1 = compute_single(&metric_events, evlist, &st, name1);
+	if (name2 && ratio2)
+		*ratio2 = compute_single(&metric_events, evlist, &st, name2);
 
 	/* ... clenup. */
 	metricgroup__rblist_exit(&metric_events);
@@ -177,6 +184,18 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
 	return 0;
 }
 
+static int compute_metric(const char *name, struct value *vals, double *ratio)
+{
+	return __compute_metric(name, vals, name, ratio, NULL, NULL);
+}
+
+static int compute_metric_group(const char *name, struct value *vals,
+				const char *name1, double *ratio1,
+				const char *name2, double *ratio2)
+{
+	return __compute_metric(name, vals, name1, ratio1, name2, ratio2);
+}
+
 static int test_ipc(void)
 {
 	double ratio;
@@ -297,6 +316,30 @@ static int test_recursion_fail(void)
 	return 0;
 }
 
+static int test_metric_group(void)
+{
+	double ratio1, ratio2;
+	struct value vals[] = {
+		{ .event = "cpu_clk_unhalted.thread", .val = 200 },
+		{ .event = "l1d-loads-misses",        .val = 300 },
+		{ .event = "l1i-loads-misses",        .val = 200 },
+		{ .event = "inst_retired.any",        .val = 400 },
+		{ 0 },
+	};
+
+	TEST_ASSERT_VAL("failed to find recursion",
+			compute_metric_group("group1", vals,
+					     "IPC", &ratio1,
+					     "cache_miss_cycles", &ratio2) == 0);
+
+	TEST_ASSERT_VAL("group IPC failed, wrong ratio",
+			ratio1 == 2.0);
+
+	TEST_ASSERT_VAL("group cache_miss_cycles failed, wrong ratio",
+			ratio2 == 1.25);
+	return 0;
+}
+
 int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
 {
 	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
@@ -304,5 +347,6 @@ int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unu
 	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
 	TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
 	TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
+	TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
 	return 0;
 }
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 18/19] perf metric: Rename struct egroup to metric
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (16 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 17/19] perf metric: Add metric group test Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-26  9:20   ` kajoljain
  2020-07-19 18:13 ` [PATCH 19/19] perf metric: Rename group_list to metric_list Jiri Olsa
                   ` (2 subsequent siblings)
  20 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Renaming struct egroup to metric, because it seems
to make more sense. Plus renaming all the variables
that hold egroup to appropriate names.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 142 +++++++++++++++++-----------------
 1 file changed, 71 insertions(+), 71 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 2a45ee94fd61..9d5fff36042d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -115,7 +115,7 @@ struct metric_ref_node {
 	struct list_head list;
 };
 
-struct egroup {
+struct metric {
 	struct list_head nd;
 	struct expr_parse_ctx pctx;
 	const char *metric_name;
@@ -262,7 +262,7 @@ static int metricgroup__setup_events(struct list_head *groups,
 	struct metric_expr *expr;
 	int i = 0;
 	int ret = 0;
-	struct egroup *eg;
+	struct metric *m;
 	struct evsel *evsel, *tmp;
 	unsigned long *evlist_used;
 
@@ -270,23 +270,23 @@ static int metricgroup__setup_events(struct list_head *groups,
 	if (!evlist_used)
 		return -ENOMEM;
 
-	list_for_each_entry (eg, groups, nd) {
+	list_for_each_entry (m, groups, nd) {
 		struct evsel **metric_events;
 		struct metric_ref *metric_refs = NULL;
 
 		metric_events = calloc(sizeof(void *),
-				hashmap__size(&eg->pctx.ids) + 1);
+				hashmap__size(&m->pctx.ids) + 1);
 		if (!metric_events) {
 			ret = -ENOMEM;
 			break;
 		}
-		evsel = find_evsel_group(perf_evlist, &eg->pctx,
+		evsel = find_evsel_group(perf_evlist, &m->pctx,
 					 metric_no_merge,
-					 eg->has_constraint, metric_events,
+					 m->has_constraint, metric_events,
 					 evlist_used);
 		if (!evsel) {
 			pr_debug("Cannot resolve %s: %s\n",
-					eg->metric_name, eg->metric_expr);
+					m->metric_name, m->metric_expr);
 			free(metric_events);
 			continue;
 		}
@@ -309,10 +309,10 @@ static int metricgroup__setup_events(struct list_head *groups,
 		 * Collect and store collected nested expressions
 		 * for metric processing.
 		 */
-		if (eg->metric_refs_cnt) {
+		if (m->metric_refs_cnt) {
 			struct metric_ref_node *ref;
 
-			metric_refs = zalloc(sizeof(struct metric_ref) * (eg->metric_refs_cnt + 1));
+			metric_refs = zalloc(sizeof(struct metric_ref) * (m->metric_refs_cnt + 1));
 			if (!metric_refs) {
 				ret = -ENOMEM;
 				free(metric_events);
@@ -320,7 +320,7 @@ static int metricgroup__setup_events(struct list_head *groups,
 			}
 
 			i = 0;
-			list_for_each_entry(ref, &eg->metric_refs, list) {
+			list_for_each_entry(ref, &m->metric_refs, list) {
 				/*
 				 * Intentionally passing just const char pointers,
 				 * originally from 'struct pmu_event' object.
@@ -334,11 +334,11 @@ static int metricgroup__setup_events(struct list_head *groups,
 		};
 
 		expr->metric_refs = metric_refs;
-		expr->metric_expr = eg->metric_expr;
-		expr->metric_name = eg->metric_name;
-		expr->metric_unit = eg->metric_unit;
+		expr->metric_expr = m->metric_expr;
+		expr->metric_name = m->metric_name;
+		expr->metric_unit = m->metric_unit;
 		expr->metric_events = metric_events;
-		expr->runtime = eg->runtime;
+		expr->runtime = m->runtime;
 		list_add(&expr->nd, &me->head);
 	}
 
@@ -643,41 +643,41 @@ static int __add_metric(struct list_head *group_list,
 			struct pmu_event *pe,
 			bool metric_no_group,
 			int runtime,
-			struct egroup **egp,
+			struct metric **mp,
 			struct expr_id *parent,
 		        struct expr_ids *ids)
 {
 	struct metric_ref_node *ref;
-	struct egroup *eg;
+	struct metric *m;
 
-	if (*egp == NULL) {
+	if (*mp == NULL) {
 		/*
 		 * We got in here for the parent group,
 		 * allocate it and put it on the list.
 		 */
-		eg = zalloc(sizeof(*eg));
-		if (!eg)
+		m = zalloc(sizeof(*m));
+		if (!m)
 			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;
+		expr__ctx_init(&m->pctx);
+		m->metric_name = pe->metric_name;
+		m->metric_expr = pe->metric_expr;
+		m->metric_unit = pe->unit;
+		m->runtime = runtime;
+		m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
+		INIT_LIST_HEAD(&m->metric_refs);
+		m->metric_refs_cnt = 0;
+		*mp = m;
 
 		parent = expr_ids__alloc(ids);
 		if (!parent) {
-			free(eg);
+			free(m);
 			return -EINVAL;
 		}
 
 		parent->id = strdup(pe->metric_name);
 		if (!parent->id) {
-			free(eg);
+			free(m);
 			return -ENOMEM;
 		}
 	} else {
@@ -686,7 +686,7 @@ static int __add_metric(struct list_head *group_list,
 		 * recursive metricgroup__add_metric call, add
 		 * it to the parent group.
 		 */
-		eg = *egp;
+		m = *mp;
 
 		ref = malloc(sizeof(*ref));
 		if (!ref)
@@ -701,21 +701,21 @@ static int __add_metric(struct list_head *group_list,
 		ref->metric_name = pe->metric_name;
 		ref->metric_expr = pe->metric_expr;
 
-		list_add(&ref->list, &eg->metric_refs);
-		eg->metric_refs_cnt++;
+		list_add(&ref->list, &m->metric_refs);
+		m->metric_refs_cnt++;
 	}
 
 	/* Force all found IDs in metric to have us as parent ID. */
 	WARN_ON_ONCE(!parent);
-	eg->pctx.parent = parent;
+	m->pctx.parent = parent;
 
 	/*
 	 * 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);
+	if (expr__find_other(pe->metric_expr, NULL, &m->pctx, runtime) < 0) {
+		expr__ctx_clear(&m->pctx);
+		free(m);
 		return -EINVAL;
 	}
 
@@ -723,23 +723,23 @@ static int __add_metric(struct list_head *group_list,
 	 * We add new group only in the 'parent' call,
 	 * so bail out for referenced metric case.
 	 */
-	if (eg->metric_refs_cnt)
+	if (m->metric_refs_cnt)
 		return 0;
 
 	if (list_empty(group_list))
-		list_add(&eg->nd, group_list);
+		list_add(&m->nd, group_list);
 	else {
 		struct list_head *pos;
 
 		/* Place the largest groups at the front. */
 		list_for_each_prev(pos, group_list) {
-			struct egroup *old = list_entry(pos, struct egroup, nd);
+			struct metric *old = list_entry(pos, struct metric, nd);
 
-			if (hashmap__size(&eg->pctx.ids) <=
+			if (hashmap__size(&m->pctx.ids) <=
 			    hashmap__size(&old->pctx.ids))
 				break;
 		}
-		list_add(&eg->nd, pos);
+		list_add(&m->nd, pos);
 	}
 
 	return 0;
@@ -769,7 +769,7 @@ static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *
 	return NULL;
 }
 
-static int recursion_check(struct egroup *eg, const char *id, struct expr_id **parent,
+static int recursion_check(struct metric *m, const char *id, struct expr_id **parent,
 			   struct expr_ids *ids)
 {
 	struct expr_id_data *data;
@@ -782,7 +782,7 @@ static int recursion_check(struct egroup *eg, const char *id, struct expr_id **p
 	 * if we already processed 'id', if we did, it's recursion
 	 * and we fail.
 	 */
-	ret = expr__get_id(&eg->pctx, id, &data);
+	ret = expr__get_id(&m->pctx, id, &data);
 	if (ret)
 		return ret;
 
@@ -816,11 +816,11 @@ static int recursion_check(struct egroup *eg, const char *id, struct expr_id **p
 static int add_metric(struct list_head *group_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
-		      struct egroup **egp,
+		      struct metric **mp,
 		      struct expr_id *parent,
 		      struct expr_ids *ids);
 
-static int resolve_metric(struct egroup *eg,
+static int resolve_metric(struct metric *m,
 			  bool metric_no_group,
 			  struct list_head *group_list,
 			  struct pmu_events_map *map,
@@ -837,7 +837,7 @@ static int resolve_metric(struct egroup *eg,
 	 */
 	do {
 		all = true;
-		hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
+		hashmap__for_each_entry((&m->pctx.ids), cur, bkt) {
 			struct expr_id *parent;
 			struct pmu_event *pe;
 
@@ -845,16 +845,16 @@ static int resolve_metric(struct egroup *eg,
 			if (!pe)
 				continue;
 
-			ret = recursion_check(eg, cur->key, &parent, ids);
+			ret = recursion_check(m, cur->key, &parent, ids);
 			if (ret)
 				return ret;
 
 			all = false;
 			/* The metric key itself needs to go out.. */
-			expr__del_id(&eg->pctx, cur->key);
+			expr__del_id(&m->pctx, cur->key);
 
 			/* ... and it gets resolved to the parent context. */
-			ret = add_metric(group_list, pe, metric_no_group, &eg, parent, ids);
+			ret = add_metric(group_list, pe, metric_no_group, &m, parent, ids);
 			if (ret)
 				return ret;
 
@@ -872,7 +872,7 @@ static int resolve_metric(struct egroup *eg,
 static int add_metric(struct list_head *group_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
-		      struct egroup **egp,
+		      struct metric **m,
 		      struct expr_id *parent,
 		      struct expr_ids *ids)
 {
@@ -881,7 +881,7 @@ static int add_metric(struct list_head *group_list,
 	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, egp, parent, ids);
+		ret = __add_metric(group_list, pe, metric_no_group, 1, m, parent, ids);
 	} else {
 		int j, count;
 
@@ -893,7 +893,7 @@ static int add_metric(struct list_head *group_list,
 		 */
 
 		for (j = 0; j < count && !ret; j++) {
-			ret = __add_metric(group_list, pe, metric_no_group, j, egp, parent, ids);
+			ret = __add_metric(group_list, pe, metric_no_group, j, m, parent, ids);
 		}
 	}
 
@@ -908,16 +908,16 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 {
 	struct expr_ids ids = { 0 };
 	struct pmu_event *pe;
-	struct egroup *eg;
+	struct metric *m;
 	LIST_HEAD(list);
 	int i, ret;
 	bool has_match = false;
 
 	map_for_each_metric(pe, i, map, metric) {
 		has_match = true;
-		eg = NULL;
+		m = NULL;
 
-		ret = add_metric(&list, pe, metric_no_group, &eg, NULL, &ids);
+		ret = add_metric(&list, pe, metric_no_group, &m, NULL, &ids);
 		if (ret)
 			return ret;
 
@@ -925,7 +925,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		 * Process any possible referenced metrics
 		 * included in the expression.
 		 */
-		ret = resolve_metric(eg, metric_no_group,
+		ret = resolve_metric(m, metric_no_group,
 				     &list, map, &ids);
 		if (ret)
 			return ret;
@@ -935,16 +935,16 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 	if (!has_match)
 		return -EINVAL;
 
-	list_for_each_entry(eg, &list, nd) {
+	list_for_each_entry(m, &list, nd) {
 		if (events->len > 0)
 			strbuf_addf(events, ",");
 
-		if (eg->has_constraint) {
+		if (m->has_constraint) {
 			metricgroup__add_metric_non_group(events,
-							  &eg->pctx);
+							  &m->pctx);
 		} else {
 			metricgroup__add_metric_weak_group(events,
-							   &eg->pctx);
+							   &m->pctx);
 		}
 	}
 
@@ -986,25 +986,25 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 	return ret;
 }
 
-static void egroup__free_refs(struct egroup *egroup)
+static void metric__free_refs(struct metric *metric)
 {
 	struct metric_ref_node *ref, *tmp;
 
-	list_for_each_entry_safe(ref, tmp, &egroup->metric_refs, list) {
+	list_for_each_entry_safe(ref, tmp, &metric->metric_refs, list) {
 		list_del(&ref->list);
 		free(ref);
 	}
 }
 
-static void metricgroup__free_egroups(struct list_head *group_list)
+static void metricgroup__free_metrics(struct list_head *group_list)
 {
-	struct egroup *eg, *egtmp;
+	struct metric *m, *tmp;
 
-	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);
+	list_for_each_entry_safe (m, tmp, group_list, nd) {
+		metric__free_refs(m);
+		expr__ctx_clear(&m->pctx);
+		list_del_init(&m->nd);
+		free(m);
 	}
 }
 
@@ -1037,7 +1037,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 	ret = metricgroup__setup_events(&group_list, metric_no_merge,
 					perf_evlist, metric_events);
 out:
-	metricgroup__free_egroups(&group_list);
+	metricgroup__free_metrics(&group_list);
 	return ret;
 }
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH 19/19] perf metric: Rename group_list to metric_list
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (17 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 18/19] perf metric: Rename struct egroup to metric Jiri Olsa
@ 2020-07-19 18:13 ` Jiri Olsa
  2020-07-19 22:42   ` Ian Rogers
  2020-07-26  9:21   ` kajoljain
  2020-07-20  6:44 ` [PATCHv3 00/19] perf metric: Add support to reuse metric kajoljain
  2020-07-21 14:48 ` Paul A. Clarke
  20 siblings, 2 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-19 18:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Following the previous change that rename egroup
to metric, there's no reason to call the list
'group_list' anymore, renaming it to metric_list.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 42 +++++++++++++++++------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 9d5fff36042d..6f179b9903a0 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -639,7 +639,7 @@ int __weak arch_get_runtimeparam(void)
 	return 1;
 }
 
-static int __add_metric(struct list_head *group_list,
+static int __add_metric(struct list_head *metric_list,
 			struct pmu_event *pe,
 			bool metric_no_group,
 			int runtime,
@@ -726,13 +726,13 @@ static int __add_metric(struct list_head *group_list,
 	if (m->metric_refs_cnt)
 		return 0;
 
-	if (list_empty(group_list))
-		list_add(&m->nd, group_list);
+	if (list_empty(metric_list))
+		list_add(&m->nd, metric_list);
 	else {
 		struct list_head *pos;
 
 		/* Place the largest groups at the front. */
-		list_for_each_prev(pos, group_list) {
+		list_for_each_prev(pos, metric_list) {
 			struct metric *old = list_entry(pos, struct metric, nd);
 
 			if (hashmap__size(&m->pctx.ids) <=
@@ -813,7 +813,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa
 	return p->id ? 0 : -ENOMEM;
 }
 
-static int add_metric(struct list_head *group_list,
+static int add_metric(struct list_head *metric_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
 		      struct metric **mp,
@@ -822,7 +822,7 @@ static int add_metric(struct list_head *group_list,
 
 static int resolve_metric(struct metric *m,
 			  bool metric_no_group,
-			  struct list_head *group_list,
+			  struct list_head *metric_list,
 			  struct pmu_events_map *map,
 			  struct expr_ids *ids)
 {
@@ -854,7 +854,7 @@ static int resolve_metric(struct metric *m,
 			expr__del_id(&m->pctx, cur->key);
 
 			/* ... and it gets resolved to the parent context. */
-			ret = add_metric(group_list, pe, metric_no_group, &m, parent, ids);
+			ret = add_metric(metric_list, pe, metric_no_group, &m, parent, ids);
 			if (ret)
 				return ret;
 
@@ -869,7 +869,7 @@ static int resolve_metric(struct metric *m,
 	return 0;
 }
 
-static int add_metric(struct list_head *group_list,
+static int add_metric(struct list_head *metric_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
 		      struct metric **m,
@@ -881,7 +881,7 @@ static int add_metric(struct list_head *group_list,
 	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, m, parent, ids);
+		ret = __add_metric(metric_list, pe, metric_no_group, 1, m, parent, ids);
 	} else {
 		int j, count;
 
@@ -889,11 +889,11 @@ static int add_metric(struct list_head *group_list,
 
 		/* This loop is added to create multiple
 		 * events depend on count value and add
-		 * those events to group_list.
+		 * those events to metric_list.
 		 */
 
 		for (j = 0; j < count && !ret; j++) {
-			ret = __add_metric(group_list, pe, metric_no_group, j, m, parent, ids);
+			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
 		}
 	}
 
@@ -902,7 +902,7 @@ static int add_metric(struct list_head *group_list,
 
 static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 				   struct strbuf *events,
-				   struct list_head *group_list,
+				   struct list_head *metric_list,
 				   struct pmu_events_map *map)
 
 {
@@ -948,14 +948,14 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		}
 	}
 
-	list_splice(&list, group_list);
+	list_splice(&list, metric_list);
 	expr_ids__exit(&ids);
 	return 0;
 }
 
 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 					struct strbuf *events,
-					struct list_head *group_list,
+					struct list_head *metric_list,
 					struct pmu_events_map *map)
 {
 	char *llist, *nlist, *p;
@@ -971,7 +971,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
 
 	while ((p = strsep(&llist, ",")) != NULL) {
 		ret = metricgroup__add_metric(p, metric_no_group, events,
-					      group_list, map);
+					      metric_list, map);
 		if (ret == -EINVAL) {
 			fprintf(stderr, "Cannot find metric or group `%s'\n",
 					p);
@@ -996,11 +996,11 @@ static void metric__free_refs(struct metric *metric)
 	}
 }
 
-static void metricgroup__free_metrics(struct list_head *group_list)
+static void metricgroup__free_metrics(struct list_head *metric_list)
 {
 	struct metric *m, *tmp;
 
-	list_for_each_entry_safe (m, tmp, group_list, nd) {
+	list_for_each_entry_safe (m, tmp, metric_list, nd) {
 		metric__free_refs(m);
 		expr__ctx_clear(&m->pctx);
 		list_del_init(&m->nd);
@@ -1017,13 +1017,13 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 {
 	struct parse_events_error parse_error;
 	struct strbuf extra_events;
-	LIST_HEAD(group_list);
+	LIST_HEAD(metric_list);
 	int ret;
 
 	if (metric_events->nr_entries == 0)
 		metricgroup__rblist_init(metric_events);
 	ret = metricgroup__add_metric_list(str, metric_no_group,
-					   &extra_events, &group_list, map);
+					   &extra_events, &metric_list, map);
 	if (ret)
 		return ret;
 	pr_debug("adding %s\n", extra_events.buf);
@@ -1034,10 +1034,10 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
 		goto out;
 	}
 	strbuf_release(&extra_events);
-	ret = metricgroup__setup_events(&group_list, metric_no_merge,
+	ret = metricgroup__setup_events(&metric_list, metric_no_merge,
 					perf_evlist, metric_events);
 out:
-	metricgroup__free_metrics(&group_list);
+	metricgroup__free_metrics(&metric_list);
 	return ret;
 }
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function
  2020-07-19 18:13 ` [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function Jiri Olsa
@ 2020-07-19 21:41   ` Ian Rogers
  2020-07-28 12:26     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 21:41 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Arnaldo Carvalho de Melo, lkml,
	Ingo Molnar, Namhyung Kim, Alexander Shishkin, Peter Zijlstra,
	Michael Petlan, Andi Kleen, Kajol Jain, John Garry,
	Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Arnaldo found that we don't release value data in case the
> hashmap__set fails. Releasing it in case of an error.
>
> Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

> ---
>  tools/perf/util/expr.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index 5d05f9765ed8..578a173d4873 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -47,6 +47,8 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>         }
>         ret = hashmap__set(&ctx->ids, id, data_ptr,
>                            (const void **)&old_key, (void **)&old_data);
> +       if (ret)
> +               free(data_ptr);
>         free(old_key);
>         free(old_data);
>         return ret;
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 05/19] perf metric: Add macros for iterating map events
  2020-07-19 18:13 ` [PATCH 05/19] perf metric: Add macros for iterating map events Jiri Olsa
@ 2020-07-19 21:46   ` Ian Rogers
  2020-07-28 12:29     ` Arnaldo Carvalho de Melo
  2020-07-26  9:17   ` kajoljain
  1 sibling, 1 reply; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 21:46 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding following macros to iterate events and metric:
>   map_for_each_event(__pe, __idx, __map)
>     - iterates over all pmu_events_map events
>   map_for_each_metric(__pe, __idx, __map, __metric)
>     - iterates over all metrics that match __metric argument
>
> and use it in metricgroup__add_metric function. Macros
> will be be used from other places in following changes.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

Thanks!
Ian

> ---
>  tools/perf/util/metricgroup.c | 77 ++++++++++++++++++-----------------
>  1 file changed, 40 insertions(+), 37 deletions(-)
>
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index df0356ec120d..b37008fc253c 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -614,6 +614,17 @@ static int __metricgroup__add_metric(struct list_head *group_list,
>         return 0;
>  }
>
> +#define map_for_each_event(__pe, __idx, __map)                         \
> +       for (__idx = 0, __pe = &__map->table[__idx];                    \
> +            __pe->name || __pe->metric_group || __pe->metric_name;     \
> +            __pe = &__map->table[++__idx])
> +
> +#define map_for_each_metric(__pe, __idx, __map, __metric)              \
> +       map_for_each_event(__pe, __idx, __map)                          \
> +               if (__pe->metric_expr &&                                \
> +                   (match_metric(__pe->metric_group, __metric) ||      \
> +                    match_metric(__pe->metric_name, __metric)))
> +
>  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                                    struct strbuf *events,
>                                    struct list_head *group_list,
> @@ -624,49 +635,41 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>         int i, ret;
>         bool has_match = false;
>
> -       for (i = 0; ; i++) {
> -               pe = &map->table[i];
> -
> -               if (!pe->name && !pe->metric_group && !pe->metric_name) {
> -                       /* End of pmu events. */
> -                       if (!has_match)
> -                               return -EINVAL;
> -                       break;
> -               }
> -               if (!pe->metric_expr)
> -                       continue;
> -               if (match_metric(pe->metric_group, metric) ||
> -                   match_metric(pe->metric_name, metric)) {
> -                       has_match = true;
> -                       pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> -
> -                       if (!strstr(pe->metric_expr, "?")) {
> -                               ret = __metricgroup__add_metric(group_list,
> -                                                               pe,
> -                                                               metric_no_group,
> -                                                               1);
> -                               if (ret)
> -                                       return ret;
> -                       } else {
> -                               int j, count;
> +       map_for_each_metric(pe, i, map, metric) {
> +               pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> +               has_match = true;
> +
> +               if (!strstr(pe->metric_expr, "?")) {
> +                       ret = __metricgroup__add_metric(group_list,
> +                                                       pe,
> +                                                       metric_no_group,
> +                                                       1);
> +                       if (ret)
> +                               return ret;
> +               } else {
> +                       int j, count;
>
> -                               count = arch_get_runtimeparam();
> +                       count = arch_get_runtimeparam();
>
> -                               /* This loop is added to create multiple
> -                                * events depend on count value and add
> -                                * those events to group_list.
> -                                */
> +                       /* This loop is added to create multiple
> +                        * events depend on count value and add
> +                        * those events to group_list.
> +                        */
>
> -                               for (j = 0; j < count; j++) {
> -                                       ret = __metricgroup__add_metric(
> -                                               group_list, pe,
> -                                               metric_no_group, j);
> -                                       if (ret)
> -                                               return ret;
> -                               }
> +                       for (j = 0; j < count; j++) {
> +                               ret = __metricgroup__add_metric(
> +                                       group_list, pe,
> +                                       metric_no_group, j);
> +                               if (ret)
> +                                       return ret;
>                         }
>                 }
>         }
> +
> +       /* End of pmu events. */
> +       if (!has_match)
> +               return -EINVAL;
> +
>         list_for_each_entry(eg, group_list, nd) {
>                 if (events->len > 0)
>                         strbuf_addf(events, ",");
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node
  2020-07-19 18:13 ` [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node Jiri Olsa
@ 2020-07-19 22:18   ` Ian Rogers
  2020-07-26  9:18     ` kajoljain
  2020-07-28 12:31     ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 22:18 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> 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>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/metricgroup.c | 170 +++++++++++++++++++++++++++++++---
>  1 file changed, 156 insertions(+), 14 deletions(-)
>
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index ccd80538a6ae..d1b2c1aa436f 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -102,12 +102,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;
>  };
> @@ -574,27 +587,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;
> +
> +               /*
> +                * 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;
>
> -       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);
> +               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 {
> @@ -625,16 +683,78 @@ 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,
> +                     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 add_metric(struct list_head *group_list,
>                       struct pmu_event *pe,
> -                     bool metric_no_group)
> +                     bool metric_no_group,
> +                     struct egroup **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;
>
> @@ -646,7 +766,7 @@ static int add_metric(struct list_head *group_list,
>                  */
>
>                 for (j = 0; j < count && !ret; j++) {
> -                       ret = __add_metric(group_list, pe, metric_no_group, j);
> +                       ret = __add_metric(group_list, pe, metric_no_group, j, egp);
>                 }
>         }
>
> @@ -657,6 +777,7 @@ 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)
> +
>  {
>         struct pmu_event *pe;
>         struct egroup *eg;
> @@ -665,8 +786,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);
> +               ret = add_metric(group_list, pe, metric_no_group, &eg);
> +               if (ret)
> +                       return ret;
> +
> +               /*
> +                * Process any possible referenced metrics
> +                * included in the expression.
> +                */
> +               ret = resolve_metric(eg, metric_no_group,
> +                                    group_list, map);
>                 if (ret)
>                         return ret;
>         }
> @@ -723,11 +854,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.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 10/19] perf metric: Add referenced metrics to hash data
  2020-07-19 18:13 ` [PATCH 10/19] perf metric: Add referenced metrics to hash data Jiri Olsa
@ 2020-07-19 22:32   ` Ian Rogers
  2020-07-26  9:18     ` kajoljain
  2020-07-28 12:32     ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 22:32 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding referenced metrics to the parsing context so they
> can be resolved during the metric processing.
>
> Adding expr__add_ref function to store referenced metrics
> into parse context.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/expr.c        | 54 +++++++++++++++++++++++++++++++++++
>  tools/perf/util/expr.h        | 13 ++++++++-
>  tools/perf/util/stat-shadow.c | 20 +++++++++----
>  3 files changed, 80 insertions(+), 7 deletions(-)
>
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index f726211f49d4..d3997c2b4a90 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -4,10 +4,14 @@
>  #include <errno.h>
>  #include <stdlib.h>
>  #include <string.h>
> +#include "metricgroup.h"
> +#include "debug.h"
>  #include "expr.h"
>  #include "expr-bison.h"
>  #include "expr-flex.h"
>  #include <linux/kernel.h>
> +#include <linux/zalloc.h>
> +#include <ctype.h>
>
>  #ifdef PARSER_DEBUG
>  extern int expr_debug;
> @@ -63,6 +67,7 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>         if (!data_ptr)
>                 return -ENOMEM;
>         data_ptr->val = val;
> +       data_ptr->is_ref = false;
>
>         ret = hashmap__set(&ctx->ids, id, data_ptr,
>                            (const void **)&old_key, (void **)&old_data);
> @@ -73,6 +78,55 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>         return ret;
>  }
>
> +int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
> +{
> +       struct expr_id_data *data_ptr = NULL, *old_data = NULL;
> +       char *old_key = NULL;
> +       char *name, *p;
> +       int ret;
> +
> +       data_ptr = zalloc(sizeof(*data_ptr));
> +       if (!data_ptr)
> +               return -ENOMEM;
> +
> +       name = strdup(ref->metric_name);
> +       if (!name) {
> +               free(data_ptr);
> +               return -ENOMEM;
> +       }
> +
> +       /*
> +        * The jevents tool converts all metric expressions
> +        * to lowercase, including metric references, hence
> +        * we need to add lowercase name for metric, so it's
> +        * properly found.
> +        */
> +       for (p = name; *p; p++)
> +               *p = tolower(*p);
> +
> +       /*
> +        * Intentionally passing just const char pointers,
> +        * originally from 'struct pmu_event' object.
> +        * We don't need to change them, so there's no
> +        * need to create our own copy.
> +        */
> +       data_ptr->ref.metric_name = ref->metric_name;
> +       data_ptr->ref.metric_expr = ref->metric_expr;
> +       data_ptr->is_ref = true;
> +
> +       ret = hashmap__set(&ctx->ids, name, data_ptr,
> +                          (const void **)&old_key, (void **)&old_data);
> +       if (ret)
> +               free(data_ptr);
> +
> +       pr_debug2("adding ref metric %s: %s\n",
> +                 ref->metric_name, ref->metric_expr);
> +
> +       free(old_key);
> +       free(old_data);
> +       return ret;
> +}
> +
>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>                  struct expr_id_data **data)
>  {
> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> index 2462abd0ac65..81d04ff7f857 100644
> --- a/tools/perf/util/expr.h
> +++ b/tools/perf/util/expr.h
> @@ -11,12 +11,22 @@
>  #include "util/hashmap.h"
>  //#endif
>
> +struct metric_ref;
> +
>  struct expr_parse_ctx {
>         struct hashmap ids;
>  };
>
>  struct expr_id_data {
> -       double  val;
> +       union {
> +               double val;
> +               struct {
> +                       const char *metric_name;
> +                       const char *metric_expr;
> +               } ref;
> +       };
> +
> +       bool is_ref;
>  };
>
>  struct expr_scanner_ctx {
> @@ -29,6 +39,7 @@ void expr__ctx_clear(struct expr_parse_ctx *ctx);
>  void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
>  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
>  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> +int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>                  struct expr_id_data **data);
>  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
> index fc9ac4b4218e..e1ba6c1b916a 100644
> --- a/tools/perf/util/stat-shadow.c
> +++ b/tools/perf/util/stat-shadow.c
> @@ -731,13 +731,14 @@ static void print_smi_cost(struct perf_stat_config *config,
>  }
>
>  static int prepare_metric(struct evsel **metric_events,
> +                         struct metric_ref *metric_refs,
>                           struct expr_parse_ctx *pctx,
>                           int cpu,
>                           struct runtime_stat *st)
>  {
>         double scale;
>         char *n, *pn;
> -       int i;
> +       int i, j, ret;
>
>         expr__ctx_init(pctx);
>         for (i = 0; metric_events[i]; i++) {
> @@ -778,12 +779,19 @@ static int prepare_metric(struct evsel **metric_events,
>                         expr__add_id_val(pctx, n, avg_stats(stats)*scale);
>         }
>
> +       for (j = 0; metric_refs && metric_refs[j].metric_name; j++) {
> +               ret = expr__add_ref(pctx, &metric_refs[j]);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         return i;
>  }
>
>  static void generic_metric(struct perf_stat_config *config,
>                            const char *metric_expr,
>                            struct evsel **metric_events,
> +                          struct metric_ref *metric_refs,
>                            char *name,
>                            const char *metric_name,
>                            const char *metric_unit,
> @@ -798,7 +806,7 @@ static void generic_metric(struct perf_stat_config *config,
>         int i;
>         void *ctxp = out->ctx;
>
> -       i = prepare_metric(metric_events, &pctx, cpu, st);
> +       i = prepare_metric(metric_events, metric_refs, &pctx, cpu, st);
>         if (i < 0)
>                 return;
>
> @@ -847,7 +855,7 @@ double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_sta
>         struct expr_parse_ctx pctx;
>         double ratio;
>
> -       if (prepare_metric(mexp->metric_events, &pctx, cpu, st) < 0)
> +       if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0)
>                 return 0.;
>
>         if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1))
> @@ -1064,8 +1072,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
>                 else
>                         print_metric(config, ctxp, NULL, NULL, name, 0);
>         } else if (evsel->metric_expr) {
> -               generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name,
> -                               evsel->metric_name, NULL, 1, cpu, out, st);
> +               generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
> +                               evsel->name, evsel->metric_name, NULL, 1, cpu, out, st);
>         } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) {
>                 char unit = 'M';
>                 char unit_buf[10];
> @@ -1093,7 +1101,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
>                         if (num++ > 0)
>                                 out->new_line(config, ctxp);
>                         generic_metric(config, mexp->metric_expr, mexp->metric_events,
> -                                       evsel->name, mexp->metric_name,
> +                                       mexp->metric_refs, evsel->name, mexp->metric_name,
>                                         mexp->metric_unit, mexp->runtime, cpu, out, st);
>                 }
>         }
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 12/19] perf metric: Add events for the current list
  2020-07-19 18:13 ` [PATCH 12/19] perf metric: Add events for the current list Jiri Olsa
@ 2020-07-19 22:34   ` Ian Rogers
  2020-07-26  9:19     ` kajoljain
  2020-07-28 12:33     ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 22:34 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> There's no need to iterate the whole list of groups,
> when adding new events. The currently created groups
> are the ones we want to add.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/metricgroup.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index bb5757b9419d..332414d93f7a 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -813,6 +813,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  {
>         struct pmu_event *pe;
>         struct egroup *eg;
> +       LIST_HEAD(list);
>         int i, ret;
>         bool has_match = false;
>
> @@ -820,7 +821,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                 has_match = true;
>                 eg = NULL;
>
> -               ret = add_metric(group_list, pe, metric_no_group, &eg);
> +               ret = add_metric(&list, pe, metric_no_group, &eg);
>                 if (ret)
>                         return ret;
>
> @@ -829,7 +830,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                  * included in the expression.
>                  */
>                 ret = resolve_metric(eg, metric_no_group,
> -                                    group_list, map);
> +                                    &list, map);
>                 if (ret)
>                         return ret;
>         }
> @@ -838,7 +839,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>         if (!has_match)
>                 return -EINVAL;
>
> -       list_for_each_entry(eg, group_list, nd) {
> +       list_for_each_entry(eg, &list, nd) {
>                 if (events->len > 0)
>                         strbuf_addf(events, ",");
>
> @@ -850,6 +851,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                                                            &eg->pctx);
>                 }
>         }
> +
> +       list_splice(&list, group_list);
>         return 0;
>  }
>
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 15/19] perf metric: Add recursion check when processing nested metrics
  2020-07-19 18:13 ` [PATCH 15/19] perf metric: Add recursion check when processing nested metrics Jiri Olsa
@ 2020-07-19 22:40   ` Ian Rogers
  2020-07-26  9:20     ` kajoljain
  2020-07-28 12:35     ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 22:40 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Keeping the stack of nested metrics via 'struct expr_id' objects
> and checking if we are in recursion via already processed metric.
>
> The stack is implemented as static array within the struct egroup
> with 100 entries, which should be enough nesting depth for any
> metric we have or plan to have at the moment.
>
> Adding test that simulates the recursion and checks we can
> detect it.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/tests/parse-metric.c |  34 +++++++++-
>  tools/perf/util/expr.c          |   2 +
>  tools/perf/util/expr.h          |   9 ++-
>  tools/perf/util/metricgroup.c   | 117 +++++++++++++++++++++++++++++---
>  4 files changed, 149 insertions(+), 13 deletions(-)
>
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index aa4d5a9f09a8..01370ccb9ed9 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -57,6 +57,18 @@ static struct pmu_event pme_test[] = {
>         .metric_expr    = "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
>         .metric_name    = "DCache_L2_Misses",
>  },
> +{
> +       .metric_expr    = "ipc + m2",
> +       .metric_name    = "M1",
> +},
> +{
> +       .metric_expr    = "ipc + m1",
> +       .metric_name    = "M2",
> +},
> +{
> +       .metric_expr    = "1/m3",
> +       .metric_name    = "M3",
> +}
>  };
>
>  static struct pmu_events_map map = {
> @@ -139,8 +151,8 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>         err = metricgroup__parse_groups_test(evlist, &map, name,
>                                              false, false,
>                                              &metric_events);
> -
> -       TEST_ASSERT_VAL("failed to parse metric", err == 0);
> +       if (err)
> +               return err;
>
>         if (perf_evlist__alloc_stats(evlist, false))
>                 return -1;
> @@ -264,11 +276,29 @@ static int test_dcache_l2(void)
>         return 0;
>  }
>
> +static int test_recursion_fail(void)
> +{
> +       double ratio;
> +       struct value vals[] = {
> +               { .event = "inst_retired.any",        .val = 300 },
> +               { .event = "cpu_clk_unhalted.thread", .val = 200 },
> +               { 0 },
> +       };
> +
> +       TEST_ASSERT_VAL("failed to find recursion",
> +                       compute_metric("M1", vals, &ratio) == -1);
> +
> +       TEST_ASSERT_VAL("failed to find recursion",
> +                       compute_metric("M3", vals, &ratio) == -1);
> +       return 0;
> +}
> +
>  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>  {
>         TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
>         TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
>         TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>         TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
> +       TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
>         return 0;
>  }
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index a346ca590513..53482ef53c41 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -47,6 +47,8 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
>         if (!data_ptr)
>                 return -ENOMEM;
>
> +       data_ptr->parent = ctx->parent;
> +
>         ret = hashmap__set(&ctx->ids, id, data_ptr,
>                            (const void **)&old_key, (void **)&old_data);
>         if (ret)
> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> index 9ed208d93418..fc2b5e824a66 100644
> --- a/tools/perf/util/expr.h
> +++ b/tools/perf/util/expr.h
> @@ -13,8 +13,14 @@
>
>  struct metric_ref;
>
> +struct expr_id {
> +       char            *id;
> +       struct expr_id  *parent;
> +};
> +
>  struct expr_parse_ctx {
> -       struct hashmap ids;
> +       struct hashmap   ids;
> +       struct expr_id  *parent;
>  };
>
>  struct expr_id_data {
> @@ -25,6 +31,7 @@ struct expr_id_data {
>                         const char *metric_expr;
>                         bool counted;
>                 } ref;
> +               struct expr_id  *parent;
>         };
>
>         bool is_ref;
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 332414d93f7a..2a45ee94fd61 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -24,6 +24,7 @@
>  #include <subcmd/parse-options.h>
>  #include <api/fs/fs.h>
>  #include "util.h"
> +#include <asm/bug.h>
>
>  struct metric_event *metricgroup__lookup(struct rblist *metric_events,
>                                          struct evsel *evsel,
> @@ -126,6 +127,28 @@ struct egroup {
>         bool has_constraint;
>  };
>
> +#define RECURSION_ID_MAX 100
> +
> +struct expr_ids {
> +       struct expr_id  id[RECURSION_ID_MAX];
> +       int             cnt;
> +};
> +
> +static struct expr_id *expr_ids__alloc(struct expr_ids *ids)
> +{
> +       if (ids->cnt >= RECURSION_ID_MAX)
> +               return NULL;
> +       return &ids->id[ids->cnt++];
> +}
> +
> +static void expr_ids__exit(struct expr_ids *ids)
> +{
> +       int i;
> +
> +       for (i = 0; i < ids->cnt; i++)
> +               free(ids->id[i].id);
> +}
> +
>  /**
>   * Find a group of events in perf_evlist that correpond to those from a parsed
>   * metric expression. Note, as find_evsel_group is called in the same order as
> @@ -620,7 +643,9 @@ static int __add_metric(struct list_head *group_list,
>                         struct pmu_event *pe,
>                         bool metric_no_group,
>                         int runtime,
> -                       struct egroup **egp)
> +                       struct egroup **egp,
> +                       struct expr_id *parent,
> +                       struct expr_ids *ids)
>  {
>         struct metric_ref_node *ref;
>         struct egroup *eg;
> @@ -630,7 +655,7 @@ static int __add_metric(struct list_head *group_list,
>                  * We got in here for the parent group,
>                  * allocate it and put it on the list.
>                  */
> -               eg = malloc(sizeof(*eg));
> +               eg = zalloc(sizeof(*eg));
>                 if (!eg)
>                         return -ENOMEM;
>
> @@ -643,6 +668,18 @@ static int __add_metric(struct list_head *group_list,
>                 INIT_LIST_HEAD(&eg->metric_refs);
>                 eg->metric_refs_cnt = 0;
>                 *egp = eg;
> +
> +               parent = expr_ids__alloc(ids);
> +               if (!parent) {
> +                       free(eg);
> +                       return -EINVAL;
> +               }
> +
> +               parent->id = strdup(pe->metric_name);
> +               if (!parent->id) {
> +                       free(eg);
> +                       return -ENOMEM;
> +               }
>         } else {
>                 /*
>                  * We got here for the referenced metric, via the
> @@ -668,6 +705,10 @@ static int __add_metric(struct list_head *group_list,
>                 eg->metric_refs_cnt++;
>         }
>
> +       /* Force all found IDs in metric to have us as parent ID. */
> +       WARN_ON_ONCE(!parent);
> +       eg->pctx.parent = parent;
> +
>         /*
>          * For both the parent and referenced metrics, we parse
>          * all the metric's IDs and add it to the parent context.
> @@ -728,15 +769,62 @@ static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *
>         return NULL;
>  }
>
> +static int recursion_check(struct egroup *eg, const char *id, struct expr_id **parent,
> +                          struct expr_ids *ids)
> +{
> +       struct expr_id_data *data;
> +       struct expr_id *p;
> +       int ret;
> +
> +       /*
> +        * We get the parent referenced by 'id' argument and
> +        * traverse through all the parent object IDs to check
> +        * if we already processed 'id', if we did, it's recursion
> +        * and we fail.
> +        */
> +       ret = expr__get_id(&eg->pctx, id, &data);
> +       if (ret)
> +               return ret;
> +
> +       p = data->parent;
> +
> +       while (p->parent) {
> +               if (!strcmp(p->id, id)) {
> +                       pr_err("failed: recursion detected for %s\n", id);
> +                       return -1;
> +               }
> +               p = p->parent;
> +       }
> +
> +       /*
> +        * If we are over the limit of static entris, the metric
> +        * is too difficult/nested to process, fail as well.
> +        */
> +       p = expr_ids__alloc(ids);
> +       if (!p) {
> +               pr_err("failed: too many nested metrics\n");
> +               return -EINVAL;
> +       }
> +
> +       p->id     = strdup(id);
> +       p->parent = data->parent;
> +       *parent   = p;
> +
> +       return p->id ? 0 : -ENOMEM;
> +}
> +
>  static int add_metric(struct list_head *group_list,
>                       struct pmu_event *pe,
>                       bool metric_no_group,
> -                     struct egroup **egp);
> +                     struct egroup **egp,
> +                     struct expr_id *parent,
> +                     struct expr_ids *ids);
>
>  static int resolve_metric(struct egroup *eg,
>                           bool metric_no_group,
>                           struct list_head *group_list,
> -                         struct pmu_events_map *map)
> +                         struct pmu_events_map *map,
> +                         struct expr_ids *ids)
>  {
>         struct hashmap_entry *cur;
>         size_t bkt;
> @@ -750,18 +838,23 @@ static int resolve_metric(struct egroup *eg,
>         do {
>                 all = true;
>                 hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
> +                       struct expr_id *parent;
>                         struct pmu_event *pe;
>
>                         pe = find_metric(cur->key, map);
>                         if (!pe)
>                                 continue;
>
> +                       ret = recursion_check(eg, cur->key, &parent, ids);
> +                       if (ret)
> +                               return ret;
> +
>                         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);
> +                       ret = add_metric(group_list, pe, metric_no_group, &eg, parent, ids);
>                         if (ret)
>                                 return ret;
>
> @@ -779,14 +872,16 @@ static int resolve_metric(struct egroup *eg,
>  static int add_metric(struct list_head *group_list,
>                       struct pmu_event *pe,
>                       bool metric_no_group,
> -                     struct egroup **egp)
> +                     struct egroup **egp,
> +                     struct expr_id *parent,
> +                     struct expr_ids *ids)
>  {
>         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, egp);
> +               ret = __add_metric(group_list, pe, metric_no_group, 1, egp, parent, ids);
>         } else {
>                 int j, count;
>
> @@ -798,7 +893,7 @@ static int add_metric(struct list_head *group_list,
>                  */
>
>                 for (j = 0; j < count && !ret; j++) {
> -                       ret = __add_metric(group_list, pe, metric_no_group, j, egp);
> +                       ret = __add_metric(group_list, pe, metric_no_group, j, egp, parent, ids);
>                 }
>         }
>
> @@ -811,6 +906,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                                    struct pmu_events_map *map)
>
>  {
> +       struct expr_ids ids = { 0 };
>         struct pmu_event *pe;
>         struct egroup *eg;
>         LIST_HEAD(list);
> @@ -821,7 +917,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                 has_match = true;
>                 eg = NULL;
>
> -               ret = add_metric(&list, pe, metric_no_group, &eg);
> +               ret = add_metric(&list, pe, metric_no_group, &eg, NULL, &ids);
>                 if (ret)
>                         return ret;
>
> @@ -830,7 +926,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                  * included in the expression.
>                  */
>                 ret = resolve_metric(eg, metric_no_group,
> -                                    &list, map);
> +                                    &list, map, &ids);
>                 if (ret)
>                         return ret;
>         }
> @@ -853,6 +949,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>         }
>
>         list_splice(&list, group_list);
> +       expr_ids__exit(&ids);
>         return 0;
>  }
>
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 17/19] perf metric: Add metric group test
  2020-07-19 18:13 ` [PATCH 17/19] perf metric: Add metric group test Jiri Olsa
@ 2020-07-19 22:41   ` Ian Rogers
  2020-07-26  9:20     ` kajoljain
  2020-07-28 12:37     ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 22:41 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding test for metric group plus compute_metric_group
> function to get metrics values within the group.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/tests/parse-metric.c | 48 +++++++++++++++++++++++++++++++--
>  1 file changed, 46 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 5ac32f80f8ea..f2ba5b2c5557 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -18,6 +18,7 @@ static struct pmu_event pme_test[] = {
>  {
>         .metric_expr    = "inst_retired.any / cpu_clk_unhalted.thread",
>         .metric_name    = "IPC",
> +       .metric_group   = "group1",
>  },
>  {
>         .metric_expr    = "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
> @@ -35,6 +36,7 @@ static struct pmu_event pme_test[] = {
>  {
>         .metric_expr    = "(dcache_miss_cpi + icache_miss_cycles)",
>         .metric_name    = "cache_miss_cycles",
> +       .metric_group   = "group1",
>  },
>  {
>         .metric_expr    = "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
> @@ -127,7 +129,9 @@ static double compute_single(struct rblist *metric_events, struct evlist *evlist
>         return 0.;
>  }
>
> -static int compute_metric(const char *name, struct value *vals, double *ratio)
> +static int __compute_metric(const char *name, struct value *vals,
> +                           const char *name1, double *ratio1,
> +                           const char *name2, double *ratio2)
>  {
>         struct rblist metric_events = {
>                 .nr_entries = 0,
> @@ -166,7 +170,10 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>         load_runtime_stat(&st, evlist, vals);
>
>         /* And execute the metric */
> -       *ratio = compute_single(&metric_events, evlist, &st, name);
> +       if (name1 && ratio1)
> +               *ratio1 = compute_single(&metric_events, evlist, &st, name1);
> +       if (name2 && ratio2)
> +               *ratio2 = compute_single(&metric_events, evlist, &st, name2);
>
>         /* ... clenup. */
>         metricgroup__rblist_exit(&metric_events);
> @@ -177,6 +184,18 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>         return 0;
>  }
>
> +static int compute_metric(const char *name, struct value *vals, double *ratio)
> +{
> +       return __compute_metric(name, vals, name, ratio, NULL, NULL);
> +}
> +
> +static int compute_metric_group(const char *name, struct value *vals,
> +                               const char *name1, double *ratio1,
> +                               const char *name2, double *ratio2)
> +{
> +       return __compute_metric(name, vals, name1, ratio1, name2, ratio2);
> +}
> +
>  static int test_ipc(void)
>  {
>         double ratio;
> @@ -297,6 +316,30 @@ static int test_recursion_fail(void)
>         return 0;
>  }
>
> +static int test_metric_group(void)
> +{
> +       double ratio1, ratio2;
> +       struct value vals[] = {
> +               { .event = "cpu_clk_unhalted.thread", .val = 200 },
> +               { .event = "l1d-loads-misses",        .val = 300 },
> +               { .event = "l1i-loads-misses",        .val = 200 },
> +               { .event = "inst_retired.any",        .val = 400 },
> +               { 0 },
> +       };
> +
> +       TEST_ASSERT_VAL("failed to find recursion",
> +                       compute_metric_group("group1", vals,
> +                                            "IPC", &ratio1,
> +                                            "cache_miss_cycles", &ratio2) == 0);
> +
> +       TEST_ASSERT_VAL("group IPC failed, wrong ratio",
> +                       ratio1 == 2.0);
> +
> +       TEST_ASSERT_VAL("group cache_miss_cycles failed, wrong ratio",
> +                       ratio2 == 1.25);
> +       return 0;
> +}
> +
>  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>  {
>         TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
> @@ -304,5 +347,6 @@ int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unu
>         TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>         TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
>         TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
> +       TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
>         return 0;
>  }
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 19/19] perf metric: Rename group_list to metric_list
  2020-07-19 18:13 ` [PATCH 19/19] perf metric: Rename group_list to metric_list Jiri Olsa
@ 2020-07-19 22:42   ` Ian Rogers
  2020-07-26  9:21   ` kajoljain
  1 sibling, 0 replies; 88+ messages in thread
From: Ian Rogers @ 2020-07-19 22:42 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Paul A. Clarke, Stephane Eranian

On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Following the previous change that rename egroup
> to metric, there's no reason to call the list
> 'group_list' anymore, renaming it to metric_list.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/metricgroup.c | 42 +++++++++++++++++------------------
>  1 file changed, 21 insertions(+), 21 deletions(-)
>
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 9d5fff36042d..6f179b9903a0 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -639,7 +639,7 @@ int __weak arch_get_runtimeparam(void)
>         return 1;
>  }
>
> -static int __add_metric(struct list_head *group_list,
> +static int __add_metric(struct list_head *metric_list,
>                         struct pmu_event *pe,
>                         bool metric_no_group,
>                         int runtime,
> @@ -726,13 +726,13 @@ static int __add_metric(struct list_head *group_list,
>         if (m->metric_refs_cnt)
>                 return 0;
>
> -       if (list_empty(group_list))
> -               list_add(&m->nd, group_list);
> +       if (list_empty(metric_list))
> +               list_add(&m->nd, metric_list);
>         else {
>                 struct list_head *pos;
>
>                 /* Place the largest groups at the front. */
> -               list_for_each_prev(pos, group_list) {
> +               list_for_each_prev(pos, metric_list) {
>                         struct metric *old = list_entry(pos, struct metric, nd);
>
>                         if (hashmap__size(&m->pctx.ids) <=
> @@ -813,7 +813,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa
>         return p->id ? 0 : -ENOMEM;
>  }
>
> -static int add_metric(struct list_head *group_list,
> +static int add_metric(struct list_head *metric_list,
>                       struct pmu_event *pe,
>                       bool metric_no_group,
>                       struct metric **mp,
> @@ -822,7 +822,7 @@ static int add_metric(struct list_head *group_list,
>
>  static int resolve_metric(struct metric *m,
>                           bool metric_no_group,
> -                         struct list_head *group_list,
> +                         struct list_head *metric_list,
>                           struct pmu_events_map *map,
>                           struct expr_ids *ids)
>  {
> @@ -854,7 +854,7 @@ static int resolve_metric(struct metric *m,
>                         expr__del_id(&m->pctx, cur->key);
>
>                         /* ... and it gets resolved to the parent context. */
> -                       ret = add_metric(group_list, pe, metric_no_group, &m, parent, ids);
> +                       ret = add_metric(metric_list, pe, metric_no_group, &m, parent, ids);
>                         if (ret)
>                                 return ret;
>
> @@ -869,7 +869,7 @@ static int resolve_metric(struct metric *m,
>         return 0;
>  }
>
> -static int add_metric(struct list_head *group_list,
> +static int add_metric(struct list_head *metric_list,
>                       struct pmu_event *pe,
>                       bool metric_no_group,
>                       struct metric **m,
> @@ -881,7 +881,7 @@ static int add_metric(struct list_head *group_list,
>         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, m, parent, ids);
> +               ret = __add_metric(metric_list, pe, metric_no_group, 1, m, parent, ids);
>         } else {
>                 int j, count;
>
> @@ -889,11 +889,11 @@ static int add_metric(struct list_head *group_list,
>
>                 /* This loop is added to create multiple
>                  * events depend on count value and add
> -                * those events to group_list.
> +                * those events to metric_list.
>                  */
>
>                 for (j = 0; j < count && !ret; j++) {
> -                       ret = __add_metric(group_list, pe, metric_no_group, j, m, parent, ids);
> +                       ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
>                 }
>         }
>
> @@ -902,7 +902,7 @@ static int add_metric(struct list_head *group_list,
>
>  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                                    struct strbuf *events,
> -                                  struct list_head *group_list,
> +                                  struct list_head *metric_list,
>                                    struct pmu_events_map *map)
>
>  {
> @@ -948,14 +948,14 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>                 }
>         }
>
> -       list_splice(&list, group_list);
> +       list_splice(&list, metric_list);
>         expr_ids__exit(&ids);
>         return 0;
>  }
>
>  static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>                                         struct strbuf *events,
> -                                       struct list_head *group_list,
> +                                       struct list_head *metric_list,
>                                         struct pmu_events_map *map)
>  {
>         char *llist, *nlist, *p;
> @@ -971,7 +971,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>
>         while ((p = strsep(&llist, ",")) != NULL) {
>                 ret = metricgroup__add_metric(p, metric_no_group, events,
> -                                             group_list, map);
> +                                             metric_list, map);
>                 if (ret == -EINVAL) {
>                         fprintf(stderr, "Cannot find metric or group `%s'\n",
>                                         p);
> @@ -996,11 +996,11 @@ static void metric__free_refs(struct metric *metric)
>         }
>  }
>
> -static void metricgroup__free_metrics(struct list_head *group_list)
> +static void metricgroup__free_metrics(struct list_head *metric_list)
>  {
>         struct metric *m, *tmp;
>
> -       list_for_each_entry_safe (m, tmp, group_list, nd) {
> +       list_for_each_entry_safe (m, tmp, metric_list, nd) {
>                 metric__free_refs(m);
>                 expr__ctx_clear(&m->pctx);
>                 list_del_init(&m->nd);
> @@ -1017,13 +1017,13 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>  {
>         struct parse_events_error parse_error;
>         struct strbuf extra_events;
> -       LIST_HEAD(group_list);
> +       LIST_HEAD(metric_list);
>         int ret;
>
>         if (metric_events->nr_entries == 0)
>                 metricgroup__rblist_init(metric_events);
>         ret = metricgroup__add_metric_list(str, metric_no_group,
> -                                          &extra_events, &group_list, map);
> +                                          &extra_events, &metric_list, map);
>         if (ret)
>                 return ret;
>         pr_debug("adding %s\n", extra_events.buf);
> @@ -1034,10 +1034,10 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>                 goto out;
>         }
>         strbuf_release(&extra_events);
> -       ret = metricgroup__setup_events(&group_list, metric_no_merge,
> +       ret = metricgroup__setup_events(&metric_list, metric_no_merge,
>                                         perf_evlist, metric_events);
>  out:
> -       metricgroup__free_metrics(&group_list);
> +       metricgroup__free_metrics(&metric_list);
>         return ret;
>  }
>
> --
> 2.25.4
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (18 preceding siblings ...)
  2020-07-19 18:13 ` [PATCH 19/19] perf metric: Rename group_list to metric_list Jiri Olsa
@ 2020-07-20  6:44 ` kajoljain
  2020-07-20  7:22   ` Jiri Olsa
  2020-07-21 14:48 ` Paul A. Clarke
  20 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-20  6:44 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian, Ian Rogers



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> hi,
> this patchset is adding the support to reused metric in
> another metric.
> 
> For example, to define IPC by using CPI with change like:
> 
>      {
>          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> +        "MetricExpr": "1/CPI",
>          "MetricGroup": "TopDownL1",
>          "MetricName": "IPC"
>      },
> 
> I won't be able to find all the possible places we could
> use this at, so I wonder you guys (who was asking for this)
> would try it and come up with comments if there's something
> missing or we could already use it at some places.
> 
> It's based on Arnaldo's tmp.perf/core.
> 
> v3 changes:
>   - added some acks
>   - some patches got merged
>   - added missing zalloc include [John Garry]
>   - added ids array outside the egroup object [Ian]
>   - removed wrong m->has_constraint assignment [Ian]
>   - renamed 'list' to 'metric_list' [Ian]
>   - fixed group metric and added test for it [Paul A. Clarke]
>   - fixed memory leak [Arnaldo]
>   - using lowercase keys for metrics in hashmap, because jevents
>     converts metric_expr to lowercase
> 
> Also available in here:
>   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
>   perf/metric
> 

Hi Jiri,
   I am trying to review these patches and also test it in power box. I am testing your `perf/metric` branch.
With your current patches,some of hv-24x7 events not giving appropriate result
while doing "--metric-only" command. I can't see corresponding output for all chips.

This is output on power9 machine:

Without your patches on upstream kernel:

command# ./perf stat --metric-only -M PowerBUS_Frequency -I 1000 -C 0
#           time GHz  PowerBUS_Frequency_0 GHz  PowerBUS_Frequency_1 
     1.000073877                        2.0                        2.0 
     2.000240551                        2.0                        1.9 
^C     2.452590532                        0.9                        0.9 

 Performance counter stats for 'CPU(s) 0':

                       4.8                        4.8 

       2.452654834 seconds time elapsed

With your patches on perf/metric branch:

command# ./perf stat --metric-only -M PowerBUS_Frequency -I 1000 -C 0
assertion failed at util/metricgroup.c:709
#           time GHz  PowerBUS_Frequency_0 
     1.000073875                        2.0 
     2.000380706                        2.0 
^C     2.658962182                        1.3 

 Performance counter stats for 'CPU(s) 0':

                       5.2 

Please let me know, if I am missing something. 

Thanks,
Kajol Jain

> thanks,
> jirka
> 
> 
> ---
> Jiri Olsa (19):
>       perf metric: Fix memory leak in expr__add_id function
>       perf metric: Add expr__add_id function
>       perf metric: Change expr__get_id to return struct expr_id_data
>       perf metric: Add expr__del_id function
>       perf metric: Add macros for iterating map events
>       perf metric: Add add_metric function
>       perf metric: Rename __metricgroup__add_metric to __add_metric
>       perf metric: Collect referenced metrics in struct metric_ref_node
>       perf metric: Collect referenced metrics in struct metric_expr
>       perf metric: Add referenced metrics to hash data
>       perf metric: Compute referenced metrics
>       perf metric: Add events for the current list
>       perf metric: Add cache_miss_cycles to metric parse test
>       perf metric: Add DCache_L2 to metric parse test
>       perf metric: Add recursion check when processing nested metrics
>       perf metric: Make compute_single function more precise
>       perf metric: Add metric group test
>       perf metric: Rename struct egroup to metric
>       perf metric: Rename group_list to metric_list
> 
>  tools/perf/tests/parse-metric.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++----
>  tools/perf/util/expr.c          | 143 ++++++++++++++++++++++++++++++++-----
>  tools/perf/util/expr.h          |  30 +++++++-
>  tools/perf/util/expr.y          |  16 +++--
>  tools/perf/util/metricgroup.c   | 466 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
>  tools/perf/util/metricgroup.h   |   6 ++
>  tools/perf/util/stat-shadow.c   |  20 ++++--
>  7 files changed, 751 insertions(+), 136 deletions(-)
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20  6:44 ` [PATCHv3 00/19] perf metric: Add support to reuse metric kajoljain
@ 2020-07-20  7:22   ` Jiri Olsa
  2020-07-20  8:09     ` kajoljain
  0 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-20  7:22 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers

On Mon, Jul 20, 2020 at 12:14:00PM +0530, kajoljain wrote:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > hi,
> > this patchset is adding the support to reused metric in
> > another metric.
> > 
> > For example, to define IPC by using CPI with change like:
> > 
> >      {
> >          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> > -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> > +        "MetricExpr": "1/CPI",
> >          "MetricGroup": "TopDownL1",
> >          "MetricName": "IPC"
> >      },
> > 
> > I won't be able to find all the possible places we could
> > use this at, so I wonder you guys (who was asking for this)
> > would try it and come up with comments if there's something
> > missing or we could already use it at some places.
> > 
> > It's based on Arnaldo's tmp.perf/core.
> > 
> > v3 changes:
> >   - added some acks
> >   - some patches got merged
> >   - added missing zalloc include [John Garry]
> >   - added ids array outside the egroup object [Ian]
> >   - removed wrong m->has_constraint assignment [Ian]
> >   - renamed 'list' to 'metric_list' [Ian]
> >   - fixed group metric and added test for it [Paul A. Clarke]
> >   - fixed memory leak [Arnaldo]
> >   - using lowercase keys for metrics in hashmap, because jevents
> >     converts metric_expr to lowercase
> > 
> > Also available in here:
> >   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> >   perf/metric
> > 
> 
> Hi Jiri,
>    I am trying to review these patches and also test it in power box. I am testing your `perf/metric` branch.
> With your current patches,some of hv-24x7 events not giving appropriate result
> while doing "--metric-only" command. I can't see corresponding output for all chips.

hi,
is that just for --metric-only option?

> 
> This is output on power9 machine:
> 
> Without your patches on upstream kernel:
> 
> command# ./perf stat --metric-only -M PowerBUS_Frequency -I 1000 -C 0
> #           time GHz  PowerBUS_Frequency_0 GHz  PowerBUS_Frequency_1 
>      1.000073877                        2.0                        2.0 
>      2.000240551                        2.0                        1.9 
> ^C     2.452590532                        0.9                        0.9 
> 
>  Performance counter stats for 'CPU(s) 0':
> 
>                        4.8                        4.8 
> 
>        2.452654834 seconds time elapsed
> 
> With your patches on perf/metric branch:
> 
> command# ./perf stat --metric-only -M PowerBUS_Frequency -I 1000 -C 0
> assertion failed at util/metricgroup.c:709
> #           time GHz  PowerBUS_Frequency_0 
>      1.000073875                        2.0 
>      2.000380706                        2.0 
> ^C     2.658962182                        1.3 
> 
>  Performance counter stats for 'CPU(s) 0':
> 
>                        5.2 
> 
> Please let me know, if I am missing something. 

hum, I'll need to add test for metric with hv-24x7 events

thanks,
jirka


^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20  7:22   ` Jiri Olsa
@ 2020-07-20  8:09     ` kajoljain
  2020-07-20  8:19       ` Jiri Olsa
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-20  8:09 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers



On 7/20/20 12:52 PM, Jiri Olsa wrote:
> On Mon, Jul 20, 2020 at 12:14:00PM +0530, kajoljain wrote:
>>
>>
>> On 7/19/20 11:43 PM, Jiri Olsa wrote:
>>> hi,
>>> this patchset is adding the support to reused metric in
>>> another metric.
>>>
>>> For example, to define IPC by using CPI with change like:
>>>
>>>      {
>>>          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
>>> -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
>>> +        "MetricExpr": "1/CPI",
>>>          "MetricGroup": "TopDownL1",
>>>          "MetricName": "IPC"
>>>      },
>>>
>>> I won't be able to find all the possible places we could
>>> use this at, so I wonder you guys (who was asking for this)
>>> would try it and come up with comments if there's something
>>> missing or we could already use it at some places.
>>>
>>> It's based on Arnaldo's tmp.perf/core.
>>>
>>> v3 changes:
>>>   - added some acks
>>>   - some patches got merged
>>>   - added missing zalloc include [John Garry]
>>>   - added ids array outside the egroup object [Ian]
>>>   - removed wrong m->has_constraint assignment [Ian]
>>>   - renamed 'list' to 'metric_list' [Ian]
>>>   - fixed group metric and added test for it [Paul A. Clarke]
>>>   - fixed memory leak [Arnaldo]
>>>   - using lowercase keys for metrics in hashmap, because jevents
>>>     converts metric_expr to lowercase
>>>
>>> Also available in here:
>>>   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
>>>   perf/metric
>>>
>>
>> Hi Jiri,
>>    I am trying to review these patches and also test it in power box. I am testing your `perf/metric` branch.
>> With your current patches,some of hv-24x7 events not giving appropriate result
>> while doing "--metric-only" command. I can't see corresponding output for all chips.
> 
> hi,
> is that just for --metric-only option?

Hi Jiri,
   So basically, this issue is for both with/without metric-only option. Without metric-only option,
I am not able to see aggregate result for other chips.

This is with upstream kernel:

command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
#           time             counts unit events
     1.000076370          7,807,494      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
     1.000076370          7,807,456      hv_24x7/pm_pb_cyc,chip=1/ #      2.0 GHz  PowerBUS_Frequency_1
     2.000259226          7,807,490      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
     2.000259226          7,799,691      hv_24x7/pm_pb_cyc,chip=1/ #      1.9 GHz  PowerBUS_Frequency_1
^C     2.745238246          5,816,562      hv_24x7/pm_pb_cyc,chip=0/ #      1.5 GHz  PowerBUS_Frequency_0
     2.745238246          5,816,580      hv_24x7/pm_pb_cyc,chip=1/ #      1.5 GHz  PowerBUS_Frequency_1

 Performance counter stats for 'CPU(s) 0':

        21,431,546      hv_24x7/pm_pb_cyc,chip=0/ #      5.4 GHz  PowerBUS_Frequency_0
        21,423,727      hv_24x7/pm_pb_cyc,chip=1/ #      5.4 GHz  PowerBUS_Frequency_1

This is with your perf/metric branch:
command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
assertion failed at util/metricgroup.c:709
#           time             counts unit events
     1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
     1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
     2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
     2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
     3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
     3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
     3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   

 Performance counter stats for 'CPU(s) 0':

        25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
        25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   

       3.259505529 seconds time elapsed
Thanks,
Kajol Jain
> 
>>
>> This is output on power9 machine:
>>
>> Without your patches on upstream kernel:
>>
>> command# ./perf stat --metric-only -M PowerBUS_Frequency -I 1000 -C 0
>> #           time GHz  PowerBUS_Frequency_0 GHz  PowerBUS_Frequency_1 
>>      1.000073877                        2.0                        2.0 
>>      2.000240551                        2.0                        1.9 
>> ^C     2.452590532                        0.9                        0.9 
>>
>>  Performance counter stats for 'CPU(s) 0':
>>
>>                        4.8                        4.8 
>>
>>        2.452654834 seconds time elapsed
>>
>> With your patches on perf/metric branch:
>>
>> command# ./perf stat --metric-only -M PowerBUS_Frequency -I 1000 -C 0
>> assertion failed at util/metricgroup.c:709
>> #           time GHz  PowerBUS_Frequency_0 
>>      1.000073875                        2.0 
>>      2.000380706                        2.0 
>> ^C     2.658962182                        1.3 
>>
>>  Performance counter stats for 'CPU(s) 0':
>>
>>                        5.2 
>>
>> Please let me know, if I am missing something. 
> 
> hum, I'll need to add test for metric with hv-24x7 events
> 
> thanks,
> jirka
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20  8:09     ` kajoljain
@ 2020-07-20  8:19       ` Jiri Olsa
  2020-07-20  9:02         ` kajoljain
  0 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-20  8:19 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers

On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:

SNIP

> This is with your perf/metric branch:
> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
> assertion failed at util/metricgroup.c:709
> #           time             counts unit events
>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
> 
>  Performance counter stats for 'CPU(s) 0':
> 
>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
> 
>        3.259505529 seconds time elapsed

I found the bug, we are not adding runtime metrics as standalone ones,
but as referenced metrics.. will fix and try to add test for that

as for testing.. do I need some special ppc server to have support for this? 

thanks,
jirka


^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20  8:19       ` Jiri Olsa
@ 2020-07-20  9:02         ` kajoljain
  2020-07-20 19:16           ` Jiri Olsa
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-20  9:02 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers



On 7/20/20 1:49 PM, Jiri Olsa wrote:
> On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:
> 
> SNIP
> 
>> This is with your perf/metric branch:
>> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
>> assertion failed at util/metricgroup.c:709
>> #           time             counts unit events
>>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
>>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
>>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
>>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
>>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
>>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
>> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
>>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
>>
>>  Performance counter stats for 'CPU(s) 0':
>>
>>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
>>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
>>
>>        3.259505529 seconds time elapsed
> 
> I found the bug, we are not adding runtime metrics as standalone ones,
> but as referenced metrics.. will fix and try to add test for that
> 
> as for testing.. do I need some special ppc server to have support for this? 

Hi jiri,
    We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
enabled.

Thanks,
Kajol Jain
> 
> thanks,
> jirka
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20  9:02         ` kajoljain
@ 2020-07-20 19:16           ` Jiri Olsa
  2020-07-24  5:52             ` kajoljain
  2020-07-28 12:39             ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-20 19:16 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers

On Mon, Jul 20, 2020 at 02:32:40PM +0530, kajoljain wrote:
> 
> 
> On 7/20/20 1:49 PM, Jiri Olsa wrote:
> > On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:
> > 
> > SNIP
> > 
> >> This is with your perf/metric branch:
> >> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
> >> assertion failed at util/metricgroup.c:709
> >> #           time             counts unit events
> >>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> >>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
> >>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> >>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
> >>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
> >>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
> >> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
> >>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
> >>
> >>  Performance counter stats for 'CPU(s) 0':
> >>
> >>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
> >>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
> >>
> >>        3.259505529 seconds time elapsed
> > 
> > I found the bug, we are not adding runtime metrics as standalone ones,
> > but as referenced metrics.. will fix and try to add test for that
> > 
> > as for testing.. do I need some special ppc server to have support for this? 
> 
> Hi jiri,
>     We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
> enabled.

could you please try with following patch on top?

thanks,
jirka


---
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 6f179b9903a0..03aa4bd4a38b 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -820,11 +820,11 @@ static int add_metric(struct list_head *metric_list,
 		      struct expr_id *parent,
 		      struct expr_ids *ids);
 
-static int resolve_metric(struct metric *m,
-			  bool metric_no_group,
-			  struct list_head *metric_list,
-			  struct pmu_events_map *map,
-			  struct expr_ids *ids)
+static int __resolve_metric(struct metric *m,
+			    bool metric_no_group,
+			    struct list_head *metric_list,
+			    struct pmu_events_map *map,
+			    struct expr_ids *ids)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -869,6 +869,23 @@ static int resolve_metric(struct metric *m,
 	return 0;
 }
 
+static int resolve_metric(bool metric_no_group,
+			  struct list_head *metric_list,
+			  struct pmu_events_map *map,
+			  struct expr_ids *ids)
+{
+	struct metric *m;
+	int err;
+
+	list_for_each_entry(m, metric_list, nd) {
+		err = __resolve_metric(m, metric_no_group, metric_list, map, ids);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int add_metric(struct list_head *metric_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
@@ -876,6 +893,7 @@ static int add_metric(struct list_head *metric_list,
 		      struct expr_id *parent,
 		      struct expr_ids *ids)
 {
+	struct metric *orig = *m;
 	int ret = 0;
 
 	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
@@ -892,7 +910,7 @@ static int add_metric(struct list_head *metric_list,
 		 * those events to metric_list.
 		 */
 
-		for (j = 0; j < count && !ret; j++) {
+		for (j = 0; j < count && !ret; j++, *m = orig) {
 			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
 		}
 	}
@@ -907,8 +925,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 
 {
 	struct expr_ids ids = { 0 };
+	struct metric *m = NULL;
 	struct pmu_event *pe;
-	struct metric *m;
 	LIST_HEAD(list);
 	int i, ret;
 	bool has_match = false;
@@ -925,7 +943,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		 * Process any possible referenced metrics
 		 * included in the expression.
 		 */
-		ret = resolve_metric(m, metric_no_group,
+		ret = resolve_metric(metric_no_group,
 				     &list, map, &ids);
 		if (ret)
 			return ret;


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re:  [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
                   ` (19 preceding siblings ...)
  2020-07-20  6:44 ` [PATCHv3 00/19] perf metric: Add support to reuse metric kajoljain
@ 2020-07-21 14:48 ` Paul A. Clarke
  2020-07-22 18:11   ` Jiri Olsa
  20 siblings, 1 reply; 88+ messages in thread
From: Paul A. Clarke @ 2020-07-21 14:48 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Stephane Eranian, Ian Rogers

On Sun, Jul 19, 2020 at 08:13:01PM +0200, Jiri Olsa wrote:
> hi,
> this patchset is adding the support to reused metric in
> another metric.
> 
> For example, to define IPC by using CPI with change like:
> 
>      {
>          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> +        "MetricExpr": "1/CPI",
>          "MetricGroup": "TopDownL1",
>          "MetricName": "IPC"
>      },
> 
> I won't be able to find all the possible places we could
> use this at, so I wonder you guys (who was asking for this)
> would try it and come up with comments if there's something
> missing or we could already use it at some places.
> 
> It's based on Arnaldo's tmp.perf/core.
> 
> v3 changes:
>   - added some acks
>   - some patches got merged
>   - added missing zalloc include [John Garry]
>   - added ids array outside the egroup object [Ian]
>   - removed wrong m->has_constraint assignment [Ian]
>   - renamed 'list' to 'metric_list' [Ian]
>   - fixed group metric and added test for it [Paul A. Clarke]
>   - fixed memory leak [Arnaldo]
>   - using lowercase keys for metrics in hashmap, because jevents
>     converts metric_expr to lowercase
> 
> Also available in here:
>   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
>   perf/metric

These changes seem to be mostly working for me.

I attempted to exploit the new capability in the metrics definitions in
tools/perf/pmu-events/arch/powerpc/power9/metrics.json.  Those changes
are included below.

The one problem I found is with the "cpi_breakdown" metric group, as it
no longer works:
```
# perf stat --metrics cpi_breakdown ./command
Cannot find metric or group `cpi_breakdown'
```

"cpi_breakdown" does show up in `perf list --metricgroup`, and all of the
(95!) metrics listed in that group are usable, so it's not obvious whether
my changes have a problem, or merely provoke one.

diff --git a/tools/perf/pmu-events/arch/powerpc/power9/metrics.json b/tools/perf/pmu-events/arch/powerpc/power9/metrics.json
index 80816d6402e9..f8784c608479 100644
--- a/tools/perf/pmu-events/arch/powerpc/power9/metrics.json
+++ b/tools/perf/pmu-events/arch/powerpc/power9/metrics.json
@@ -60,7 +60,7 @@
     },
     {
         "BriefDescription": "Stalls due to short latency decimal floating ops.",
-        "MetricExpr": "(PM_CMPLU_STALL_DFU - PM_CMPLU_STALL_DFLONG)/PM_RUN_INST_CMPL",
+        "MetricExpr": "dfu_stall_cpi - dflong_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "dfu_other_stall_cpi"
     },
@@ -72,7 +72,7 @@
     },
     {
         "BriefDescription": "Completion stall by Dcache miss which resolved off node memory/cache",
-        "MetricExpr": "(PM_CMPLU_STALL_DMISS_L3MISS - PM_CMPLU_STALL_DMISS_L21_L31 - PM_CMPLU_STALL_DMISS_LMEM - PM_CMPLU_STALL_DMISS_REMOTE)/PM_RUN_INST_CMPL",
+        "MetricExpr": "dmiss_non_local_stall_cpi - dmiss_remote_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "dmiss_distant_stall_cpi"
     },
@@ -90,7 +90,7 @@
     },
     {
         "BriefDescription": "Completion stall due to cache miss that resolves in the L2 or L3 without conflict",
-        "MetricExpr": "(PM_CMPLU_STALL_DMISS_L2L3 - PM_CMPLU_STALL_DMISS_L2L3_CONFLICT)/PM_RUN_INST_CMPL",
+        "MetricExpr": "dmiss_l2l3_stall_cpi - dmiss_l2l3_conflict_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "dmiss_l2l3_noconflict_stall_cpi"
     },
@@ -114,7 +114,7 @@
     },
     {
         "BriefDescription": "Completion stall by Dcache miss which resolved outside of local memory",
-        "MetricExpr": "(PM_CMPLU_STALL_DMISS_L3MISS - PM_CMPLU_STALL_DMISS_L21_L31 - PM_CMPLU_STALL_DMISS_LMEM)/PM_RUN_INST_CMPL",
+        "MetricExpr": "dmiss_l3miss_stall_cpi - dmiss_l21_l31_stall_cpi - dmiss_lmem_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "dmiss_non_local_stall_cpi"
     },
@@ -126,7 +126,7 @@
     },
     {
         "BriefDescription": "Stalls due to short latency double precision ops.",
-        "MetricExpr": "(PM_CMPLU_STALL_DP - PM_CMPLU_STALL_DPLONG)/PM_RUN_INST_CMPL",
+        "MetricExpr": "dp_stall_cpi - dplong_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "dp_other_stall_cpi"
     },
@@ -155,7 +155,7 @@
         "MetricName": "emq_full_stall_cpi"
     },
     {
-        "MetricExpr": "(PM_CMPLU_STALL_ERAT_MISS + PM_CMPLU_STALL_EMQ_FULL)/PM_RUN_INST_CMPL",
+        "MetricExpr": "erat_miss_stall_cpi + emq_full_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "emq_stall_cpi"
     },
@@ -173,7 +173,7 @@
     },
     {
         "BriefDescription": "Completion stall due to execution units for other reasons.",
-        "MetricExpr": "(PM_CMPLU_STALL_EXEC_UNIT - PM_CMPLU_STALL_FXU - PM_CMPLU_STALL_DP - PM_CMPLU_STALL_DFU - PM_CMPLU_STALL_PM - PM_CMPLU_STALL_CRYPTO - PM_CMPLU_STALL_VFXU - PM_CMPLU_STALL_VDP)/PM_RUN_INST_CMPL",
+        "MetricExpr": "exec_unit_stall_cpi - scalar_stall_cpi - vector_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "exec_unit_other_stall_cpi"
     },
@@ -197,7 +197,7 @@
     },
     {
         "BriefDescription": "Stalls due to short latency integer ops",
-        "MetricExpr": "(PM_CMPLU_STALL_FXU - PM_CMPLU_STALL_FXLONG)/PM_RUN_INST_CMPL",
+        "MetricExpr": "fxu_stall_cpi - fxlong_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "fxu_other_stall_cpi"
     },
@@ -221,7 +221,7 @@
     },
     {
         "BriefDescription": "Instruction Completion Table other stalls",
-        "MetricExpr": "(PM_ICT_NOSLOT_CYC - PM_ICT_NOSLOT_IC_MISS - PM_ICT_NOSLOT_BR_MPRED_ICMISS - PM_ICT_NOSLOT_BR_MPRED - PM_ICT_NOSLOT_DISP_HELD)/PM_RUN_INST_CMPL",
+        "MetricExpr": "nothing_dispatched_cpi - ict_noslot_ic_miss_cpi - ict_noslot_br_mpred_icmiss_cpi - ict_noslot_br_mpred_cpi - ict_noslot_disp_held_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "ict_noslot_cyc_other_cpi"
     },
@@ -245,7 +245,7 @@
     },
     {
         "BriefDescription": "ICT_NOSLOT_DISP_HELD_OTHER_CPI",
-        "MetricExpr": "(PM_ICT_NOSLOT_DISP_HELD - PM_ICT_NOSLOT_DISP_HELD_HB_FULL - PM_ICT_NOSLOT_DISP_HELD_SYNC - PM_ICT_NOSLOT_DISP_HELD_TBEGIN - PM_ICT_NOSLOT_DISP_HELD_ISSQ)/PM_RUN_INST_CMPL",
+        "MetricExpr": "ict_noslot_disp_held_cpi - ict_noslot_disp_held_hb_full_cpi - ict_noslot_disp_held_sync_cpi - ict_noslot_disp_held_tbegin_cpi - ict_noslot_disp_held_issq_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "ict_noslot_disp_held_other_cpi"
     },
@@ -263,7 +263,7 @@
     },
     {
         "BriefDescription": "ICT_NOSLOT_IC_L2_CPI",
-        "MetricExpr": "(PM_ICT_NOSLOT_IC_MISS - PM_ICT_NOSLOT_IC_L3 - PM_ICT_NOSLOT_IC_L3MISS)/PM_RUN_INST_CMPL",
+        "MetricExpr": "ict_noslot_ic_miss_cpi - ict_noslot_ic_l3_cpi - ict_noslot_ic_l3miss_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "ict_noslot_ic_l2_cpi"
     },
@@ -286,7 +286,7 @@
         "MetricName": "ict_noslot_ic_miss_cpi"
     },
     {
-        "MetricExpr": "(PM_NTC_ISSUE_HELD_DARQ_FULL + PM_NTC_ISSUE_HELD_ARB + PM_NTC_ISSUE_HELD_OTHER)/PM_RUN_INST_CMPL",
+        "MetricExpr": "ntc_issue_held_darq_full_cpi + ntc_issue_held_arb_cpi + ntc_issue_held_other_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "issue_hold_cpi"
     },
@@ -327,7 +327,7 @@
         "MetricName": "lrq_other_stall_cpi"
     },
     {
-        "MetricExpr": "(PM_CMPLU_STALL_LMQ_FULL + PM_CMPLU_STALL_ST_FWD + PM_CMPLU_STALL_LHS + PM_CMPLU_STALL_LSU_MFSPR + PM_CMPLU_STALL_LARX + PM_CMPLU_STALL_LRQ_OTHER)/PM_RUN_INST_CMPL",
+        "MetricExpr": "lmq_full_stall_cpi + st_fwd_stall_cpi + lhs_stall_cpi + lsu_mfspr_stall_cpi + larx_stall_cpi + lrq_other_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "lrq_stall_cpi"
     },
@@ -338,7 +338,7 @@
         "MetricName": "lsaq_arb_stall_cpi"
     },
     {
-        "MetricExpr": "(PM_CMPLU_STALL_LRQ_FULL + PM_CMPLU_STALL_SRQ_FULL + PM_CMPLU_STALL_LSAQ_ARB)/PM_RUN_INST_CMPL",
+        "MetricExpr": "lrq_full_stall_cpi + srq_full_stall_cpi + lsaq_arb_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "lsaq_stall_cpi"
     },
@@ -362,7 +362,7 @@
     },
     {
         "BriefDescription": "Completion LSU stall for other reasons",
-        "MetricExpr": "(PM_CMPLU_STALL_LSU - PM_CMPLU_STALL_LSU_FIN - PM_CMPLU_STALL_STORE_FINISH - PM_CMPLU_STALL_STORE_DATA - PM_CMPLU_STALL_EIEIO - PM_CMPLU_STALL_STCX - PM_CMPLU_STALL_SLB - PM_CMPLU_STALL_TEND - PM_CMPLU_STALL_PASTE - PM_CMPLU_STALL_TLBIE - PM_CMPLU_STALL_STORE_PIPE_ARB - PM_CMPLU_STALL_STORE_FIN_ARB - PM_CMPLU_STALL_LOAD_FINISH + PM_CMPLU_STALL_DCACHE_MISS - PM_CMPLU_STALL_LMQ_FULL - PM_CMPLU_STALL_ST_FWD - PM_CMPLU_STALL_LHS - PM_CMPLU_STALL_LSU_MFSPR - PM_CMPLU_STALL_LARX - PM_CMPLU_STALL_LRQ_OTHER + PM_CMPLU_STALL_ERAT_MISS + PM_CMPLU_STALL_EMQ_FULL - PM_CMPLU_STALL_LRQ_FULL - PM_CMPLU_STALL_SRQ_FULL - PM_CMPLU_STALL_LSAQ_ARB) / PM_RUN_INST_CMPL",
+        "MetricExpr": "lsu_stall_cpi - lsu_fin_stall_cpi - store_finish_stall_cpi - srq_stall_cpi - load_finish_stall_cpi + lsu_stall_dcache_miss_cpi - lrq_stall_cpi + emq_stall_cpi - lsaq_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "lsu_other_stall_cpi"
     },
@@ -434,13 +434,13 @@
     },
     {
         "BriefDescription": "Cycles unaccounted for.",
-        "MetricExpr": "(PM_RUN_CYC - PM_1PLUS_PPC_CMPL - PM_CMPLU_STALL_THRD - PM_CMPLU_STALL - PM_ICT_NOSLOT_CYC)/PM_RUN_INST_CMPL",
+        "MetricExpr": "run_cpi - completion_cpi - thread_block_stall_cpi - stall_cpi - nothing_dispatched_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "other_cpi"
     },
     {
         "BriefDescription": "Completion stall for other reasons",
-        "MetricExpr": "(PM_CMPLU_STALL - PM_CMPLU_STALL_NTC_DISP_FIN - PM_CMPLU_STALL_NTC_FLUSH - PM_CMPLU_STALL_LSU - PM_CMPLU_STALL_EXEC_UNIT - PM_CMPLU_STALL_BRU)/PM_RUN_INST_CMPL",
+        "MetricExpr": "stall_cpi - ntc_disp_fin_stall_cpi - ntc_flush_stall_cpi - lsu_stall_cpi - exec_unit_stall_cpi - bru_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "other_stall_cpi"
     },
@@ -469,7 +469,7 @@
         "MetricName": "run_cyc_cpi"
     },
     {
-        "MetricExpr": "(PM_CMPLU_STALL_FXU + PM_CMPLU_STALL_DP + PM_CMPLU_STALL_DFU + PM_CMPLU_STALL_PM + PM_CMPLU_STALL_CRYPTO)/PM_RUN_INST_CMPL",
+        "MetricExpr": "fxu_stall_cpi + dp_stall_cpi + dfu_stall_cpi + pm_stall_cpi + crypto_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "scalar_stall_cpi"
     },
@@ -492,7 +492,7 @@
         "MetricName": "srq_full_stall_cpi"
     },
     {
-        "MetricExpr": "(PM_CMPLU_STALL_STORE_DATA + PM_CMPLU_STALL_EIEIO + PM_CMPLU_STALL_STCX + PM_CMPLU_STALL_SLB + PM_CMPLU_STALL_TEND + PM_CMPLU_STALL_PASTE + PM_CMPLU_STALL_TLBIE + PM_CMPLU_STALL_STORE_PIPE_ARB + PM_CMPLU_STALL_STORE_FIN_ARB)/PM_RUN_INST_CMPL",
+        "MetricExpr": "store_data_stall_cpi + eieio_stall_cpi + stcx_stall_cpi + slb_stall_cpi + tend_stall_cpi + paste_stall_cpi + tlbie_stall_cpi + store_pipe_arb_stall_cpi + store_fin_arb_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "srq_stall_cpi"
     },
@@ -558,7 +558,7 @@
     },
     {
         "BriefDescription": "Vector stalls due to small latency double precision ops",
-        "MetricExpr": "(PM_CMPLU_STALL_VDP - PM_CMPLU_STALL_VDPLONG)/PM_RUN_INST_CMPL",
+        "MetricExpr": "vdp_stall_cpi - vdplong_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "vdp_other_stall_cpi"
     },
@@ -575,7 +575,7 @@
         "MetricName": "vdplong_stall_cpi"
     },
     {
-        "MetricExpr": "(PM_CMPLU_STALL_VFXU + PM_CMPLU_STALL_VDP)/PM_RUN_INST_CMPL",
+        "MetricExpr": "vfxu_stall_cpi + vdp_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "vector_stall_cpi"
     },
@@ -587,7 +587,7 @@
     },
     {
         "BriefDescription": "Vector stalls due to small latency integer ops",
-        "MetricExpr": "(PM_CMPLU_STALL_VFXU - PM_CMPLU_STALL_VFXLONG)/PM_RUN_INST_CMPL",
+        "MetricExpr": "vfxu_stall_cpi - vfxlong_stall_cpi",
         "MetricGroup": "cpi_breakdown",
         "MetricName": "vfxu_other_stall_cpi"
     },
@@ -1844,7 +1844,7 @@
     },
     {
         "BriefDescription": "% of DL1 reloads from Private L3, other core per Inst",
-        "MetricExpr": "(PM_DATA_FROM_L31_MOD + PM_DATA_FROM_L31_SHR) * 100 / PM_RUN_INST_CMPL",
+        "MetricExpr": "dl1_reload_from_l31_mod_rate_percent + dl1_reload_from_l31_shr_rate_percent",
         "MetricName": "dl1_reload_from_l31_rate_percent"
     },
     {
@@ -1979,7 +1979,7 @@
     },
     {
         "BriefDescription": "Completion stall because a different thread was using the completion pipe",
-        "MetricExpr": "(PM_CMPLU_STALL_THRD - PM_CMPLU_STALL_EXCEPTION - PM_CMPLU_STALL_ANY_SYNC - PM_CMPLU_STALL_SYNC_PMU_INT - PM_CMPLU_STALL_SPEC_FINISH - PM_CMPLU_STALL_FLUSH_ANY_THREAD - PM_CMPLU_STALL_LSU_FLUSH_NEXT - PM_CMPLU_STALL_NESTED_TBEGIN - PM_CMPLU_STALL_NESTED_TEND - PM_CMPLU_STALL_MTFPSCR)/PM_RUN_INST_CMPL",
+        "MetricExpr": "thread_block_stall_cpi - exception_stall_cpi - any_sync_stall_cpi - sync_pmu_int_stall_cpi - spec_finish_stall_cpi - flush_any_thread_stall_cpi - lsu_flush_next_stall_cpi - nested_tbegin_stall_cpi - nested_tend_stall_cpi - mtfpscr_stall_cpi",
         "MetricName": "other_thread_cmpl_stall"
     },
     {

PC

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-21 14:48 ` Paul A. Clarke
@ 2020-07-22 18:11   ` Jiri Olsa
  2020-07-23 15:59     ` Paul A. Clarke
  2020-07-23 17:14     ` Paul A. Clarke
  0 siblings, 2 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-22 18:11 UTC (permalink / raw)
  To: Paul A. Clarke
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, Kajol Jain, John Garry, Stephane Eranian, Ian Rogers

On Tue, Jul 21, 2020 at 09:48:48AM -0500, Paul A. Clarke wrote:
> On Sun, Jul 19, 2020 at 08:13:01PM +0200, Jiri Olsa wrote:
> > hi,
> > this patchset is adding the support to reused metric in
> > another metric.
> > 
> > For example, to define IPC by using CPI with change like:
> > 
> >      {
> >          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> > -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> > +        "MetricExpr": "1/CPI",
> >          "MetricGroup": "TopDownL1",
> >          "MetricName": "IPC"
> >      },
> > 
> > I won't be able to find all the possible places we could
> > use this at, so I wonder you guys (who was asking for this)
> > would try it and come up with comments if there's something
> > missing or we could already use it at some places.
> > 
> > It's based on Arnaldo's tmp.perf/core.
> > 
> > v3 changes:
> >   - added some acks
> >   - some patches got merged
> >   - added missing zalloc include [John Garry]
> >   - added ids array outside the egroup object [Ian]
> >   - removed wrong m->has_constraint assignment [Ian]
> >   - renamed 'list' to 'metric_list' [Ian]
> >   - fixed group metric and added test for it [Paul A. Clarke]
> >   - fixed memory leak [Arnaldo]
> >   - using lowercase keys for metrics in hashmap, because jevents
> >     converts metric_expr to lowercase
> > 
> > Also available in here:
> >   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> >   perf/metric
> 
> These changes seem to be mostly working for me.
> 
> I attempted to exploit the new capability in the metrics definitions in
> tools/perf/pmu-events/arch/powerpc/power9/metrics.json.  Those changes
> are included below.
> 
> The one problem I found is with the "cpi_breakdown" metric group, as it
> no longer works:
> ```
> # perf stat --metrics cpi_breakdown ./command
> Cannot find metric or group `cpi_breakdown'
> ```
> 
> "cpi_breakdown" does show up in `perf list --metricgroup`, and all of the
> (95!) metrics listed in that group are usable, so it's not obvious whether
> my changes have a problem, or merely provoke one.

I underestimated the recursion depth setup for groups,
your change is working for me with following change:

-#define RECURSION_ID_MAX 100
+#define RECURSION_ID_MAX 1000

jirka


^ permalink raw reply	[flat|nested] 88+ messages in thread

* RE: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-22 18:11   ` Jiri Olsa
@ 2020-07-23 15:59     ` Paul A. Clarke
  2020-07-25 11:52       ` Jiri Olsa
  2020-07-28 12:42       ` Arnaldo Carvalho de Melo
  2020-07-23 17:14     ` Paul A. Clarke
  1 sibling, 2 replies; 88+ messages in thread
From: Paul A. Clarke @ 2020-07-23 15:59 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, Kajol Jain, John Garry, Stephane Eranian, Ian Rogers

On Wed, Jul 22, 2020 at 08:11:58PM +0200, Jiri Olsa wrote:
> On Tue, Jul 21, 2020 at 09:48:48AM -0500, Paul A. Clarke wrote:
> > On Sun, Jul 19, 2020 at 08:13:01PM +0200, Jiri Olsa wrote:
> > > hi,
> > > this patchset is adding the support to reused metric in
> > > another metric.
> > > 
> > > For example, to define IPC by using CPI with change like:
> > > 
> > >      {
> > >          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> > > -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> > > +        "MetricExpr": "1/CPI",
> > >          "MetricGroup": "TopDownL1",
> > >          "MetricName": "IPC"
> > >      },
> > > 
> > > I won't be able to find all the possible places we could
> > > use this at, so I wonder you guys (who was asking for this)
> > > would try it and come up with comments if there's something
> > > missing or we could already use it at some places.
> > > 
> > > It's based on Arnaldo's tmp.perf/core.
> > > 
> > > v3 changes:
> > >   - added some acks
> > >   - some patches got merged
> > >   - added missing zalloc include [John Garry]
> > >   - added ids array outside the egroup object [Ian]
> > >   - removed wrong m->has_constraint assignment [Ian]
> > >   - renamed 'list' to 'metric_list' [Ian]
> > >   - fixed group metric and added test for it [Paul A. Clarke]
> > >   - fixed memory leak [Arnaldo]
> > >   - using lowercase keys for metrics in hashmap, because jevents
> > >     converts metric_expr to lowercase
> > > 
> > > Also available in here:
> > >   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> > >   perf/metric
> > 
> > These changes seem to be mostly working for me.
> > 
> > I attempted to exploit the new capability in the metrics definitions in
> > tools/perf/pmu-events/arch/powerpc/power9/metrics.json.  Those changes
> > are included below.
> > 
> > The one problem I found is with the "cpi_breakdown" metric group, as it
> > no longer works:
> > ```
> > # perf stat --metrics cpi_breakdown ./command
> > Cannot find metric or group `cpi_breakdown'
> > ```
> > 
> > "cpi_breakdown" does show up in `perf list --metricgroup`, and all of the
> > (95!) metrics listed in that group are usable, so it's not obvious whether
> > my changes have a problem, or merely provoke one.
> 
> I underestimated the recursion depth setup for groups,
> your change is working for me with following change:
> 
> -#define RECURSION_ID_MAX 100
> +#define RECURSION_ID_MAX 1000

That indeed addressed the issue.

Is there a point where that limit was being hit and the code silently fails?
If so, should that failure be less silent?

PC

^ permalink raw reply	[flat|nested] 88+ messages in thread

* RE: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-22 18:11   ` Jiri Olsa
  2020-07-23 15:59     ` Paul A. Clarke
@ 2020-07-23 17:14     ` Paul A. Clarke
  2020-07-23 17:40       ` Andi Kleen
  1 sibling, 1 reply; 88+ messages in thread
From: Paul A. Clarke @ 2020-07-23 17:14 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, Kajol Jain, John Garry, Stephane Eranian, Ian Rogers

On Wed, Jul 22, 2020 at 08:11:58PM +0200, Jiri Olsa wrote:
> On Tue, Jul 21, 2020 at 09:48:48AM -0500, Paul A. Clarke wrote:
> > On Sun, Jul 19, 2020 at 08:13:01PM +0200, Jiri Olsa wrote:
> > > hi,
> > > this patchset is adding the support to reused metric in
> > > another metric.
> > > 
> > > For example, to define IPC by using CPI with change like:
> > > 
> > >      {
> > >          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> > > -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> > > +        "MetricExpr": "1/CPI",
> > >          "MetricGroup": "TopDownL1",
> > >          "MetricName": "IPC"
> > >      },
> > > 
> > > I won't be able to find all the possible places we could
> > > use this at, so I wonder you guys (who was asking for this)
> > > would try it and come up with comments if there's something
> > > missing or we could already use it at some places.
> > > 
> > > It's based on Arnaldo's tmp.perf/core.
> > > 
> > > v3 changes:
> > >   - added some acks
> > >   - some patches got merged
> > >   - added missing zalloc include [John Garry]
> > >   - added ids array outside the egroup object [Ian]
> > >   - removed wrong m->has_constraint assignment [Ian]
> > >   - renamed 'list' to 'metric_list' [Ian]
> > >   - fixed group metric and added test for it [Paul A. Clarke]
> > >   - fixed memory leak [Arnaldo]
> > >   - using lowercase keys for metrics in hashmap, because jevents
> > >     converts metric_expr to lowercase
> > > 
> > > Also available in here:
> > >   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> > >   perf/metric
> > 
> > These changes seem to be mostly working for me.
> > 
> > I attempted to exploit the new capability in the metrics definitions in
> > tools/perf/pmu-events/arch/powerpc/power9/metrics.json.  Those changes
> > are included below.
> > 
> > The one problem I found is with the "cpi_breakdown" metric group, as it
> > no longer works:
> > ```
> > # perf stat --metrics cpi_breakdown ./command
> > Cannot find metric or group `cpi_breakdown'
> > ```
> > 
> > "cpi_breakdown" does show up in `perf list --metricgroup`, and all of the
> > (95!) metrics listed in that group are usable, so it's not obvious whether
> > my changes have a problem, or merely provoke one.
> 
> I underestimated the recursion depth setup for groups,
> your change is working for me with following change:
> 
> -#define RECURSION_ID_MAX 100
> +#define RECURSION_ID_MAX 1000

I just saw some odd behavior:
```
# perf stat --metrics cpi_breakdown --metrics cpi_breakdown --metric-only ./cmd
WARNING: grouped events cpus do not match, disabling group:
  anon group { raw 0x2d018 }                                                         
  anon group { raw 0x2d018 }   
  anon group { raw 0x2d018 }                                                                                                                                                                                      
  anon group { raw 0x2d018 }                                               
  anon group { raw 0x1006a }                                                                                                                                                                                      
  anon group { raw 0x400fa }                                                                                                                                                                                      
  anon group { raw 0x400fa }                                               
  anon group { raw 0x400fa }                                               
  anon group { raw 0x400fa }                                               
perf: util/evsel.c:1452: get_group_fd: Assertion `!(!leader->core.fd)' failed.                                                             
Aborted (core dumped)
```

It happened both with and without my changes on binaries which were built
yesterday.  Three or four times in a row.

Oddly, it went away without any action on my part. Same commands a minute or so
later. I haven't seen this before.  I can't reproduce it now.  :-/

PC

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-23 17:14     ` Paul A. Clarke
@ 2020-07-23 17:40       ` Andi Kleen
  0 siblings, 0 replies; 88+ messages in thread
From: Andi Kleen @ 2020-07-23 17:40 UTC (permalink / raw)
  To: Paul A. Clarke
  Cc: Jiri Olsa, Jiri Olsa, Arnaldo Carvalho de Melo, lkml,
	Ingo Molnar, Namhyung Kim, Alexander Shishkin, Peter Zijlstra,
	Michael Petlan, Kajol Jain, John Garry, Stephane Eranian,
	Ian Rogers

> perf: util/evsel.c:1452: get_group_fd: Assertion `!(!leader->core.fd)' failed.                                                             
> Aborted (core dumped)
> ```

This usually happens when you run out of file descriptors

-Andi

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20 19:16           ` Jiri Olsa
@ 2020-07-24  5:52             ` kajoljain
  2020-07-25 11:51               ` Jiri Olsa
  2020-07-28 12:39             ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-24  5:52 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers



On 7/21/20 12:46 AM, Jiri Olsa wrote:
> On Mon, Jul 20, 2020 at 02:32:40PM +0530, kajoljain wrote:
>>
>>
>> On 7/20/20 1:49 PM, Jiri Olsa wrote:
>>> On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:
>>>
>>> SNIP
>>>
>>>> This is with your perf/metric branch:
>>>> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
>>>> assertion failed at util/metricgroup.c:709
>>>> #           time             counts unit events
>>>>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
>>>>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
>>>>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
>>>>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
>>>>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
>>>>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
>>>> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
>>>>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
>>>>
>>>>  Performance counter stats for 'CPU(s) 0':
>>>>
>>>>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
>>>>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
>>>>
>>>>        3.259505529 seconds time elapsed
>>>
>>> I found the bug, we are not adding runtime metrics as standalone ones,
>>> but as referenced metrics.. will fix and try to add test for that
>>>
>>> as for testing.. do I need some special ppc server to have support for this? 
>>
>> Hi jiri,
>>     We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
>> enabled.
> 
> could you please try with following patch on top?

Hi Jiri,
       The change looks good to me. I tried with adding this patch on top of your perf/metric branch. It did resolve the issue of not printing
all chips data. And now I can see proper values for hv-24x7 metric events.

I was also trying by adding new metric using the feature added in this patchset with something like this:

diff --git a/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json b/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
index 8383a37647ad..dfe4bd63b587 100644
--- a/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
+++ b/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
@@ -16,6 +16,11 @@
         "MetricName": "PowerBUS_Frequency",
         "ScaleUnit": "2.5e-7GHz"
     },
+    {
+       "MetricExpr": "Memory_WR_BW_Chip + Memory_RD_BW_Chip",
+        "MetricName": "Total_Memory_BW",
+        "ScaleUnit": "1.6e-2MB"
+    },

I guess as we have dependency on '?' symbol, I am not able to see all chips data for Total_Memory_BW.
I am not sure if Its expected behavior?

This is what I am getting:

[root@ltc-zz189-lp4 perf]# ./perf stat --metric-only -M Total_Memory_BW,Memory_WR_BW_Chip,Memory_RD_BW_Chip -I 1000 -C 0
#           time  MB  Total_Memory_BW MB  Memory_RD_BW_Chip_1 MB  Memory_WR_BW_Chip_1 MB  Memory_WR_BW_Chip_0 MB  Memory_RD_BW_Chip_0 
     1.000067388                 36.4                      0.2                     36.3                     65.0                     72.1 
     2.000374276                 36.2                      0.3                     35.9                     65.4                     77.9 
     3.000543202                 36.3                      0.3                     36.0                     68.7                     81.2 
     4.000702855                 36.3                      0.3                     36.0                     70.9                     93.3 
     5.000856837                 36.0                      0.2                     35.8                     67.4                     81.5 
^C     5.367865273                 13.2                      0.1                     13.1                     23.5                     28.3 
 Performance counter stats for 'CPU(s) 0':
               194.4                      1.3                    193.1                    361.0                    434.3 
       5.368039176 seconds time elapsed

We can only get single chip data's sum in Total_Memory_BW. Please let me know if I am missing something.

Thanks,
Kajol Jain
> 
> thanks,
> jirka
> 
> 
> ---
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 6f179b9903a0..03aa4bd4a38b 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -820,11 +820,11 @@ static int add_metric(struct list_head *metric_list,
>  		      struct expr_id *parent,
>  		      struct expr_ids *ids);
>  
> -static int resolve_metric(struct metric *m,
> -			  bool metric_no_group,
> -			  struct list_head *metric_list,
> -			  struct pmu_events_map *map,
> -			  struct expr_ids *ids)
> +static int __resolve_metric(struct metric *m,
> +			    bool metric_no_group,
> +			    struct list_head *metric_list,
> +			    struct pmu_events_map *map,
> +			    struct expr_ids *ids)
>  {
>  	struct hashmap_entry *cur;
>  	size_t bkt;
> @@ -869,6 +869,23 @@ static int resolve_metric(struct metric *m,
>  	return 0;
>  }
>  
> +static int resolve_metric(bool metric_no_group,
> +			  struct list_head *metric_list,
> +			  struct pmu_events_map *map,
> +			  struct expr_ids *ids)
> +{
> +	struct metric *m;
> +	int err;
> +
> +	list_for_each_entry(m, metric_list, nd) {
> +		err = __resolve_metric(m, metric_no_group, metric_list, map, ids);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
>  static int add_metric(struct list_head *metric_list,
>  		      struct pmu_event *pe,
>  		      bool metric_no_group,
> @@ -876,6 +893,7 @@ static int add_metric(struct list_head *metric_list,
>  		      struct expr_id *parent,
>  		      struct expr_ids *ids)
>  {
> +	struct metric *orig = *m;
>  	int ret = 0;
>  
>  	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> @@ -892,7 +910,7 @@ static int add_metric(struct list_head *metric_list,
>  		 * those events to metric_list.
>  		 */
>  
> -		for (j = 0; j < count && !ret; j++) {
> +		for (j = 0; j < count && !ret; j++, *m = orig) {
>  			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
>  		}
>  	}
> @@ -907,8 +925,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  
>  {
>  	struct expr_ids ids = { 0 };
> +	struct metric *m = NULL;
>  	struct pmu_event *pe;
> -	struct metric *m;
>  	LIST_HEAD(list);
>  	int i, ret;
>  	bool has_match = false;
> @@ -925,7 +943,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  		 * Process any possible referenced metrics
>  		 * included in the expression.
>  		 */
> -		ret = resolve_metric(m, metric_no_group,
> +		ret = resolve_metric(metric_no_group,
>  				     &list, map, &ids);
>  		if (ret)
>  			return ret;
> 

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-24  5:52             ` kajoljain
@ 2020-07-25 11:51               ` Jiri Olsa
  2020-07-26  9:14                 ` kajoljain
  0 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-25 11:51 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers

On Fri, Jul 24, 2020 at 11:22:28AM +0530, kajoljain wrote:

SNIP

> 
> Hi Jiri,
>        The change looks good to me. I tried with adding this patch on top of your perf/metric branch. It did resolve the issue of not printing
> all chips data. And now I can see proper values for hv-24x7 metric events.
> 
> I was also trying by adding new metric using the feature added in this patchset with something like this:
> 
> diff --git a/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json b/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
> index 8383a37647ad..dfe4bd63b587 100644
> --- a/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
> +++ b/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
> @@ -16,6 +16,11 @@
>          "MetricName": "PowerBUS_Frequency",
>          "ScaleUnit": "2.5e-7GHz"
>      },
> +    {
> +       "MetricExpr": "Memory_WR_BW_Chip + Memory_RD_BW_Chip",
> +        "MetricName": "Total_Memory_BW",
> +        "ScaleUnit": "1.6e-2MB"
> +    },

hum, we'll need special case this.. because Memory_WR_BW_Chip will
unwind to Memory_WR_BW_Chip_[01] and Total_Memory_BW is not aware of
that.. what's the expected behaviour in here?

have Total_Memory_BW_[01] for each runtime arg?

I think this will need to come on top of this changes,
it's already too big

thanks,
jirka

> 
> I guess as we have dependency on '?' symbol, I am not able to see all chips data for Total_Memory_BW.
> I am not sure if Its expected behavior?
> 
> This is what I am getting:
> 
> [root@ltc-zz189-lp4 perf]# ./perf stat --metric-only -M Total_Memory_BW,Memory_WR_BW_Chip,Memory_RD_BW_Chip -I 1000 -C 0
> #           time  MB  Total_Memory_BW MB  Memory_RD_BW_Chip_1 MB  Memory_WR_BW_Chip_1 MB  Memory_WR_BW_Chip_0 MB  Memory_RD_BW_Chip_0 
>      1.000067388                 36.4                      0.2                     36.3                     65.0                     72.1 
>      2.000374276                 36.2                      0.3                     35.9                     65.4                     77.9 
>      3.000543202                 36.3                      0.3                     36.0                     68.7                     81.2 
>      4.000702855                 36.3                      0.3                     36.0                     70.9                     93.3 
>      5.000856837                 36.0                      0.2                     35.8                     67.4                     81.5 
> ^C     5.367865273                 13.2                      0.1                     13.1                     23.5                     28.3 
>  Performance counter stats for 'CPU(s) 0':
>                194.4                      1.3                    193.1                    361.0                    434.3 
>        5.368039176 seconds time elapsed
> 
> We can only get single chip data's sum in Total_Memory_BW. Please let me know if I am missing something.

SNIP


^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-23 15:59     ` Paul A. Clarke
@ 2020-07-25 11:52       ` Jiri Olsa
  2020-07-28 12:42       ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-25 11:52 UTC (permalink / raw)
  To: Paul A. Clarke
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, Kajol Jain, John Garry, Stephane Eranian, Ian Rogers

On Thu, Jul 23, 2020 at 10:59:58AM -0500, Paul A. Clarke wrote:
> On Wed, Jul 22, 2020 at 08:11:58PM +0200, Jiri Olsa wrote:
> > On Tue, Jul 21, 2020 at 09:48:48AM -0500, Paul A. Clarke wrote:
> > > On Sun, Jul 19, 2020 at 08:13:01PM +0200, Jiri Olsa wrote:
> > > > hi,
> > > > this patchset is adding the support to reused metric in
> > > > another metric.
> > > > 
> > > > For example, to define IPC by using CPI with change like:
> > > > 
> > > >      {
> > > >          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> > > > -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> > > > +        "MetricExpr": "1/CPI",
> > > >          "MetricGroup": "TopDownL1",
> > > >          "MetricName": "IPC"
> > > >      },
> > > > 
> > > > I won't be able to find all the possible places we could
> > > > use this at, so I wonder you guys (who was asking for this)
> > > > would try it and come up with comments if there's something
> > > > missing or we could already use it at some places.
> > > > 
> > > > It's based on Arnaldo's tmp.perf/core.
> > > > 
> > > > v3 changes:
> > > >   - added some acks
> > > >   - some patches got merged
> > > >   - added missing zalloc include [John Garry]
> > > >   - added ids array outside the egroup object [Ian]
> > > >   - removed wrong m->has_constraint assignment [Ian]
> > > >   - renamed 'list' to 'metric_list' [Ian]
> > > >   - fixed group metric and added test for it [Paul A. Clarke]
> > > >   - fixed memory leak [Arnaldo]
> > > >   - using lowercase keys for metrics in hashmap, because jevents
> > > >     converts metric_expr to lowercase
> > > > 
> > > > Also available in here:
> > > >   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> > > >   perf/metric
> > > 
> > > These changes seem to be mostly working for me.
> > > 
> > > I attempted to exploit the new capability in the metrics definitions in
> > > tools/perf/pmu-events/arch/powerpc/power9/metrics.json.  Those changes
> > > are included below.
> > > 
> > > The one problem I found is with the "cpi_breakdown" metric group, as it
> > > no longer works:
> > > ```
> > > # perf stat --metrics cpi_breakdown ./command
> > > Cannot find metric or group `cpi_breakdown'
> > > ```
> > > 
> > > "cpi_breakdown" does show up in `perf list --metricgroup`, and all of the
> > > (95!) metrics listed in that group are usable, so it's not obvious whether
> > > my changes have a problem, or merely provoke one.
> > 
> > I underestimated the recursion depth setup for groups,
> > your change is working for me with following change:
> > 
> > -#define RECURSION_ID_MAX 100
> > +#define RECURSION_ID_MAX 1000
> 
> That indeed addressed the issue.
> 
> Is there a point where that limit was being hit and the code silently fails?

yes

> If so, should that failure be less silent?

I'll make it more verbose

thanks,
jirka


^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-25 11:51               ` Jiri Olsa
@ 2020-07-26  9:14                 ` kajoljain
  0 siblings, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:14 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, John Garry, Paul A. Clarke, Stephane Eranian,
	Ian Rogers



On 7/25/20 5:21 PM, Jiri Olsa wrote:
> On Fri, Jul 24, 2020 at 11:22:28AM +0530, kajoljain wrote:
> 
> SNIP
> 
>>
>> Hi Jiri,
>>        The change looks good to me. I tried with adding this patch on top of your perf/metric branch. It did resolve the issue of not printing
>> all chips data. And now I can see proper values for hv-24x7 metric events.
>>
>> I was also trying by adding new metric using the feature added in this patchset with something like this:
>>
>> diff --git a/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json b/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
>> index 8383a37647ad..dfe4bd63b587 100644
>> --- a/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
>> +++ b/tools/perf/pmu-events/arch/powerpc/power9/nest_metrics.json
>> @@ -16,6 +16,11 @@
>>          "MetricName": "PowerBUS_Frequency",
>>          "ScaleUnit": "2.5e-7GHz"
>>      },
>> +    {
>> +       "MetricExpr": "Memory_WR_BW_Chip + Memory_RD_BW_Chip",
>> +        "MetricName": "Total_Memory_BW",
>> +        "ScaleUnit": "1.6e-2MB"
>> +    },
> 
> hum, we'll need special case this.. because Memory_WR_BW_Chip will
> unwind to Memory_WR_BW_Chip_[01] and Total_Memory_BW is not aware of
> that.. what's the expected behaviour in here?
> 
> have Total_Memory_BW_[01] for each runtime arg?

Hi Jiri,
    Yes right. So we want Total_Memory_BW to show sum results of both chip 0 and 1 seperately, which is missing here.
> 
> I think this will need to come on top of this changes,
> it's already too big
> 

Yes make sense. We can send separate patches on top of this patch set for this use case. 

Other then that the whole patchset looks good to me with the change to rectify Paul A. Clarke concern.

Tested/Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> thanks,
> jirka
> 
>>
>> I guess as we have dependency on '?' symbol, I am not able to see all chips data for Total_Memory_BW.
>> I am not sure if Its expected behavior?
>>
>> This is what I am getting:
>>
>> [root@ltc-zz189-lp4 perf]# ./perf stat --metric-only -M Total_Memory_BW,Memory_WR_BW_Chip,Memory_RD_BW_Chip -I 1000 -C 0
>> #           time  MB  Total_Memory_BW MB  Memory_RD_BW_Chip_1 MB  Memory_WR_BW_Chip_1 MB  Memory_WR_BW_Chip_0 MB  Memory_RD_BW_Chip_0 
>>      1.000067388                 36.4                      0.2                     36.3                     65.0                     72.1 
>>      2.000374276                 36.2                      0.3                     35.9                     65.4                     77.9 
>>      3.000543202                 36.3                      0.3                     36.0                     68.7                     81.2 
>>      4.000702855                 36.3                      0.3                     36.0                     70.9                     93.3 
>>      5.000856837                 36.0                      0.2                     35.8                     67.4                     81.5 
>> ^C     5.367865273                 13.2                      0.1                     13.1                     23.5                     28.3 
>>  Performance counter stats for 'CPU(s) 0':
>>                194.4                      1.3                    193.1                    361.0                    434.3 
>>        5.368039176 seconds time elapsed
>>
>> We can only get single chip data's sum in Total_Memory_BW. Please let me know if I am missing something.
> 
> SNIP
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 02/19] perf metric: Add expr__add_id function
  2020-07-19 18:13 ` [PATCH 02/19] perf metric: Add " Jiri Olsa
@ 2020-07-26  9:16   ` kajoljain
  2020-07-28 12:27     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:16 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Adding expr__add_id function to data for ID
> with zero value, which is used when scanning
> the expression for IDs.
> 

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain

> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/perf/util/expr.c | 31 +++++++++++++++++++++++++------
>  tools/perf/util/expr.h |  1 +
>  tools/perf/util/expr.y |  2 +-
>  3 files changed, 27 insertions(+), 7 deletions(-)
> 
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index 578a173d4873..9228f60e2a20 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -32,6 +32,26 @@ static bool key_equal(const void *key1, const void *key2,
>  	return !strcmp((const char *)key1, (const char *)key2);
>  }
>  
> +/* Caller must make sure id is allocated */
> +int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
> +{
> +	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
> +	char *old_key = NULL;
> +	int ret;
> +
> +	data_ptr = malloc(sizeof(*data_ptr));
> +	if (!data_ptr)
> +		return -ENOMEM;
> +
> +	ret = hashmap__set(&ctx->ids, id, data_ptr,
> +			   (const void **)&old_key, (void **)&old_data);
> +	if (ret)
> +		free(data_ptr);
> +	free(old_key);
> +	free(old_data);
> +	return ret;
> +}
> +
>  /* Caller must make sure id is allocated */
>  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>  {
> @@ -39,12 +59,11 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>  	char *old_key = NULL;
>  	int ret;
>  
> -	if (val != 0.0) {
> -		data_ptr = malloc(sizeof(*data_ptr));
> -		if (!data_ptr)
> -			return -ENOMEM;
> -		data_ptr->val = val;
> -	}
> +	data_ptr = malloc(sizeof(*data_ptr));
> +	if (!data_ptr)
> +		return -ENOMEM;
> +	data_ptr->val = val;
> +
>  	ret = hashmap__set(&ctx->ids, id, data_ptr,
>  			   (const void **)&old_key, (void **)&old_data);
>  	if (ret)
> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> index 21fe5bd85718..ac32cda42006 100644
> --- a/tools/perf/util/expr.h
> +++ b/tools/perf/util/expr.h
> @@ -26,6 +26,7 @@ struct expr_scanner_ctx {
>  
>  void expr__ctx_init(struct expr_parse_ctx *ctx);
>  void expr__ctx_clear(struct expr_parse_ctx *ctx);
> +int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
>  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr);
>  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
> index b2b3420ea6ec..8befe4a46f87 100644
> --- a/tools/perf/util/expr.y
> +++ b/tools/perf/util/expr.y
> @@ -69,7 +69,7 @@ all_other: all_other other
>  
>  other: ID
>  {
> -	expr__add_id_val(ctx, $1, 0.0);
> +	expr__add_id(ctx, $1);
>  }
>  |
>  MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ','
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data
  2020-07-19 18:13 ` [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data Jiri Olsa
@ 2020-07-26  9:17   ` kajoljain
  2020-07-28 12:28     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:17 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Changing expr__get_id to use and return struct expr_id_data
> pointer as value for the ID. This way we can access data other
> than value for given ID in following changes.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain

>  tools/perf/util/expr.c | 10 +++-------
>  tools/perf/util/expr.h |  3 ++-
>  tools/perf/util/expr.y | 14 +++++++++-----
>  3 files changed, 14 insertions(+), 13 deletions(-)
> 
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index 9228f60e2a20..4e5a6533dfce 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -73,14 +73,10 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>  	return ret;
>  }
>  
> -int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr)
> +int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> +		 struct expr_id_data **data)
>  {
> -	struct expr_id_data *data;
> -
> -	if (!hashmap__find(&ctx->ids, id, (void **)&data))
> -		return -1;
> -	*val_ptr = (data == NULL) ?  0.0 : data->val;
> -	return 0;
> +	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
>  }
>  
>  void expr__ctx_init(struct expr_parse_ctx *ctx)
> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> index ac32cda42006..f38292fdab19 100644
> --- a/tools/perf/util/expr.h
> +++ b/tools/perf/util/expr.h
> @@ -28,7 +28,8 @@ void expr__ctx_init(struct expr_parse_ctx *ctx);
>  void expr__ctx_clear(struct expr_parse_ctx *ctx);
>  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
>  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> -int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr);
> +int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> +		 struct expr_id_data **data);
>  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
>  		const char *expr, int runtime);
>  int expr__find_other(const char *expr, const char *one,
> diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
> index 8befe4a46f87..0d4f5d324be7 100644
> --- a/tools/perf/util/expr.y
> +++ b/tools/perf/util/expr.y
> @@ -85,12 +85,16 @@ if_expr:
>  	;
>  
>  expr:	  NUMBER
> -	| ID			{ if (expr__get_id(ctx, $1, &$$)) {
> -					pr_debug("%s not found\n", $1);
> +	| ID			{
> +					struct expr_id_data *data;
> +
> +					if (expr__get_id(ctx, $1, &data) || !data) {
> +						pr_debug("%s not found\n", $1);
> +						free($1);
> +						YYABORT;
> +					}
> +					$$ = data->val;
>  					free($1);
> -					YYABORT;
> -				  }
> -				  free($1);
>  				}
>  	| expr '|' expr		{ $$ = (long)$1 | (long)$3; }
>  	| expr '&' expr		{ $$ = (long)$1 & (long)$3; }
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 04/19] perf metric: Add expr__del_id function
  2020-07-19 18:13 ` [PATCH 04/19] perf metric: Add expr__del_id function Jiri Olsa
@ 2020-07-26  9:17   ` kajoljain
  2020-07-28 12:28     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:17 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Adding expr__del_id function to remove ID from hashmap.
> It will save us few lines in following changes.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain

> ---
>  tools/perf/util/expr.c | 21 +++++++++++++--------
>  tools/perf/util/expr.h |  1 +
>  2 files changed, 14 insertions(+), 8 deletions(-)
> 
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index 4e5a6533dfce..f726211f49d4 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -79,6 +79,17 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>  	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
>  }
>  
> +void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
> +{
> +	struct expr_id_data *old_val = NULL;
> +	char *old_key = NULL;
> +
> +	hashmap__delete(&ctx->ids, id,
> +			(const void **)&old_key, (void **)&old_val);
> +	free(old_key);
> +	free(old_val);
> +}
> +
>  void expr__ctx_init(struct expr_parse_ctx *ctx)
>  {
>  	hashmap__init(&ctx->ids, key_hash, key_equal, NULL);
> @@ -136,16 +147,10 @@ int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
>  int expr__find_other(const char *expr, const char *one,
>  		     struct expr_parse_ctx *ctx, int runtime)
>  {
> -	struct expr_id_data *old_val = NULL;
> -	char *old_key = NULL;
>  	int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime);
>  
> -	if (one) {
> -		hashmap__delete(&ctx->ids, one,
> -				(const void **)&old_key, (void **)&old_val);
> -		free(old_key);
> -		free(old_val);
> -	}
> +	if (one)
> +		expr__del_id(ctx, one);
>  
>  	return ret;
>  }
> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> index f38292fdab19..2462abd0ac65 100644
> --- a/tools/perf/util/expr.h
> +++ b/tools/perf/util/expr.h
> @@ -26,6 +26,7 @@ struct expr_scanner_ctx {
>  
>  void expr__ctx_init(struct expr_parse_ctx *ctx);
>  void expr__ctx_clear(struct expr_parse_ctx *ctx);
> +void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
>  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
>  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 05/19] perf metric: Add macros for iterating map events
  2020-07-19 18:13 ` [PATCH 05/19] perf metric: Add macros for iterating map events Jiri Olsa
  2020-07-19 21:46   ` Ian Rogers
@ 2020-07-26  9:17   ` kajoljain
  1 sibling, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:17 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian, Ian Rogers



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Adding following macros to iterate events and metric:
>   map_for_each_event(__pe, __idx, __map)
>     - iterates over all pmu_events_map events
>   map_for_each_metric(__pe, __idx, __map, __metric)
>     - iterates over all metrics that match __metric argument
> 
> and use it in metricgroup__add_metric function. Macros
> will be be used from other places in following changes.
> 
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain

> ---
>  tools/perf/util/metricgroup.c | 77 ++++++++++++++++++-----------------
>  1 file changed, 40 insertions(+), 37 deletions(-)
> 
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index df0356ec120d..b37008fc253c 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -614,6 +614,17 @@ static int __metricgroup__add_metric(struct list_head *group_list,
>  	return 0;
>  }
>  
> +#define map_for_each_event(__pe, __idx, __map)				\
> +	for (__idx = 0, __pe = &__map->table[__idx];			\
> +	     __pe->name || __pe->metric_group || __pe->metric_name;	\
> +	     __pe = &__map->table[++__idx])
> +
> +#define map_for_each_metric(__pe, __idx, __map, __metric)		\
> +	map_for_each_event(__pe, __idx, __map)				\
> +		if (__pe->metric_expr &&				\
> +		    (match_metric(__pe->metric_group, __metric) ||	\
> +		     match_metric(__pe->metric_name, __metric)))
> +
>  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  				   struct strbuf *events,
>  				   struct list_head *group_list,
> @@ -624,49 +635,41 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  	int i, ret;
>  	bool has_match = false;
>  
> -	for (i = 0; ; i++) {
> -		pe = &map->table[i];
> -
> -		if (!pe->name && !pe->metric_group && !pe->metric_name) {
> -			/* End of pmu events. */
> -			if (!has_match)
> -				return -EINVAL;
> -			break;
> -		}
> -		if (!pe->metric_expr)
> -			continue;
> -		if (match_metric(pe->metric_group, metric) ||
> -		    match_metric(pe->metric_name, metric)) {
> -			has_match = true;
> -			pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> -
> -			if (!strstr(pe->metric_expr, "?")) {
> -				ret = __metricgroup__add_metric(group_list,
> -								pe,
> -								metric_no_group,
> -								1);
> -				if (ret)
> -					return ret;
> -			} else {
> -				int j, count;
> +	map_for_each_metric(pe, i, map, metric) {
> +		pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> +		has_match = true;
> +
> +		if (!strstr(pe->metric_expr, "?")) {
> +			ret = __metricgroup__add_metric(group_list,
> +							pe,
> +							metric_no_group,
> +							1);
> +			if (ret)
> +				return ret;
> +		} else {
> +			int j, count;
>  
> -				count = arch_get_runtimeparam();
> +			count = arch_get_runtimeparam();
>  
> -				/* This loop is added to create multiple
> -				 * events depend on count value and add
> -				 * those events to group_list.
> -				 */
> +			/* This loop is added to create multiple
> +			 * events depend on count value and add
> +			 * those events to group_list.
> +			 */
>  
> -				for (j = 0; j < count; j++) {
> -					ret = __metricgroup__add_metric(
> -						group_list, pe,
> -						metric_no_group, j);
> -					if (ret)
> -						return ret;
> -				}
> +			for (j = 0; j < count; j++) {
> +				ret = __metricgroup__add_metric(
> +					group_list, pe,
> +					metric_no_group, j);
> +				if (ret)
> +					return ret;
>  			}
>  		}
>  	}
> +
> +	/* End of pmu events. */
> +	if (!has_match)
> +		return -EINVAL;
> +
>  	list_for_each_entry(eg, group_list, nd) {
>  		if (events->len > 0)
>  			strbuf_addf(events, ",");
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 06/19] perf metric: Add add_metric function
  2020-07-19 18:13 ` [PATCH 06/19] perf metric: Add add_metric function Jiri Olsa
@ 2020-07-26  9:17   ` kajoljain
  2020-07-28 12:30     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:17 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Decouple metric adding logging into add_metric function,
> so it can be used from other places in following changes.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
>  tools/perf/util/metricgroup.c | 62 ++++++++++++++++++++---------------
>  1 file changed, 36 insertions(+), 26 deletions(-)
> 
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index b37008fc253c..4096be7a7a9e 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -625,6 +625,39 @@ static int __metricgroup__add_metric(struct list_head *group_list,
>  		    (match_metric(__pe->metric_group, __metric) ||	\
>  		     match_metric(__pe->metric_name, __metric)))
>  
> +static int add_metric(struct list_head *group_list,
> +		      struct pmu_event *pe,
> +		      bool metric_no_group)
> +{
> +	int ret = 0;
> +
> +	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> +
> +	if (!strstr(pe->metric_expr, "?")) {
> +		ret = __metricgroup__add_metric(group_list,
> +						pe,
> +						metric_no_group,
> +						1);
> +	} else {
> +		int j, count;
> +
> +		count = arch_get_runtimeparam();
> +
> +		/* This loop is added to create multiple
> +		 * events depend on count value and add
> +		 * those events to group_list.
> +		 */
> +
> +		for (j = 0; j < count && !ret; j++) {
> +			ret = __metricgroup__add_metric(
> +				group_list, pe,
> +				metric_no_group, j);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
>  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  				   struct strbuf *events,
>  				   struct list_head *group_list,
> @@ -636,34 +669,11 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  	bool has_match = false;
>  
>  	map_for_each_metric(pe, i, map, metric) {
> -		pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
>  		has_match = true;
>  
> -		if (!strstr(pe->metric_expr, "?")) {
> -			ret = __metricgroup__add_metric(group_list,
> -							pe,
> -							metric_no_group,
> -							1);
> -			if (ret)
> -				return ret;
> -		} else {
> -			int j, count;
> -
> -			count = arch_get_runtimeparam();
> -
> -			/* This loop is added to create multiple
> -			 * events depend on count value and add
> -			 * those events to group_list.
> -			 */
> -
> -			for (j = 0; j < count; j++) {
> -				ret = __metricgroup__add_metric(
> -					group_list, pe,
> -					metric_no_group, j);
> -				if (ret)
> -					return ret;
> -			}
> -		}
> +		ret = add_metric(group_list, pe, metric_no_group);
> +		if (ret)
> +			return ret;
>  	}
>  
>  	/* End of pmu events. */
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric
  2020-07-19 18:13 ` [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric Jiri Olsa
@ 2020-07-26  9:18   ` kajoljain
  2020-07-28 12:30     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:18 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Renaming __metricgroup__add_metric to __add_metric
> to fit in the current function names.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> ---
>  tools/perf/util/metricgroup.c | 17 ++++++-----------
>  1 file changed, 6 insertions(+), 11 deletions(-)
> 
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 4096be7a7a9e..ccd80538a6ae 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -571,10 +571,10 @@ int __weak arch_get_runtimeparam(void)
>  	return 1;
>  }
>  
> -static int __metricgroup__add_metric(struct list_head *group_list,
> -				     struct pmu_event *pe,
> -				     bool metric_no_group,
> -				     int runtime)
> +static int __add_metric(struct list_head *group_list,
> +			struct pmu_event *pe,
> +			bool metric_no_group,
> +			int runtime)
>  {
>  	struct egroup *eg;
>  
> @@ -634,10 +634,7 @@ static int add_metric(struct list_head *group_list,
>  	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
>  
>  	if (!strstr(pe->metric_expr, "?")) {
> -		ret = __metricgroup__add_metric(group_list,
> -						pe,
> -						metric_no_group,
> -						1);
> +		ret = __add_metric(group_list, pe, metric_no_group, 1);
>  	} else {
>  		int j, count;
>  
> @@ -649,9 +646,7 @@ static int add_metric(struct list_head *group_list,
>  		 */
>  
>  		for (j = 0; j < count && !ret; j++) {
> -			ret = __metricgroup__add_metric(
> -				group_list, pe,
> -				metric_no_group, j);
> +			ret = __add_metric(group_list, pe, metric_no_group, j);
>  		}
>  	}
>  
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node
  2020-07-19 22:18   ` Ian Rogers
@ 2020-07-26  9:18     ` kajoljain
  2020-07-28 12:31     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:18 UTC (permalink / raw)
  To: Ian Rogers, Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian



On 7/20/20 3:48 AM, Ian Rogers wrote:
> On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
>>
>> 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>
> 
> Acked-by: Ian Rogers <irogers@google.com>
> 
> Thanks,
> Ian

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> 
>> ---
>>  tools/perf/util/metricgroup.c | 170 +++++++++++++++++++++++++++++++---
>>  1 file changed, 156 insertions(+), 14 deletions(-)
>>
>> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
>> index ccd80538a6ae..d1b2c1aa436f 100644
>> --- a/tools/perf/util/metricgroup.c
>> +++ b/tools/perf/util/metricgroup.c
>> @@ -102,12 +102,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;
>>  };
>> @@ -574,27 +587,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;
>> +
>> +               /*
>> +                * 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;
>>
>> -       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);
>> +               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 {
>> @@ -625,16 +683,78 @@ 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,
>> +                     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 add_metric(struct list_head *group_list,
>>                       struct pmu_event *pe,
>> -                     bool metric_no_group)
>> +                     bool metric_no_group,
>> +                     struct egroup **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;
>>
>> @@ -646,7 +766,7 @@ static int add_metric(struct list_head *group_list,
>>                  */
>>
>>                 for (j = 0; j < count && !ret; j++) {
>> -                       ret = __add_metric(group_list, pe, metric_no_group, j);
>> +                       ret = __add_metric(group_list, pe, metric_no_group, j, egp);
>>                 }
>>         }
>>
>> @@ -657,6 +777,7 @@ 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)
>> +
>>  {
>>         struct pmu_event *pe;
>>         struct egroup *eg;
>> @@ -665,8 +786,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);
>> +               ret = add_metric(group_list, pe, metric_no_group, &eg);
>> +               if (ret)
>> +                       return ret;
>> +
>> +               /*
>> +                * Process any possible referenced metrics
>> +                * included in the expression.
>> +                */
>> +               ret = resolve_metric(eg, metric_no_group,
>> +                                    group_list, map);
>>                 if (ret)
>>                         return ret;
>>         }
>> @@ -723,11 +854,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.25.4
>>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr
  2020-07-19 18:13 ` [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr Jiri Olsa
@ 2020-07-26  9:18   ` kajoljain
  2020-07-28 12:32     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:18 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Add referenced metrics into struct metric_expr object,
> so they are accessible when computing the metric.
> 
> Storing just name and expression itself, so the metric
> can be resolved and computed.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> ---
>  tools/perf/util/metricgroup.c | 32 ++++++++++++++++++++++++++++++++
>  tools/perf/util/metricgroup.h |  6 ++++++
>  2 files changed, 38 insertions(+)
> 
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index d1b2c1aa436f..bb5757b9419d 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -83,6 +83,7 @@ static void metric_event_delete(struct rblist *rblist __maybe_unused,
>  	struct metric_expr *expr, *tmp;
>  
>  	list_for_each_entry_safe(expr, tmp, &me->head, nd) {
> +		free(expr->metric_refs);
>  		free(expr);
>  	}
>  
> @@ -248,6 +249,7 @@ static int metricgroup__setup_events(struct list_head *groups,
>  
>  	list_for_each_entry (eg, groups, nd) {
>  		struct evsel **metric_events;
> +		struct metric_ref *metric_refs = NULL;
>  
>  		metric_events = calloc(sizeof(void *),
>  				hashmap__size(&eg->pctx.ids) + 1);
> @@ -279,6 +281,36 @@ static int metricgroup__setup_events(struct list_head *groups,
>  			free(metric_events);
>  			break;
>  		}
> +
> +		/*
> +		 * Collect and store collected nested expressions
> +		 * for metric processing.
> +		 */
> +		if (eg->metric_refs_cnt) {
> +			struct metric_ref_node *ref;
> +
> +			metric_refs = zalloc(sizeof(struct metric_ref) * (eg->metric_refs_cnt + 1));
> +			if (!metric_refs) {
> +				ret = -ENOMEM;
> +				free(metric_events);
> +				break;
> +			}
> +
> +			i = 0;
> +			list_for_each_entry(ref, &eg->metric_refs, list) {
> +				/*
> +				 * Intentionally passing just const char pointers,
> +				 * originally from 'struct pmu_event' object.
> +				 * We don't need to change them, so there's no
> +				 * need to create our own copy.
> +				 */
> +				metric_refs[i].metric_name = ref->metric_name;
> +				metric_refs[i].metric_expr = ref->metric_expr;
> +				i++;
> +			}
> +		};
> +
> +		expr->metric_refs = metric_refs;
>  		expr->metric_expr = eg->metric_expr;
>  		expr->metric_name = eg->metric_name;
>  		expr->metric_unit = eg->metric_unit;
> diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> index 8315bd1a7da4..62623a39cbec 100644
> --- a/tools/perf/util/metricgroup.h
> +++ b/tools/perf/util/metricgroup.h
> @@ -18,12 +18,18 @@ struct metric_event {
>  	struct list_head head; /* list of metric_expr */
>  };
>  
> +struct metric_ref {
> +	const char *metric_name;
> +	const char *metric_expr;
> +};
> +
>  struct metric_expr {
>  	struct list_head nd;
>  	const char *metric_expr;
>  	const char *metric_name;
>  	const char *metric_unit;
>  	struct evsel **metric_events;
> +	struct metric_ref *metric_refs;
>  	int runtime;
>  };
>  
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 10/19] perf metric: Add referenced metrics to hash data
  2020-07-19 22:32   ` Ian Rogers
@ 2020-07-26  9:18     ` kajoljain
  2020-07-28 12:32     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:18 UTC (permalink / raw)
  To: Ian Rogers, Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian



On 7/20/20 4:02 AM, Ian Rogers wrote:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>>
>> Adding referenced metrics to the parsing context so they
>> can be resolved during the metric processing.
>>
>> Adding expr__add_ref function to store referenced metrics
>> into parse context.
>>
>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> 
> Thanks,
> Ian
> 
>> ---
>>  tools/perf/util/expr.c        | 54 +++++++++++++++++++++++++++++++++++
>>  tools/perf/util/expr.h        | 13 ++++++++-
>>  tools/perf/util/stat-shadow.c | 20 +++++++++----
>>  3 files changed, 80 insertions(+), 7 deletions(-)
>>
>> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
>> index f726211f49d4..d3997c2b4a90 100644
>> --- a/tools/perf/util/expr.c
>> +++ b/tools/perf/util/expr.c
>> @@ -4,10 +4,14 @@
>>  #include <errno.h>
>>  #include <stdlib.h>
>>  #include <string.h>
>> +#include "metricgroup.h"
>> +#include "debug.h"
>>  #include "expr.h"
>>  #include "expr-bison.h"
>>  #include "expr-flex.h"
>>  #include <linux/kernel.h>
>> +#include <linux/zalloc.h>
>> +#include <ctype.h>
>>
>>  #ifdef PARSER_DEBUG
>>  extern int expr_debug;
>> @@ -63,6 +67,7 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>>         if (!data_ptr)
>>                 return -ENOMEM;
>>         data_ptr->val = val;
>> +       data_ptr->is_ref = false;
>>
>>         ret = hashmap__set(&ctx->ids, id, data_ptr,
>>                            (const void **)&old_key, (void **)&old_data);
>> @@ -73,6 +78,55 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
>>         return ret;
>>  }
>>
>> +int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
>> +{
>> +       struct expr_id_data *data_ptr = NULL, *old_data = NULL;
>> +       char *old_key = NULL;
>> +       char *name, *p;
>> +       int ret;
>> +
>> +       data_ptr = zalloc(sizeof(*data_ptr));
>> +       if (!data_ptr)
>> +               return -ENOMEM;
>> +
>> +       name = strdup(ref->metric_name);
>> +       if (!name) {
>> +               free(data_ptr);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       /*
>> +        * The jevents tool converts all metric expressions
>> +        * to lowercase, including metric references, hence
>> +        * we need to add lowercase name for metric, so it's
>> +        * properly found.
>> +        */
>> +       for (p = name; *p; p++)
>> +               *p = tolower(*p);
>> +
>> +       /*
>> +        * Intentionally passing just const char pointers,
>> +        * originally from 'struct pmu_event' object.
>> +        * We don't need to change them, so there's no
>> +        * need to create our own copy.
>> +        */
>> +       data_ptr->ref.metric_name = ref->metric_name;
>> +       data_ptr->ref.metric_expr = ref->metric_expr;
>> +       data_ptr->is_ref = true;
>> +
>> +       ret = hashmap__set(&ctx->ids, name, data_ptr,
>> +                          (const void **)&old_key, (void **)&old_data);
>> +       if (ret)
>> +               free(data_ptr);
>> +
>> +       pr_debug2("adding ref metric %s: %s\n",
>> +                 ref->metric_name, ref->metric_expr);
>> +
>> +       free(old_key);
>> +       free(old_data);
>> +       return ret;
>> +}
>> +
>>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>>                  struct expr_id_data **data)
>>  {
>> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
>> index 2462abd0ac65..81d04ff7f857 100644
>> --- a/tools/perf/util/expr.h
>> +++ b/tools/perf/util/expr.h
>> @@ -11,12 +11,22 @@
>>  #include "util/hashmap.h"
>>  //#endif
>>
>> +struct metric_ref;
>> +
>>  struct expr_parse_ctx {
>>         struct hashmap ids;
>>  };
>>
>>  struct expr_id_data {
>> -       double  val;
>> +       union {
>> +               double val;
>> +               struct {
>> +                       const char *metric_name;
>> +                       const char *metric_expr;
>> +               } ref;
>> +       };
>> +
>> +       bool is_ref;
>>  };
>>
>>  struct expr_scanner_ctx {
>> @@ -29,6 +39,7 @@ void expr__ctx_clear(struct expr_parse_ctx *ctx);
>>  void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
>>  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
>>  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
>> +int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
>>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>>                  struct expr_id_data **data);
>>  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
>> diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
>> index fc9ac4b4218e..e1ba6c1b916a 100644
>> --- a/tools/perf/util/stat-shadow.c
>> +++ b/tools/perf/util/stat-shadow.c
>> @@ -731,13 +731,14 @@ static void print_smi_cost(struct perf_stat_config *config,
>>  }
>>
>>  static int prepare_metric(struct evsel **metric_events,
>> +                         struct metric_ref *metric_refs,
>>                           struct expr_parse_ctx *pctx,
>>                           int cpu,
>>                           struct runtime_stat *st)
>>  {
>>         double scale;
>>         char *n, *pn;
>> -       int i;
>> +       int i, j, ret;
>>
>>         expr__ctx_init(pctx);
>>         for (i = 0; metric_events[i]; i++) {
>> @@ -778,12 +779,19 @@ static int prepare_metric(struct evsel **metric_events,
>>                         expr__add_id_val(pctx, n, avg_stats(stats)*scale);
>>         }
>>
>> +       for (j = 0; metric_refs && metric_refs[j].metric_name; j++) {
>> +               ret = expr__add_ref(pctx, &metric_refs[j]);
>> +               if (ret)
>> +                       return ret;
>> +       }
>> +
>>         return i;
>>  }
>>
>>  static void generic_metric(struct perf_stat_config *config,
>>                            const char *metric_expr,
>>                            struct evsel **metric_events,
>> +                          struct metric_ref *metric_refs,
>>                            char *name,
>>                            const char *metric_name,
>>                            const char *metric_unit,
>> @@ -798,7 +806,7 @@ static void generic_metric(struct perf_stat_config *config,
>>         int i;
>>         void *ctxp = out->ctx;
>>
>> -       i = prepare_metric(metric_events, &pctx, cpu, st);
>> +       i = prepare_metric(metric_events, metric_refs, &pctx, cpu, st);
>>         if (i < 0)
>>                 return;
>>
>> @@ -847,7 +855,7 @@ double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_sta
>>         struct expr_parse_ctx pctx;
>>         double ratio;
>>
>> -       if (prepare_metric(mexp->metric_events, &pctx, cpu, st) < 0)
>> +       if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0)
>>                 return 0.;
>>
>>         if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1))
>> @@ -1064,8 +1072,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
>>                 else
>>                         print_metric(config, ctxp, NULL, NULL, name, 0);
>>         } else if (evsel->metric_expr) {
>> -               generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name,
>> -                               evsel->metric_name, NULL, 1, cpu, out, st);
>> +               generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
>> +                               evsel->name, evsel->metric_name, NULL, 1, cpu, out, st);
>>         } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) {
>>                 char unit = 'M';
>>                 char unit_buf[10];
>> @@ -1093,7 +1101,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
>>                         if (num++ > 0)
>>                                 out->new_line(config, ctxp);
>>                         generic_metric(config, mexp->metric_expr, mexp->metric_events,
>> -                                       evsel->name, mexp->metric_name,
>> +                                       mexp->metric_refs, evsel->name, mexp->metric_name,
>>                                         mexp->metric_unit, mexp->runtime, cpu, out, st);
>>                 }
>>         }
>> --
>> 2.25.4
>>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 11/19] perf metric: Compute referenced metrics
  2020-07-19 18:13 ` [PATCH 11/19] perf metric: Compute referenced metrics Jiri Olsa
@ 2020-07-26  9:19   ` kajoljain
  2020-07-28 12:33     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:19 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Adding computation (expr__parse call) of referenced metric at
> the point when it needs to be resolved during the parent metric
> computation.
> 
> Once the inner metric is computed, the result is stored and
> used if there's another usage of that metric.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> ---
>  tools/perf/util/expr.c | 31 +++++++++++++++++++++++++++++++
>  tools/perf/util/expr.h |  3 +++
>  tools/perf/util/expr.y |  4 ++--
>  3 files changed, 36 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index d3997c2b4a90..a346ca590513 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -112,6 +112,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
>  	 */
>  	data_ptr->ref.metric_name = ref->metric_name;
>  	data_ptr->ref.metric_expr = ref->metric_expr;
> +	data_ptr->ref.counted = false;
>  	data_ptr->is_ref = true;
>  
>  	ret = hashmap__set(&ctx->ids, name, data_ptr,
> @@ -133,6 +134,34 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>  	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
>  }
>  
> +int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
> +		     struct expr_id_data **datap)
> +{
> +	struct expr_id_data *data;
> +
> +	if (expr__get_id(ctx, id, datap) || !*datap) {
> +		pr_debug("%s not found\n", id);
> +		return -1;
> +	}
> +
> +	data = *datap;
> +
> +	pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n",
> +		  data->is_ref, data->ref.counted, data->val, id);
> +
> +	if (data->is_ref && !data->ref.counted) {
> +		data->ref.counted = true;
> +		pr_debug("processing metric: %s ENTRY\n", id);
> +		if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) {
> +			pr_debug("%s failed to count\n", id);
> +			return -1;
> +		}
> +		pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
> +	}
> +
> +	return 0;
> +}
> +
>  void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
>  {
>  	struct expr_id_data *old_val = NULL;
> @@ -173,6 +202,8 @@ __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
>  	void *scanner;
>  	int ret;
>  
> +	pr_debug2("parsing metric: %s\n", expr);
> +
>  	ret = expr_lex_init_extra(&scanner_ctx, &scanner);
>  	if (ret)
>  		return ret;
> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> index 81d04ff7f857..9ed208d93418 100644
> --- a/tools/perf/util/expr.h
> +++ b/tools/perf/util/expr.h
> @@ -23,6 +23,7 @@ struct expr_id_data {
>  		struct {
>  			const char *metric_name;
>  			const char *metric_expr;
> +			bool counted;
>  		} ref;
>  	};
>  
> @@ -42,6 +43,8 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
>  int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
>  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
>  		 struct expr_id_data **data);
> +int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
> +		     struct expr_id_data **datap);
>  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
>  		const char *expr, int runtime);
>  int expr__find_other(const char *expr, const char *one,
> diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
> index 0d4f5d324be7..d34b370391c6 100644
> --- a/tools/perf/util/expr.y
> +++ b/tools/perf/util/expr.y
> @@ -88,11 +88,11 @@ expr:	  NUMBER
>  	| ID			{
>  					struct expr_id_data *data;
>  
> -					if (expr__get_id(ctx, $1, &data) || !data) {
> -						pr_debug("%s not found\n", $1);
> +					if (expr__resolve_id(ctx, $1, &data)) {
>  						free($1);
>  						YYABORT;
>  					}
> +
>  					$$ = data->val;
>  					free($1);
>  				}
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 12/19] perf metric: Add events for the current list
  2020-07-19 22:34   ` Ian Rogers
@ 2020-07-26  9:19     ` kajoljain
  2020-07-28 12:33     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:19 UTC (permalink / raw)
  To: Ian Rogers, Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian



On 7/20/20 4:04 AM, Ian Rogers wrote:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>>
>> There's no need to iterate the whole list of groups,
>> when adding new events. The currently created groups
>> are the ones we want to add.
>>
>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>
> 

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> Thanks,
> Ian
> 
>> ---
>>  tools/perf/util/metricgroup.c | 9 ++++++---
>>  1 file changed, 6 insertions(+), 3 deletions(-)
>>
>> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
>> index bb5757b9419d..332414d93f7a 100644
>> --- a/tools/perf/util/metricgroup.c
>> +++ b/tools/perf/util/metricgroup.c
>> @@ -813,6 +813,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>  {
>>         struct pmu_event *pe;
>>         struct egroup *eg;
>> +       LIST_HEAD(list);
>>         int i, ret;
>>         bool has_match = false;
>>
>> @@ -820,7 +821,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>                 has_match = true;
>>                 eg = NULL;
>>
>> -               ret = add_metric(group_list, pe, metric_no_group, &eg);
>> +               ret = add_metric(&list, pe, metric_no_group, &eg);
>>                 if (ret)
>>                         return ret;
>>
>> @@ -829,7 +830,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>                  * included in the expression.
>>                  */
>>                 ret = resolve_metric(eg, metric_no_group,
>> -                                    group_list, map);
>> +                                    &list, map);
>>                 if (ret)
>>                         return ret;
>>         }
>> @@ -838,7 +839,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>         if (!has_match)
>>                 return -EINVAL;
>>
>> -       list_for_each_entry(eg, group_list, nd) {
>> +       list_for_each_entry(eg, &list, nd) {
>>                 if (events->len > 0)
>>                         strbuf_addf(events, ",");
>>
>> @@ -850,6 +851,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>                                                            &eg->pctx);
>>                 }
>>         }
>> +
>> +       list_splice(&list, group_list);
>>         return 0;
>>  }
>>
>> --
>> 2.25.4
>>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test
  2020-07-19 18:13 ` [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test Jiri Olsa
@ 2020-07-26  9:19   ` kajoljain
  2020-07-28 12:34     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:19 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Adding test that compute metric with other metrics in it.
> 
>   cache_miss_cycles = metric:dcache_miss_cpi + metric:icache_miss_cycles
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> ---
>  tools/perf/tests/parse-metric.c | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
> 
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 8c48251425e1..28f33893338b 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -11,6 +11,8 @@
>  #include "debug.h"
>  #include "expr.h"
>  #include "stat.h"
> +#include <perf/cpumap.h>
> +#include <perf/evlist.h>
>  
>  static struct pmu_event pme_test[] = {
>  {
> @@ -22,6 +24,18 @@ static struct pmu_event pme_test[] = {
>  			  "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
>  	.metric_name	= "Frontend_Bound_SMT",
>  },
> +{
> +	.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
> +	.metric_name	= "dcache_miss_cpi",
> +},
> +{
> +	.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
> +	.metric_name	= "icache_miss_cycles",
> +},
> +{
> +	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
> +	.metric_name	= "cache_miss_cycles",
> +},
>  };
>  
>  static struct pmu_events_map map = {
> @@ -162,9 +176,28 @@ static int test_frontend(void)
>  	return 0;
>  }
>  
> +static int test_cache_miss_cycles(void)
> +{
> +	double ratio;
> +	struct value vals[] = {
> +		{ .event = "l1d-loads-misses",  .val = 300 },
> +		{ .event = "l1i-loads-misses",  .val = 200 },
> +		{ .event = "inst_retired.any",  .val = 400 },
> +		{ 0 },
> +	};
> +
> +	TEST_ASSERT_VAL("failed to compute metric",
> +			compute_metric("cache_miss_cycles", vals, &ratio) == 0);
> +
> +	TEST_ASSERT_VAL("cache_miss_cycles failed, wrong ratio",
> +			ratio == 1.25);
> +	return 0;
> +}
> +
>  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>  {
>  	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
>  	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
> +	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>  	return 0;
>  }
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 14/19] perf metric: Add DCache_L2 to metric parse test
  2020-07-19 18:13 ` [PATCH 14/19] perf metric: Add DCache_L2 " Jiri Olsa
@ 2020-07-26  9:19   ` kajoljain
  2020-07-28 12:34     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:19 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Adding test that compute DCache_L2 metrics with other related metrics in it.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> ---
>  tools/perf/tests/parse-metric.c | 71 +++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 28f33893338b..aa4d5a9f09a8 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -36,6 +36,27 @@ static struct pmu_event pme_test[] = {
>  	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
>  	.metric_name	= "cache_miss_cycles",
>  },
> +{
> +	.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
> +	.metric_name	= "DCache_L2_All_Hits",
> +},
> +{
> +	.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
> +			  "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
> +	.metric_name	= "DCache_L2_All_Miss",
> +},
> +{
> +	.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
> +	.metric_name	= "DCache_L2_All",
> +},
> +{
> +	.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
> +	.metric_name	= "DCache_L2_Hits",
> +},
> +{
> +	.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
> +	.metric_name	= "DCache_L2_Misses",
> +},
>  };
>  
>  static struct pmu_events_map map = {
> @@ -194,10 +215,60 @@ static int test_cache_miss_cycles(void)
>  	return 0;
>  }
>  
> +
> +/*
> + * DCache_L2_All_Hits = l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hi
> + * DCache_L2_All_Miss = max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) +
> + *                      l2_rqsts.pf_miss + l2_rqsts.rfo_miss
> + * DCache_L2_All      = dcache_l2_all_hits + dcache_l2_all_miss
> + * DCache_L2_Hits     = d_ratio(dcache_l2_all_hits, dcache_l2_all)
> + * DCache_L2_Misses   = d_ratio(dcache_l2_all_miss, dcache_l2_all)
> + *
> + * l2_rqsts.demand_data_rd_hit = 100
> + * l2_rqsts.pf_hit             = 200
> + * l2_rqsts.rfo_hi             = 300
> + * l2_rqsts.all_demand_data_rd = 400
> + * l2_rqsts.pf_miss            = 500
> + * l2_rqsts.rfo_miss           = 600
> + *
> + * DCache_L2_All_Hits = 600
> + * DCache_L2_All_Miss = MAX(400 - 100, 0) + 500 + 600 = 1400
> + * DCache_L2_All      = 600 + 1400  = 2000
> + * DCache_L2_Hits     = 600 / 2000  = 0.3
> + * DCache_L2_Misses   = 1400 / 2000 = 0.7
> + */
> +static int test_dcache_l2(void)
> +{
> +	double ratio;
> +	struct value vals[] = {
> +		{ .event = "l2_rqsts.demand_data_rd_hit", .val = 100 },
> +		{ .event = "l2_rqsts.pf_hit",             .val = 200 },
> +		{ .event = "l2_rqsts.rfo_hit",            .val = 300 },
> +		{ .event = "l2_rqsts.all_demand_data_rd", .val = 400 },
> +		{ .event = "l2_rqsts.pf_miss",            .val = 500 },
> +		{ .event = "l2_rqsts.rfo_miss",           .val = 600 },
> +		{ 0 },
> +	};
> +
> +	TEST_ASSERT_VAL("failed to compute metric",
> +			compute_metric("DCache_L2_Hits", vals, &ratio) == 0);
> +
> +	TEST_ASSERT_VAL("DCache_L2_Hits failed, wrong ratio",
> +			ratio == 0.3);
> +
> +	TEST_ASSERT_VAL("failed to compute metric",
> +			compute_metric("DCache_L2_Misses", vals, &ratio) == 0);
> +
> +	TEST_ASSERT_VAL("DCache_L2_Misses failed, wrong ratio",
> +			ratio == 0.7);
> +	return 0;
> +}
> +
>  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>  {
>  	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
>  	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
>  	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> +	TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
>  	return 0;
>  }
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 15/19] perf metric: Add recursion check when processing nested metrics
  2020-07-19 22:40   ` Ian Rogers
@ 2020-07-26  9:20     ` kajoljain
  2020-07-28 12:35     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:20 UTC (permalink / raw)
  To: Ian Rogers, Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian



On 7/20/20 4:10 AM, Ian Rogers wrote:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>>
>> Keeping the stack of nested metrics via 'struct expr_id' objects
>> and checking if we are in recursion via already processed metric.
>>
>> The stack is implemented as static array within the struct egroup
>> with 100 entries, which should be enough nesting depth for any
>> metric we have or plan to have at the moment.
>>
>> Adding test that simulates the recursion and checks we can
>> detect it.
>>
>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>
> 

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> Thanks,
> Ian
> 
>> ---
>>  tools/perf/tests/parse-metric.c |  34 +++++++++-
>>  tools/perf/util/expr.c          |   2 +
>>  tools/perf/util/expr.h          |   9 ++-
>>  tools/perf/util/metricgroup.c   | 117 +++++++++++++++++++++++++++++---
>>  4 files changed, 149 insertions(+), 13 deletions(-)
>>
>> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
>> index aa4d5a9f09a8..01370ccb9ed9 100644
>> --- a/tools/perf/tests/parse-metric.c
>> +++ b/tools/perf/tests/parse-metric.c
>> @@ -57,6 +57,18 @@ static struct pmu_event pme_test[] = {
>>         .metric_expr    = "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
>>         .metric_name    = "DCache_L2_Misses",
>>  },
>> +{
>> +       .metric_expr    = "ipc + m2",
>> +       .metric_name    = "M1",
>> +},
>> +{
>> +       .metric_expr    = "ipc + m1",
>> +       .metric_name    = "M2",
>> +},
>> +{
>> +       .metric_expr    = "1/m3",
>> +       .metric_name    = "M3",
>> +}
>>  };
>>
>>  static struct pmu_events_map map = {
>> @@ -139,8 +151,8 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>>         err = metricgroup__parse_groups_test(evlist, &map, name,
>>                                              false, false,
>>                                              &metric_events);
>> -
>> -       TEST_ASSERT_VAL("failed to parse metric", err == 0);
>> +       if (err)
>> +               return err;
>>
>>         if (perf_evlist__alloc_stats(evlist, false))
>>                 return -1;
>> @@ -264,11 +276,29 @@ static int test_dcache_l2(void)
>>         return 0;
>>  }
>>
>> +static int test_recursion_fail(void)
>> +{
>> +       double ratio;
>> +       struct value vals[] = {
>> +               { .event = "inst_retired.any",        .val = 300 },
>> +               { .event = "cpu_clk_unhalted.thread", .val = 200 },
>> +               { 0 },
>> +       };
>> +
>> +       TEST_ASSERT_VAL("failed to find recursion",
>> +                       compute_metric("M1", vals, &ratio) == -1);
>> +
>> +       TEST_ASSERT_VAL("failed to find recursion",
>> +                       compute_metric("M3", vals, &ratio) == -1);
>> +       return 0;
>> +}
>> +
>>  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>>  {
>>         TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
>>         TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
>>         TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>>         TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
>> +       TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
>>         return 0;
>>  }
>> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
>> index a346ca590513..53482ef53c41 100644
>> --- a/tools/perf/util/expr.c
>> +++ b/tools/perf/util/expr.c
>> @@ -47,6 +47,8 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
>>         if (!data_ptr)
>>                 return -ENOMEM;
>>
>> +       data_ptr->parent = ctx->parent;
>> +
>>         ret = hashmap__set(&ctx->ids, id, data_ptr,
>>                            (const void **)&old_key, (void **)&old_data);
>>         if (ret)
>> diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
>> index 9ed208d93418..fc2b5e824a66 100644
>> --- a/tools/perf/util/expr.h
>> +++ b/tools/perf/util/expr.h
>> @@ -13,8 +13,14 @@
>>
>>  struct metric_ref;
>>
>> +struct expr_id {
>> +       char            *id;
>> +       struct expr_id  *parent;
>> +};
>> +
>>  struct expr_parse_ctx {
>> -       struct hashmap ids;
>> +       struct hashmap   ids;
>> +       struct expr_id  *parent;
>>  };
>>
>>  struct expr_id_data {
>> @@ -25,6 +31,7 @@ struct expr_id_data {
>>                         const char *metric_expr;
>>                         bool counted;
>>                 } ref;
>> +               struct expr_id  *parent;
>>         };
>>
>>         bool is_ref;
>> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
>> index 332414d93f7a..2a45ee94fd61 100644
>> --- a/tools/perf/util/metricgroup.c
>> +++ b/tools/perf/util/metricgroup.c
>> @@ -24,6 +24,7 @@
>>  #include <subcmd/parse-options.h>
>>  #include <api/fs/fs.h>
>>  #include "util.h"
>> +#include <asm/bug.h>
>>
>>  struct metric_event *metricgroup__lookup(struct rblist *metric_events,
>>                                          struct evsel *evsel,
>> @@ -126,6 +127,28 @@ struct egroup {
>>         bool has_constraint;
>>  };
>>
>> +#define RECURSION_ID_MAX 100
>> +
>> +struct expr_ids {
>> +       struct expr_id  id[RECURSION_ID_MAX];
>> +       int             cnt;
>> +};
>> +
>> +static struct expr_id *expr_ids__alloc(struct expr_ids *ids)
>> +{
>> +       if (ids->cnt >= RECURSION_ID_MAX)
>> +               return NULL;
>> +       return &ids->id[ids->cnt++];
>> +}
>> +
>> +static void expr_ids__exit(struct expr_ids *ids)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < ids->cnt; i++)
>> +               free(ids->id[i].id);
>> +}
>> +
>>  /**
>>   * Find a group of events in perf_evlist that correpond to those from a parsed
>>   * metric expression. Note, as find_evsel_group is called in the same order as
>> @@ -620,7 +643,9 @@ static int __add_metric(struct list_head *group_list,
>>                         struct pmu_event *pe,
>>                         bool metric_no_group,
>>                         int runtime,
>> -                       struct egroup **egp)
>> +                       struct egroup **egp,
>> +                       struct expr_id *parent,
>> +                       struct expr_ids *ids)
>>  {
>>         struct metric_ref_node *ref;
>>         struct egroup *eg;
>> @@ -630,7 +655,7 @@ static int __add_metric(struct list_head *group_list,
>>                  * We got in here for the parent group,
>>                  * allocate it and put it on the list.
>>                  */
>> -               eg = malloc(sizeof(*eg));
>> +               eg = zalloc(sizeof(*eg));
>>                 if (!eg)
>>                         return -ENOMEM;
>>
>> @@ -643,6 +668,18 @@ static int __add_metric(struct list_head *group_list,
>>                 INIT_LIST_HEAD(&eg->metric_refs);
>>                 eg->metric_refs_cnt = 0;
>>                 *egp = eg;
>> +
>> +               parent = expr_ids__alloc(ids);
>> +               if (!parent) {
>> +                       free(eg);
>> +                       return -EINVAL;
>> +               }
>> +
>> +               parent->id = strdup(pe->metric_name);
>> +               if (!parent->id) {
>> +                       free(eg);
>> +                       return -ENOMEM;
>> +               }
>>         } else {
>>                 /*
>>                  * We got here for the referenced metric, via the
>> @@ -668,6 +705,10 @@ static int __add_metric(struct list_head *group_list,
>>                 eg->metric_refs_cnt++;
>>         }
>>
>> +       /* Force all found IDs in metric to have us as parent ID. */
>> +       WARN_ON_ONCE(!parent);
>> +       eg->pctx.parent = parent;
>> +
>>         /*
>>          * For both the parent and referenced metrics, we parse
>>          * all the metric's IDs and add it to the parent context.
>> @@ -728,15 +769,62 @@ static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *
>>         return NULL;
>>  }
>>
>> +static int recursion_check(struct egroup *eg, const char *id, struct expr_id **parent,
>> +                          struct expr_ids *ids)
>> +{
>> +       struct expr_id_data *data;
>> +       struct expr_id *p;
>> +       int ret;
>> +
>> +       /*
>> +        * We get the parent referenced by 'id' argument and
>> +        * traverse through all the parent object IDs to check
>> +        * if we already processed 'id', if we did, it's recursion
>> +        * and we fail.
>> +        */
>> +       ret = expr__get_id(&eg->pctx, id, &data);
>> +       if (ret)
>> +               return ret;
>> +
>> +       p = data->parent;
>> +
>> +       while (p->parent) {
>> +               if (!strcmp(p->id, id)) {
>> +                       pr_err("failed: recursion detected for %s\n", id);
>> +                       return -1;
>> +               }
>> +               p = p->parent;
>> +       }
>> +
>> +       /*
>> +        * If we are over the limit of static entris, the metric
>> +        * is too difficult/nested to process, fail as well.
>> +        */
>> +       p = expr_ids__alloc(ids);
>> +       if (!p) {
>> +               pr_err("failed: too many nested metrics\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       p->id     = strdup(id);
>> +       p->parent = data->parent;
>> +       *parent   = p;
>> +
>> +       return p->id ? 0 : -ENOMEM;
>> +}
>> +
>>  static int add_metric(struct list_head *group_list,
>>                       struct pmu_event *pe,
>>                       bool metric_no_group,
>> -                     struct egroup **egp);
>> +                     struct egroup **egp,
>> +                     struct expr_id *parent,
>> +                     struct expr_ids *ids);
>>
>>  static int resolve_metric(struct egroup *eg,
>>                           bool metric_no_group,
>>                           struct list_head *group_list,
>> -                         struct pmu_events_map *map)
>> +                         struct pmu_events_map *map,
>> +                         struct expr_ids *ids)
>>  {
>>         struct hashmap_entry *cur;
>>         size_t bkt;
>> @@ -750,18 +838,23 @@ static int resolve_metric(struct egroup *eg,
>>         do {
>>                 all = true;
>>                 hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
>> +                       struct expr_id *parent;
>>                         struct pmu_event *pe;
>>
>>                         pe = find_metric(cur->key, map);
>>                         if (!pe)
>>                                 continue;
>>
>> +                       ret = recursion_check(eg, cur->key, &parent, ids);
>> +                       if (ret)
>> +                               return ret;
>> +
>>                         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);
>> +                       ret = add_metric(group_list, pe, metric_no_group, &eg, parent, ids);
>>                         if (ret)
>>                                 return ret;
>>
>> @@ -779,14 +872,16 @@ static int resolve_metric(struct egroup *eg,
>>  static int add_metric(struct list_head *group_list,
>>                       struct pmu_event *pe,
>>                       bool metric_no_group,
>> -                     struct egroup **egp)
>> +                     struct egroup **egp,
>> +                     struct expr_id *parent,
>> +                     struct expr_ids *ids)
>>  {
>>         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, egp);
>> +               ret = __add_metric(group_list, pe, metric_no_group, 1, egp, parent, ids);
>>         } else {
>>                 int j, count;
>>
>> @@ -798,7 +893,7 @@ static int add_metric(struct list_head *group_list,
>>                  */
>>
>>                 for (j = 0; j < count && !ret; j++) {
>> -                       ret = __add_metric(group_list, pe, metric_no_group, j, egp);
>> +                       ret = __add_metric(group_list, pe, metric_no_group, j, egp, parent, ids);
>>                 }
>>         }
>>
>> @@ -811,6 +906,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>                                    struct pmu_events_map *map)
>>
>>  {
>> +       struct expr_ids ids = { 0 };
>>         struct pmu_event *pe;
>>         struct egroup *eg;
>>         LIST_HEAD(list);
>> @@ -821,7 +917,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>                 has_match = true;
>>                 eg = NULL;
>>
>> -               ret = add_metric(&list, pe, metric_no_group, &eg);
>> +               ret = add_metric(&list, pe, metric_no_group, &eg, NULL, &ids);
>>                 if (ret)
>>                         return ret;
>>
>> @@ -830,7 +926,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>                  * included in the expression.
>>                  */
>>                 ret = resolve_metric(eg, metric_no_group,
>> -                                    &list, map);
>> +                                    &list, map, &ids);
>>                 if (ret)
>>                         return ret;
>>         }
>> @@ -853,6 +949,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>>         }
>>
>>         list_splice(&list, group_list);
>> +       expr_ids__exit(&ids);
>>         return 0;
>>  }
>>
>> --
>> 2.25.4
>>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 17/19] perf metric: Add metric group test
  2020-07-19 22:41   ` Ian Rogers
@ 2020-07-26  9:20     ` kajoljain
  2020-07-28 12:37     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:20 UTC (permalink / raw)
  To: Ian Rogers, Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian



On 7/20/20 4:11 AM, Ian Rogers wrote:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
>>
>> Adding test for metric group plus compute_metric_group
>> function to get metrics values within the group.
>>
>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain

> 
> Thanks,
> Ian
> 
>> ---
>>  tools/perf/tests/parse-metric.c | 48 +++++++++++++++++++++++++++++++--
>>  1 file changed, 46 insertions(+), 2 deletions(-)
>>
>> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
>> index 5ac32f80f8ea..f2ba5b2c5557 100644
>> --- a/tools/perf/tests/parse-metric.c
>> +++ b/tools/perf/tests/parse-metric.c
>> @@ -18,6 +18,7 @@ static struct pmu_event pme_test[] = {
>>  {
>>         .metric_expr    = "inst_retired.any / cpu_clk_unhalted.thread",
>>         .metric_name    = "IPC",
>> +       .metric_group   = "group1",
>>  },
>>  {
>>         .metric_expr    = "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
>> @@ -35,6 +36,7 @@ static struct pmu_event pme_test[] = {
>>  {
>>         .metric_expr    = "(dcache_miss_cpi + icache_miss_cycles)",
>>         .metric_name    = "cache_miss_cycles",
>> +       .metric_group   = "group1",
>>  },
>>  {
>>         .metric_expr    = "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
>> @@ -127,7 +129,9 @@ static double compute_single(struct rblist *metric_events, struct evlist *evlist
>>         return 0.;
>>  }
>>
>> -static int compute_metric(const char *name, struct value *vals, double *ratio)
>> +static int __compute_metric(const char *name, struct value *vals,
>> +                           const char *name1, double *ratio1,
>> +                           const char *name2, double *ratio2)
>>  {
>>         struct rblist metric_events = {
>>                 .nr_entries = 0,
>> @@ -166,7 +170,10 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>>         load_runtime_stat(&st, evlist, vals);
>>
>>         /* And execute the metric */
>> -       *ratio = compute_single(&metric_events, evlist, &st, name);
>> +       if (name1 && ratio1)
>> +               *ratio1 = compute_single(&metric_events, evlist, &st, name1);
>> +       if (name2 && ratio2)
>> +               *ratio2 = compute_single(&metric_events, evlist, &st, name2);
>>
>>         /* ... clenup. */
>>         metricgroup__rblist_exit(&metric_events);
>> @@ -177,6 +184,18 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>>         return 0;
>>  }
>>
>> +static int compute_metric(const char *name, struct value *vals, double *ratio)
>> +{
>> +       return __compute_metric(name, vals, name, ratio, NULL, NULL);
>> +}
>> +
>> +static int compute_metric_group(const char *name, struct value *vals,
>> +                               const char *name1, double *ratio1,
>> +                               const char *name2, double *ratio2)
>> +{
>> +       return __compute_metric(name, vals, name1, ratio1, name2, ratio2);
>> +}
>> +
>>  static int test_ipc(void)
>>  {
>>         double ratio;
>> @@ -297,6 +316,30 @@ static int test_recursion_fail(void)
>>         return 0;
>>  }
>>
>> +static int test_metric_group(void)
>> +{
>> +       double ratio1, ratio2;
>> +       struct value vals[] = {
>> +               { .event = "cpu_clk_unhalted.thread", .val = 200 },
>> +               { .event = "l1d-loads-misses",        .val = 300 },
>> +               { .event = "l1i-loads-misses",        .val = 200 },
>> +               { .event = "inst_retired.any",        .val = 400 },
>> +               { 0 },
>> +       };
>> +
>> +       TEST_ASSERT_VAL("failed to find recursion",
>> +                       compute_metric_group("group1", vals,
>> +                                            "IPC", &ratio1,
>> +                                            "cache_miss_cycles", &ratio2) == 0);
>> +
>> +       TEST_ASSERT_VAL("group IPC failed, wrong ratio",
>> +                       ratio1 == 2.0);
>> +
>> +       TEST_ASSERT_VAL("group cache_miss_cycles failed, wrong ratio",
>> +                       ratio2 == 1.25);
>> +       return 0;
>> +}
>> +
>>  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>>  {
>>         TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
>> @@ -304,5 +347,6 @@ int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unu
>>         TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>>         TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
>>         TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
>> +       TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
>>         return 0;
>>  }
>> --
>> 2.25.4
>>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 18/19] perf metric: Rename struct egroup to metric
  2020-07-19 18:13 ` [PATCH 18/19] perf metric: Rename struct egroup to metric Jiri Olsa
@ 2020-07-26  9:20   ` kajoljain
  0 siblings, 0 replies; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:20 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: Ian Rogers, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Renaming struct egroup to metric, because it seems
> to make more sense. Plus renaming all the variables
> that hold egroup to appropriate names.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
>  tools/perf/util/metricgroup.c | 142 +++++++++++++++++-----------------
>  1 file changed, 71 insertions(+), 71 deletions(-)
> 
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 2a45ee94fd61..9d5fff36042d 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -115,7 +115,7 @@ struct metric_ref_node {
>  	struct list_head list;
>  };
>  
> -struct egroup {
> +struct metric {
>  	struct list_head nd;
>  	struct expr_parse_ctx pctx;
>  	const char *metric_name;
> @@ -262,7 +262,7 @@ static int metricgroup__setup_events(struct list_head *groups,
>  	struct metric_expr *expr;
>  	int i = 0;
>  	int ret = 0;
> -	struct egroup *eg;
> +	struct metric *m;
>  	struct evsel *evsel, *tmp;
>  	unsigned long *evlist_used;
>  
> @@ -270,23 +270,23 @@ static int metricgroup__setup_events(struct list_head *groups,
>  	if (!evlist_used)
>  		return -ENOMEM;
>  
> -	list_for_each_entry (eg, groups, nd) {
> +	list_for_each_entry (m, groups, nd) {
>  		struct evsel **metric_events;
>  		struct metric_ref *metric_refs = NULL;
>  
>  		metric_events = calloc(sizeof(void *),
> -				hashmap__size(&eg->pctx.ids) + 1);
> +				hashmap__size(&m->pctx.ids) + 1);
>  		if (!metric_events) {
>  			ret = -ENOMEM;
>  			break;
>  		}
> -		evsel = find_evsel_group(perf_evlist, &eg->pctx,
> +		evsel = find_evsel_group(perf_evlist, &m->pctx,
>  					 metric_no_merge,
> -					 eg->has_constraint, metric_events,
> +					 m->has_constraint, metric_events,
>  					 evlist_used);
>  		if (!evsel) {
>  			pr_debug("Cannot resolve %s: %s\n",
> -					eg->metric_name, eg->metric_expr);
> +					m->metric_name, m->metric_expr);
>  			free(metric_events);
>  			continue;
>  		}
> @@ -309,10 +309,10 @@ static int metricgroup__setup_events(struct list_head *groups,
>  		 * Collect and store collected nested expressions
>  		 * for metric processing.
>  		 */
> -		if (eg->metric_refs_cnt) {
> +		if (m->metric_refs_cnt) {
>  			struct metric_ref_node *ref;
>  
> -			metric_refs = zalloc(sizeof(struct metric_ref) * (eg->metric_refs_cnt + 1));
> +			metric_refs = zalloc(sizeof(struct metric_ref) * (m->metric_refs_cnt + 1));
>  			if (!metric_refs) {
>  				ret = -ENOMEM;
>  				free(metric_events);
> @@ -320,7 +320,7 @@ static int metricgroup__setup_events(struct list_head *groups,
>  			}
>  
>  			i = 0;
> -			list_for_each_entry(ref, &eg->metric_refs, list) {
> +			list_for_each_entry(ref, &m->metric_refs, list) {
>  				/*
>  				 * Intentionally passing just const char pointers,
>  				 * originally from 'struct pmu_event' object.
> @@ -334,11 +334,11 @@ static int metricgroup__setup_events(struct list_head *groups,
>  		};
>  
>  		expr->metric_refs = metric_refs;
> -		expr->metric_expr = eg->metric_expr;
> -		expr->metric_name = eg->metric_name;
> -		expr->metric_unit = eg->metric_unit;
> +		expr->metric_expr = m->metric_expr;
> +		expr->metric_name = m->metric_name;
> +		expr->metric_unit = m->metric_unit;
>  		expr->metric_events = metric_events;
> -		expr->runtime = eg->runtime;
> +		expr->runtime = m->runtime;
>  		list_add(&expr->nd, &me->head);
>  	}
>  
> @@ -643,41 +643,41 @@ static int __add_metric(struct list_head *group_list,
>  			struct pmu_event *pe,
>  			bool metric_no_group,
>  			int runtime,
> -			struct egroup **egp,
> +			struct metric **mp,
>  			struct expr_id *parent,
>  		        struct expr_ids *ids)
>  {
>  	struct metric_ref_node *ref;
> -	struct egroup *eg;
> +	struct metric *m;
>  
> -	if (*egp == NULL) {
> +	if (*mp == NULL) {
>  		/*
>  		 * We got in here for the parent group,
>  		 * allocate it and put it on the list.
>  		 */
> -		eg = zalloc(sizeof(*eg));
> -		if (!eg)
> +		m = zalloc(sizeof(*m));
> +		if (!m)
>  			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;
> +		expr__ctx_init(&m->pctx);
> +		m->metric_name = pe->metric_name;
> +		m->metric_expr = pe->metric_expr;
> +		m->metric_unit = pe->unit;
> +		m->runtime = runtime;
> +		m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
> +		INIT_LIST_HEAD(&m->metric_refs);
> +		m->metric_refs_cnt = 0;
> +		*mp = m;
>  
>  		parent = expr_ids__alloc(ids);
>  		if (!parent) {
> -			free(eg);
> +			free(m);
>  			return -EINVAL;
>  		}
>  
>  		parent->id = strdup(pe->metric_name);
>  		if (!parent->id) {
> -			free(eg);
> +			free(m);
>  			return -ENOMEM;
>  		}
>  	} else {
> @@ -686,7 +686,7 @@ static int __add_metric(struct list_head *group_list,
>  		 * recursive metricgroup__add_metric call, add
>  		 * it to the parent group.
>  		 */
> -		eg = *egp;
> +		m = *mp;
>  
>  		ref = malloc(sizeof(*ref));
>  		if (!ref)
> @@ -701,21 +701,21 @@ static int __add_metric(struct list_head *group_list,
>  		ref->metric_name = pe->metric_name;
>  		ref->metric_expr = pe->metric_expr;
>  
> -		list_add(&ref->list, &eg->metric_refs);
> -		eg->metric_refs_cnt++;
> +		list_add(&ref->list, &m->metric_refs);
> +		m->metric_refs_cnt++;
>  	}
>  
>  	/* Force all found IDs in metric to have us as parent ID. */
>  	WARN_ON_ONCE(!parent);
> -	eg->pctx.parent = parent;
> +	m->pctx.parent = parent;
>  
>  	/*
>  	 * 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);
> +	if (expr__find_other(pe->metric_expr, NULL, &m->pctx, runtime) < 0) {
> +		expr__ctx_clear(&m->pctx);
> +		free(m);
>  		return -EINVAL;
>  	}
>  
> @@ -723,23 +723,23 @@ static int __add_metric(struct list_head *group_list,
>  	 * We add new group only in the 'parent' call,
>  	 * so bail out for referenced metric case.
>  	 */
> -	if (eg->metric_refs_cnt)
> +	if (m->metric_refs_cnt)
>  		return 0;
>  
>  	if (list_empty(group_list))
> -		list_add(&eg->nd, group_list);
> +		list_add(&m->nd, group_list);
>  	else {
>  		struct list_head *pos;
>  
>  		/* Place the largest groups at the front. */
>  		list_for_each_prev(pos, group_list) {
> -			struct egroup *old = list_entry(pos, struct egroup, nd);
> +			struct metric *old = list_entry(pos, struct metric, nd);
>  
> -			if (hashmap__size(&eg->pctx.ids) <=
> +			if (hashmap__size(&m->pctx.ids) <=
>  			    hashmap__size(&old->pctx.ids))
>  				break;
>  		}
> -		list_add(&eg->nd, pos);
> +		list_add(&m->nd, pos);
>  	}
>  
>  	return 0;
> @@ -769,7 +769,7 @@ static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *
>  	return NULL;
>  }
>  
> -static int recursion_check(struct egroup *eg, const char *id, struct expr_id **parent,
> +static int recursion_check(struct metric *m, const char *id, struct expr_id **parent,
>  			   struct expr_ids *ids)
>  {
>  	struct expr_id_data *data;
> @@ -782,7 +782,7 @@ static int recursion_check(struct egroup *eg, const char *id, struct expr_id **p
>  	 * if we already processed 'id', if we did, it's recursion
>  	 * and we fail.
>  	 */
> -	ret = expr__get_id(&eg->pctx, id, &data);
> +	ret = expr__get_id(&m->pctx, id, &data);
>  	if (ret)
>  		return ret;
>  
> @@ -816,11 +816,11 @@ static int recursion_check(struct egroup *eg, const char *id, struct expr_id **p
>  static int add_metric(struct list_head *group_list,
>  		      struct pmu_event *pe,
>  		      bool metric_no_group,
> -		      struct egroup **egp,
> +		      struct metric **mp,
>  		      struct expr_id *parent,
>  		      struct expr_ids *ids);
>  
> -static int resolve_metric(struct egroup *eg,
> +static int resolve_metric(struct metric *m,
>  			  bool metric_no_group,
>  			  struct list_head *group_list,
>  			  struct pmu_events_map *map,
> @@ -837,7 +837,7 @@ static int resolve_metric(struct egroup *eg,
>  	 */
>  	do {
>  		all = true;
> -		hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
> +		hashmap__for_each_entry((&m->pctx.ids), cur, bkt) {
>  			struct expr_id *parent;
>  			struct pmu_event *pe;
>  
> @@ -845,16 +845,16 @@ static int resolve_metric(struct egroup *eg,
>  			if (!pe)
>  				continue;
>  
> -			ret = recursion_check(eg, cur->key, &parent, ids);
> +			ret = recursion_check(m, cur->key, &parent, ids);
>  			if (ret)
>  				return ret;
>  
>  			all = false;
>  			/* The metric key itself needs to go out.. */
> -			expr__del_id(&eg->pctx, cur->key);
> +			expr__del_id(&m->pctx, cur->key);
>  
>  			/* ... and it gets resolved to the parent context. */
> -			ret = add_metric(group_list, pe, metric_no_group, &eg, parent, ids);
> +			ret = add_metric(group_list, pe, metric_no_group, &m, parent, ids);
>  			if (ret)
>  				return ret;
>  
> @@ -872,7 +872,7 @@ static int resolve_metric(struct egroup *eg,
>  static int add_metric(struct list_head *group_list,
>  		      struct pmu_event *pe,
>  		      bool metric_no_group,
> -		      struct egroup **egp,
> +		      struct metric **m,
>  		      struct expr_id *parent,
>  		      struct expr_ids *ids)
>  {
> @@ -881,7 +881,7 @@ static int add_metric(struct list_head *group_list,
>  	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, egp, parent, ids);
> +		ret = __add_metric(group_list, pe, metric_no_group, 1, m, parent, ids);
>  	} else {
>  		int j, count;
>  
> @@ -893,7 +893,7 @@ static int add_metric(struct list_head *group_list,
>  		 */
>  
>  		for (j = 0; j < count && !ret; j++) {
> -			ret = __add_metric(group_list, pe, metric_no_group, j, egp, parent, ids);
> +			ret = __add_metric(group_list, pe, metric_no_group, j, m, parent, ids);
>  		}
>  	}
>  
> @@ -908,16 +908,16 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  {
>  	struct expr_ids ids = { 0 };
>  	struct pmu_event *pe;
> -	struct egroup *eg;
> +	struct metric *m;
>  	LIST_HEAD(list);
>  	int i, ret;
>  	bool has_match = false;
>  
>  	map_for_each_metric(pe, i, map, metric) {
>  		has_match = true;
> -		eg = NULL;
> +		m = NULL;
>  
> -		ret = add_metric(&list, pe, metric_no_group, &eg, NULL, &ids);
> +		ret = add_metric(&list, pe, metric_no_group, &m, NULL, &ids);
>  		if (ret)
>  			return ret;
>  
> @@ -925,7 +925,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  		 * Process any possible referenced metrics
>  		 * included in the expression.
>  		 */
> -		ret = resolve_metric(eg, metric_no_group,
> +		ret = resolve_metric(m, metric_no_group,
>  				     &list, map, &ids);
>  		if (ret)
>  			return ret;
> @@ -935,16 +935,16 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  	if (!has_match)
>  		return -EINVAL;
>  
> -	list_for_each_entry(eg, &list, nd) {
> +	list_for_each_entry(m, &list, nd) {
>  		if (events->len > 0)
>  			strbuf_addf(events, ",");
>  
> -		if (eg->has_constraint) {
> +		if (m->has_constraint) {
>  			metricgroup__add_metric_non_group(events,
> -							  &eg->pctx);
> +							  &m->pctx);
>  		} else {
>  			metricgroup__add_metric_weak_group(events,
> -							   &eg->pctx);
> +							   &m->pctx);
>  		}
>  	}
>  
> @@ -986,25 +986,25 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>  	return ret;
>  }
>  
> -static void egroup__free_refs(struct egroup *egroup)
> +static void metric__free_refs(struct metric *metric)
>  {
>  	struct metric_ref_node *ref, *tmp;
>  
> -	list_for_each_entry_safe(ref, tmp, &egroup->metric_refs, list) {
> +	list_for_each_entry_safe(ref, tmp, &metric->metric_refs, list) {
>  		list_del(&ref->list);
>  		free(ref);
>  	}
>  }
>  
> -static void metricgroup__free_egroups(struct list_head *group_list)
> +static void metricgroup__free_metrics(struct list_head *group_list)
>  {
> -	struct egroup *eg, *egtmp;
> +	struct metric *m, *tmp;
>  
> -	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);
> +	list_for_each_entry_safe (m, tmp, group_list, nd) {
> +		metric__free_refs(m);
> +		expr__ctx_clear(&m->pctx);
> +		list_del_init(&m->nd);
> +		free(m);
>  	}
>  }
>  
> @@ -1037,7 +1037,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>  	ret = metricgroup__setup_events(&group_list, metric_no_merge,
>  					perf_evlist, metric_events);
>  out:
> -	metricgroup__free_egroups(&group_list);
> +	metricgroup__free_metrics(&group_list);
>  	return ret;
>  }
>  
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 19/19] perf metric: Rename group_list to metric_list
  2020-07-19 18:13 ` [PATCH 19/19] perf metric: Rename group_list to metric_list Jiri Olsa
  2020-07-19 22:42   ` Ian Rogers
@ 2020-07-26  9:21   ` kajoljain
  2020-07-28 12:38     ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-26  9:21 UTC (permalink / raw)
  To: Jiri Olsa, Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian, Ian Rogers



On 7/19/20 11:43 PM, Jiri Olsa wrote:
> Following the previous change that rename egroup
> to metric, there's no reason to call the list
> 'group_list' anymore, renaming it to metric_list.
> 
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> ---
>  tools/perf/util/metricgroup.c | 42 +++++++++++++++++------------------
>  1 file changed, 21 insertions(+), 21 deletions(-)
> 
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 9d5fff36042d..6f179b9903a0 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -639,7 +639,7 @@ int __weak arch_get_runtimeparam(void)
>  	return 1;
>  }
>  
> -static int __add_metric(struct list_head *group_list,
> +static int __add_metric(struct list_head *metric_list,
>  			struct pmu_event *pe,
>  			bool metric_no_group,
>  			int runtime,
> @@ -726,13 +726,13 @@ static int __add_metric(struct list_head *group_list,
>  	if (m->metric_refs_cnt)
>  		return 0;
>  
> -	if (list_empty(group_list))
> -		list_add(&m->nd, group_list);
> +	if (list_empty(metric_list))
> +		list_add(&m->nd, metric_list);
>  	else {
>  		struct list_head *pos;
>  
>  		/* Place the largest groups at the front. */
> -		list_for_each_prev(pos, group_list) {
> +		list_for_each_prev(pos, metric_list) {
>  			struct metric *old = list_entry(pos, struct metric, nd);
>  
>  			if (hashmap__size(&m->pctx.ids) <=
> @@ -813,7 +813,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa
>  	return p->id ? 0 : -ENOMEM;
>  }
>  
> -static int add_metric(struct list_head *group_list,
> +static int add_metric(struct list_head *metric_list,
>  		      struct pmu_event *pe,
>  		      bool metric_no_group,
>  		      struct metric **mp,
> @@ -822,7 +822,7 @@ static int add_metric(struct list_head *group_list,
>  
>  static int resolve_metric(struct metric *m,
>  			  bool metric_no_group,
> -			  struct list_head *group_list,
> +			  struct list_head *metric_list,
>  			  struct pmu_events_map *map,
>  			  struct expr_ids *ids)
>  {
> @@ -854,7 +854,7 @@ static int resolve_metric(struct metric *m,
>  			expr__del_id(&m->pctx, cur->key);
>  
>  			/* ... and it gets resolved to the parent context. */
> -			ret = add_metric(group_list, pe, metric_no_group, &m, parent, ids);
> +			ret = add_metric(metric_list, pe, metric_no_group, &m, parent, ids);
>  			if (ret)
>  				return ret;
>  
> @@ -869,7 +869,7 @@ static int resolve_metric(struct metric *m,
>  	return 0;
>  }
>  
> -static int add_metric(struct list_head *group_list,
> +static int add_metric(struct list_head *metric_list,
>  		      struct pmu_event *pe,
>  		      bool metric_no_group,
>  		      struct metric **m,
> @@ -881,7 +881,7 @@ static int add_metric(struct list_head *group_list,
>  	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, m, parent, ids);
> +		ret = __add_metric(metric_list, pe, metric_no_group, 1, m, parent, ids);
>  	} else {
>  		int j, count;
>  
> @@ -889,11 +889,11 @@ static int add_metric(struct list_head *group_list,
>  
>  		/* This loop is added to create multiple
>  		 * events depend on count value and add
> -		 * those events to group_list.
> +		 * those events to metric_list.
>  		 */
>  
>  		for (j = 0; j < count && !ret; j++) {
> -			ret = __add_metric(group_list, pe, metric_no_group, j, m, parent, ids);
> +			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
>  		}
>  	}
>  
> @@ -902,7 +902,7 @@ static int add_metric(struct list_head *group_list,
>  
>  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  				   struct strbuf *events,
> -				   struct list_head *group_list,
> +				   struct list_head *metric_list,
>  				   struct pmu_events_map *map)
>  
>  {
> @@ -948,14 +948,14 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  		}
>  	}
>  
> -	list_splice(&list, group_list);
> +	list_splice(&list, metric_list);
>  	expr_ids__exit(&ids);
>  	return 0;
>  }
>  
>  static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>  					struct strbuf *events,
> -					struct list_head *group_list,
> +					struct list_head *metric_list,
>  					struct pmu_events_map *map)
>  {
>  	char *llist, *nlist, *p;
> @@ -971,7 +971,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>  
>  	while ((p = strsep(&llist, ",")) != NULL) {
>  		ret = metricgroup__add_metric(p, metric_no_group, events,
> -					      group_list, map);
> +					      metric_list, map);
>  		if (ret == -EINVAL) {
>  			fprintf(stderr, "Cannot find metric or group `%s'\n",
>  					p);
> @@ -996,11 +996,11 @@ static void metric__free_refs(struct metric *metric)
>  	}
>  }
>  
> -static void metricgroup__free_metrics(struct list_head *group_list)
> +static void metricgroup__free_metrics(struct list_head *metric_list)
>  {
>  	struct metric *m, *tmp;
>  
> -	list_for_each_entry_safe (m, tmp, group_list, nd) {
> +	list_for_each_entry_safe (m, tmp, metric_list, nd) {
>  		metric__free_refs(m);
>  		expr__ctx_clear(&m->pctx);
>  		list_del_init(&m->nd);
> @@ -1017,13 +1017,13 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>  {
>  	struct parse_events_error parse_error;
>  	struct strbuf extra_events;
> -	LIST_HEAD(group_list);
> +	LIST_HEAD(metric_list);
>  	int ret;
>  
>  	if (metric_events->nr_entries == 0)
>  		metricgroup__rblist_init(metric_events);
>  	ret = metricgroup__add_metric_list(str, metric_no_group,
> -					   &extra_events, &group_list, map);
> +					   &extra_events, &metric_list, map);
>  	if (ret)
>  		return ret;
>  	pr_debug("adding %s\n", extra_events.buf);
> @@ -1034,10 +1034,10 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
>  		goto out;
>  	}
>  	strbuf_release(&extra_events);
> -	ret = metricgroup__setup_events(&group_list, metric_no_merge,
> +	ret = metricgroup__setup_events(&metric_list, metric_no_merge,
>  					perf_evlist, metric_events);
>  out:
> -	metricgroup__free_metrics(&group_list);
> +	metricgroup__free_metrics(&metric_list);
>  	return ret;
>  }
>  
> 

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function
  2020-07-19 21:41   ` Ian Rogers
@ 2020-07-28 12:26     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:26 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, Alexander Shishkin, Peter Zijlstra, Michael Petlan,
	Andi Kleen, Kajol Jain, John Garry, Paul A. Clarke,
	Stephane Eranian

Em Sun, Jul 19, 2020 at 02:41:46PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Arnaldo found that we don't release value data in case the
> > hashmap__set fails. Releasing it in case of an error.
> >
> > Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 02/19] perf metric: Add expr__add_id function
  2020-07-26  9:16   ` kajoljain
@ 2020-07-28 12:27     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:27 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:46:47PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Adding expr__add_id function to data for ID
> > with zero value, which is used when scanning
> > the expression for IDs.
> > 
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  tools/perf/util/expr.c | 31 +++++++++++++++++++++++++------
> >  tools/perf/util/expr.h |  1 +
> >  tools/perf/util/expr.y |  2 +-
> >  3 files changed, 27 insertions(+), 7 deletions(-)
> > 
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index 578a173d4873..9228f60e2a20 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -32,6 +32,26 @@ static bool key_equal(const void *key1, const void *key2,
> >  	return !strcmp((const char *)key1, (const char *)key2);
> >  }
> >  
> > +/* Caller must make sure id is allocated */
> > +int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
> > +{
> > +	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
> > +	char *old_key = NULL;
> > +	int ret;
> > +
> > +	data_ptr = malloc(sizeof(*data_ptr));
> > +	if (!data_ptr)
> > +		return -ENOMEM;
> > +
> > +	ret = hashmap__set(&ctx->ids, id, data_ptr,
> > +			   (const void **)&old_key, (void **)&old_data);
> > +	if (ret)
> > +		free(data_ptr);
> > +	free(old_key);
> > +	free(old_data);
> > +	return ret;
> > +}
> > +
> >  /* Caller must make sure id is allocated */
> >  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
> >  {
> > @@ -39,12 +59,11 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
> >  	char *old_key = NULL;
> >  	int ret;
> >  
> > -	if (val != 0.0) {
> > -		data_ptr = malloc(sizeof(*data_ptr));
> > -		if (!data_ptr)
> > -			return -ENOMEM;
> > -		data_ptr->val = val;
> > -	}
> > +	data_ptr = malloc(sizeof(*data_ptr));
> > +	if (!data_ptr)
> > +		return -ENOMEM;
> > +	data_ptr->val = val;
> > +
> >  	ret = hashmap__set(&ctx->ids, id, data_ptr,
> >  			   (const void **)&old_key, (void **)&old_data);
> >  	if (ret)
> > diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> > index 21fe5bd85718..ac32cda42006 100644
> > --- a/tools/perf/util/expr.h
> > +++ b/tools/perf/util/expr.h
> > @@ -26,6 +26,7 @@ struct expr_scanner_ctx {
> >  
> >  void expr__ctx_init(struct expr_parse_ctx *ctx);
> >  void expr__ctx_clear(struct expr_parse_ctx *ctx);
> > +int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
> >  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> >  int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr);
> >  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> > diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
> > index b2b3420ea6ec..8befe4a46f87 100644
> > --- a/tools/perf/util/expr.y
> > +++ b/tools/perf/util/expr.y
> > @@ -69,7 +69,7 @@ all_other: all_other other
> >  
> >  other: ID
> >  {
> > -	expr__add_id_val(ctx, $1, 0.0);
> > +	expr__add_id(ctx, $1);
> >  }
> >  |
> >  MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ','
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data
  2020-07-26  9:17   ` kajoljain
@ 2020-07-28 12:28     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:28 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:47:00PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Changing expr__get_id to use and return struct expr_id_data
> > pointer as value for the ID. This way we can access data other
> > than value for given ID in following changes.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> 
> >  tools/perf/util/expr.c | 10 +++-------
> >  tools/perf/util/expr.h |  3 ++-
> >  tools/perf/util/expr.y | 14 +++++++++-----
> >  3 files changed, 14 insertions(+), 13 deletions(-)
> > 
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index 9228f60e2a20..4e5a6533dfce 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -73,14 +73,10 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
> >  	return ret;
> >  }
> >  
> > -int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr)
> > +int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> > +		 struct expr_id_data **data)
> >  {
> > -	struct expr_id_data *data;
> > -
> > -	if (!hashmap__find(&ctx->ids, id, (void **)&data))
> > -		return -1;
> > -	*val_ptr = (data == NULL) ?  0.0 : data->val;
> > -	return 0;
> > +	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
> >  }
> >  
> >  void expr__ctx_init(struct expr_parse_ctx *ctx)
> > diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> > index ac32cda42006..f38292fdab19 100644
> > --- a/tools/perf/util/expr.h
> > +++ b/tools/perf/util/expr.h
> > @@ -28,7 +28,8 @@ void expr__ctx_init(struct expr_parse_ctx *ctx);
> >  void expr__ctx_clear(struct expr_parse_ctx *ctx);
> >  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
> >  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> > -int expr__get_id(struct expr_parse_ctx *ctx, const char *id, double *val_ptr);
> > +int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> > +		 struct expr_id_data **data);
> >  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> >  		const char *expr, int runtime);
> >  int expr__find_other(const char *expr, const char *one,
> > diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
> > index 8befe4a46f87..0d4f5d324be7 100644
> > --- a/tools/perf/util/expr.y
> > +++ b/tools/perf/util/expr.y
> > @@ -85,12 +85,16 @@ if_expr:
> >  	;
> >  
> >  expr:	  NUMBER
> > -	| ID			{ if (expr__get_id(ctx, $1, &$$)) {
> > -					pr_debug("%s not found\n", $1);
> > +	| ID			{
> > +					struct expr_id_data *data;
> > +
> > +					if (expr__get_id(ctx, $1, &data) || !data) {
> > +						pr_debug("%s not found\n", $1);
> > +						free($1);
> > +						YYABORT;
> > +					}
> > +					$$ = data->val;
> >  					free($1);
> > -					YYABORT;
> > -				  }
> > -				  free($1);
> >  				}
> >  	| expr '|' expr		{ $$ = (long)$1 | (long)$3; }
> >  	| expr '&' expr		{ $$ = (long)$1 & (long)$3; }
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 04/19] perf metric: Add expr__del_id function
  2020-07-26  9:17   ` kajoljain
@ 2020-07-28 12:28     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:28 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:47:11PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Adding expr__del_id function to remove ID from hashmap.
> > It will save us few lines in following changes.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> 
> > ---
> >  tools/perf/util/expr.c | 21 +++++++++++++--------
> >  tools/perf/util/expr.h |  1 +
> >  2 files changed, 14 insertions(+), 8 deletions(-)
> > 
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index 4e5a6533dfce..f726211f49d4 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -79,6 +79,17 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> >  	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
> >  }
> >  
> > +void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
> > +{
> > +	struct expr_id_data *old_val = NULL;
> > +	char *old_key = NULL;
> > +
> > +	hashmap__delete(&ctx->ids, id,
> > +			(const void **)&old_key, (void **)&old_val);
> > +	free(old_key);
> > +	free(old_val);
> > +}
> > +
> >  void expr__ctx_init(struct expr_parse_ctx *ctx)
> >  {
> >  	hashmap__init(&ctx->ids, key_hash, key_equal, NULL);
> > @@ -136,16 +147,10 @@ int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> >  int expr__find_other(const char *expr, const char *one,
> >  		     struct expr_parse_ctx *ctx, int runtime)
> >  {
> > -	struct expr_id_data *old_val = NULL;
> > -	char *old_key = NULL;
> >  	int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime);
> >  
> > -	if (one) {
> > -		hashmap__delete(&ctx->ids, one,
> > -				(const void **)&old_key, (void **)&old_val);
> > -		free(old_key);
> > -		free(old_val);
> > -	}
> > +	if (one)
> > +		expr__del_id(ctx, one);
> >  
> >  	return ret;
> >  }
> > diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> > index f38292fdab19..2462abd0ac65 100644
> > --- a/tools/perf/util/expr.h
> > +++ b/tools/perf/util/expr.h
> > @@ -26,6 +26,7 @@ struct expr_scanner_ctx {
> >  
> >  void expr__ctx_init(struct expr_parse_ctx *ctx);
> >  void expr__ctx_clear(struct expr_parse_ctx *ctx);
> > +void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
> >  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
> >  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> >  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 05/19] perf metric: Add macros for iterating map events
  2020-07-19 21:46   ` Ian Rogers
@ 2020-07-28 12:29     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:29 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 19, 2020 at 02:46:12PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Adding following macros to iterate events and metric:
> >   map_for_each_event(__pe, __idx, __map)
> >     - iterates over all pmu_events_map events
> >   map_for_each_metric(__pe, __idx, __map, __metric)
> >     - iterates over all metrics that match __metric argument
> >
> > and use it in metricgroup__add_metric function. Macros
> > will be be used from other places in following changes.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo
 
> Thanks!
> Ian
> 
> > ---
> >  tools/perf/util/metricgroup.c | 77 ++++++++++++++++++-----------------
> >  1 file changed, 40 insertions(+), 37 deletions(-)
> >
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index df0356ec120d..b37008fc253c 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -614,6 +614,17 @@ static int __metricgroup__add_metric(struct list_head *group_list,
> >         return 0;
> >  }
> >
> > +#define map_for_each_event(__pe, __idx, __map)                         \
> > +       for (__idx = 0, __pe = &__map->table[__idx];                    \
> > +            __pe->name || __pe->metric_group || __pe->metric_name;     \
> > +            __pe = &__map->table[++__idx])
> > +
> > +#define map_for_each_metric(__pe, __idx, __map, __metric)              \
> > +       map_for_each_event(__pe, __idx, __map)                          \
> > +               if (__pe->metric_expr &&                                \
> > +                   (match_metric(__pe->metric_group, __metric) ||      \
> > +                    match_metric(__pe->metric_name, __metric)))
> > +
> >  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                                    struct strbuf *events,
> >                                    struct list_head *group_list,
> > @@ -624,49 +635,41 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >         int i, ret;
> >         bool has_match = false;
> >
> > -       for (i = 0; ; i++) {
> > -               pe = &map->table[i];
> > -
> > -               if (!pe->name && !pe->metric_group && !pe->metric_name) {
> > -                       /* End of pmu events. */
> > -                       if (!has_match)
> > -                               return -EINVAL;
> > -                       break;
> > -               }
> > -               if (!pe->metric_expr)
> > -                       continue;
> > -               if (match_metric(pe->metric_group, metric) ||
> > -                   match_metric(pe->metric_name, metric)) {
> > -                       has_match = true;
> > -                       pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> > -
> > -                       if (!strstr(pe->metric_expr, "?")) {
> > -                               ret = __metricgroup__add_metric(group_list,
> > -                                                               pe,
> > -                                                               metric_no_group,
> > -                                                               1);
> > -                               if (ret)
> > -                                       return ret;
> > -                       } else {
> > -                               int j, count;
> > +       map_for_each_metric(pe, i, map, metric) {
> > +               pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> > +               has_match = true;
> > +
> > +               if (!strstr(pe->metric_expr, "?")) {
> > +                       ret = __metricgroup__add_metric(group_list,
> > +                                                       pe,
> > +                                                       metric_no_group,
> > +                                                       1);
> > +                       if (ret)
> > +                               return ret;
> > +               } else {
> > +                       int j, count;
> >
> > -                               count = arch_get_runtimeparam();
> > +                       count = arch_get_runtimeparam();
> >
> > -                               /* This loop is added to create multiple
> > -                                * events depend on count value and add
> > -                                * those events to group_list.
> > -                                */
> > +                       /* This loop is added to create multiple
> > +                        * events depend on count value and add
> > +                        * those events to group_list.
> > +                        */
> >
> > -                               for (j = 0; j < count; j++) {
> > -                                       ret = __metricgroup__add_metric(
> > -                                               group_list, pe,
> > -                                               metric_no_group, j);
> > -                                       if (ret)
> > -                                               return ret;
> > -                               }
> > +                       for (j = 0; j < count; j++) {
> > +                               ret = __metricgroup__add_metric(
> > +                                       group_list, pe,
> > +                                       metric_no_group, j);
> > +                               if (ret)
> > +                                       return ret;
> >                         }
> >                 }
> >         }
> > +
> > +       /* End of pmu events. */
> > +       if (!has_match)
> > +               return -EINVAL;
> > +
> >         list_for_each_entry(eg, group_list, nd) {
> >                 if (events->len > 0)
> >                         strbuf_addf(events, ",");
> > --
> > 2.25.4
> >

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 06/19] perf metric: Add add_metric function
  2020-07-26  9:17   ` kajoljain
@ 2020-07-28 12:30     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:30 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:47:53PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Decouple metric adding logging into add_metric function,
> > so it can be used from other places in following changes.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> >  tools/perf/util/metricgroup.c | 62 ++++++++++++++++++++---------------
> >  1 file changed, 36 insertions(+), 26 deletions(-)
> > 
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index b37008fc253c..4096be7a7a9e 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -625,6 +625,39 @@ static int __metricgroup__add_metric(struct list_head *group_list,
> >  		    (match_metric(__pe->metric_group, __metric) ||	\
> >  		     match_metric(__pe->metric_name, __metric)))
> >  
> > +static int add_metric(struct list_head *group_list,
> > +		      struct pmu_event *pe,
> > +		      bool metric_no_group)
> > +{
> > +	int ret = 0;
> > +
> > +	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> > +
> > +	if (!strstr(pe->metric_expr, "?")) {
> > +		ret = __metricgroup__add_metric(group_list,
> > +						pe,
> > +						metric_no_group,
> > +						1);
> > +	} else {
> > +		int j, count;
> > +
> > +		count = arch_get_runtimeparam();
> > +
> > +		/* This loop is added to create multiple
> > +		 * events depend on count value and add
> > +		 * those events to group_list.
> > +		 */
> > +
> > +		for (j = 0; j < count && !ret; j++) {
> > +			ret = __metricgroup__add_metric(
> > +				group_list, pe,
> > +				metric_no_group, j);
> > +		}
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> >  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >  				   struct strbuf *events,
> >  				   struct list_head *group_list,
> > @@ -636,34 +669,11 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >  	bool has_match = false;
> >  
> >  	map_for_each_metric(pe, i, map, metric) {
> > -		pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> >  		has_match = true;
> >  
> > -		if (!strstr(pe->metric_expr, "?")) {
> > -			ret = __metricgroup__add_metric(group_list,
> > -							pe,
> > -							metric_no_group,
> > -							1);
> > -			if (ret)
> > -				return ret;
> > -		} else {
> > -			int j, count;
> > -
> > -			count = arch_get_runtimeparam();
> > -
> > -			/* This loop is added to create multiple
> > -			 * events depend on count value and add
> > -			 * those events to group_list.
> > -			 */
> > -
> > -			for (j = 0; j < count; j++) {
> > -				ret = __metricgroup__add_metric(
> > -					group_list, pe,
> > -					metric_no_group, j);
> > -				if (ret)
> > -					return ret;
> > -			}
> > -		}
> > +		ret = add_metric(group_list, pe, metric_no_group);
> > +		if (ret)
> > +			return ret;
> >  	}
> >  
> >  	/* End of pmu events. */
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric
  2020-07-26  9:18   ` kajoljain
@ 2020-07-28 12:30     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:30 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:48:05PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Renaming __metricgroup__add_metric to __add_metric
> > to fit in the current function names.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>
 

Thanks, applied.

- Arnaldo
> Thanks,
> Kajol Jain
> > ---
> >  tools/perf/util/metricgroup.c | 17 ++++++-----------
> >  1 file changed, 6 insertions(+), 11 deletions(-)
> > 
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 4096be7a7a9e..ccd80538a6ae 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -571,10 +571,10 @@ int __weak arch_get_runtimeparam(void)
> >  	return 1;
> >  }
> >  
> > -static int __metricgroup__add_metric(struct list_head *group_list,
> > -				     struct pmu_event *pe,
> > -				     bool metric_no_group,
> > -				     int runtime)
> > +static int __add_metric(struct list_head *group_list,
> > +			struct pmu_event *pe,
> > +			bool metric_no_group,
> > +			int runtime)
> >  {
> >  	struct egroup *eg;
> >  
> > @@ -634,10 +634,7 @@ static int add_metric(struct list_head *group_list,
> >  	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> >  
> >  	if (!strstr(pe->metric_expr, "?")) {
> > -		ret = __metricgroup__add_metric(group_list,
> > -						pe,
> > -						metric_no_group,
> > -						1);
> > +		ret = __add_metric(group_list, pe, metric_no_group, 1);
> >  	} else {
> >  		int j, count;
> >  
> > @@ -649,9 +646,7 @@ static int add_metric(struct list_head *group_list,
> >  		 */
> >  
> >  		for (j = 0; j < count && !ret; j++) {
> > -			ret = __metricgroup__add_metric(
> > -				group_list, pe,
> > -				metric_no_group, j);
> > +			ret = __add_metric(group_list, pe, metric_no_group, j);
> >  		}
> >  	}
> >  
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node
  2020-07-19 22:18   ` Ian Rogers
  2020-07-26  9:18     ` kajoljain
@ 2020-07-28 12:31     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:31 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 19, 2020 at 03:18:58PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:13 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > 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>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Ian
> 
> > ---
> >  tools/perf/util/metricgroup.c | 170 +++++++++++++++++++++++++++++++---
> >  1 file changed, 156 insertions(+), 14 deletions(-)
> >
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index ccd80538a6ae..d1b2c1aa436f 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -102,12 +102,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;
> >  };
> > @@ -574,27 +587,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;
> > +
> > +               /*
> > +                * 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;
> >
> > -       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);
> > +               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 {
> > @@ -625,16 +683,78 @@ 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,
> > +                     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 add_metric(struct list_head *group_list,
> >                       struct pmu_event *pe,
> > -                     bool metric_no_group)
> > +                     bool metric_no_group,
> > +                     struct egroup **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;
> >
> > @@ -646,7 +766,7 @@ static int add_metric(struct list_head *group_list,
> >                  */
> >
> >                 for (j = 0; j < count && !ret; j++) {
> > -                       ret = __add_metric(group_list, pe, metric_no_group, j);
> > +                       ret = __add_metric(group_list, pe, metric_no_group, j, egp);
> >                 }
> >         }
> >
> > @@ -657,6 +777,7 @@ 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)
> > +
> >  {
> >         struct pmu_event *pe;
> >         struct egroup *eg;
> > @@ -665,8 +786,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);
> > +               ret = add_metric(group_list, pe, metric_no_group, &eg);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               /*
> > +                * Process any possible referenced metrics
> > +                * included in the expression.
> > +                */
> > +               ret = resolve_metric(eg, metric_no_group,
> > +                                    group_list, map);
> >                 if (ret)
> >                         return ret;
> >         }
> > @@ -723,11 +854,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.25.4
> >

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr
  2020-07-26  9:18   ` kajoljain
@ 2020-07-28 12:32     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:32 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:48:35PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Add referenced metrics into struct metric_expr object,
> > so they are accessible when computing the metric.
> > 
> > Storing just name and expression itself, so the metric
> > can be resolved and computed.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 10/19] perf metric: Add referenced metrics to hash data
  2020-07-19 22:32   ` Ian Rogers
  2020-07-26  9:18     ` kajoljain
@ 2020-07-28 12:32     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:32 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 19, 2020 at 03:32:26PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Adding referenced metrics to the parsing context so they
> > can be resolved during the metric processing.
> >
> > Adding expr__add_ref function to store referenced metrics
> > into parse context.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Ian
> 
> > ---
> >  tools/perf/util/expr.c        | 54 +++++++++++++++++++++++++++++++++++
> >  tools/perf/util/expr.h        | 13 ++++++++-
> >  tools/perf/util/stat-shadow.c | 20 +++++++++----
> >  3 files changed, 80 insertions(+), 7 deletions(-)
> >
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index f726211f49d4..d3997c2b4a90 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -4,10 +4,14 @@
> >  #include <errno.h>
> >  #include <stdlib.h>
> >  #include <string.h>
> > +#include "metricgroup.h"
> > +#include "debug.h"
> >  #include "expr.h"
> >  #include "expr-bison.h"
> >  #include "expr-flex.h"
> >  #include <linux/kernel.h>
> > +#include <linux/zalloc.h>
> > +#include <ctype.h>
> >
> >  #ifdef PARSER_DEBUG
> >  extern int expr_debug;
> > @@ -63,6 +67,7 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
> >         if (!data_ptr)
> >                 return -ENOMEM;
> >         data_ptr->val = val;
> > +       data_ptr->is_ref = false;
> >
> >         ret = hashmap__set(&ctx->ids, id, data_ptr,
> >                            (const void **)&old_key, (void **)&old_data);
> > @@ -73,6 +78,55 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
> >         return ret;
> >  }
> >
> > +int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
> > +{
> > +       struct expr_id_data *data_ptr = NULL, *old_data = NULL;
> > +       char *old_key = NULL;
> > +       char *name, *p;
> > +       int ret;
> > +
> > +       data_ptr = zalloc(sizeof(*data_ptr));
> > +       if (!data_ptr)
> > +               return -ENOMEM;
> > +
> > +       name = strdup(ref->metric_name);
> > +       if (!name) {
> > +               free(data_ptr);
> > +               return -ENOMEM;
> > +       }
> > +
> > +       /*
> > +        * The jevents tool converts all metric expressions
> > +        * to lowercase, including metric references, hence
> > +        * we need to add lowercase name for metric, so it's
> > +        * properly found.
> > +        */
> > +       for (p = name; *p; p++)
> > +               *p = tolower(*p);
> > +
> > +       /*
> > +        * Intentionally passing just const char pointers,
> > +        * originally from 'struct pmu_event' object.
> > +        * We don't need to change them, so there's no
> > +        * need to create our own copy.
> > +        */
> > +       data_ptr->ref.metric_name = ref->metric_name;
> > +       data_ptr->ref.metric_expr = ref->metric_expr;
> > +       data_ptr->is_ref = true;
> > +
> > +       ret = hashmap__set(&ctx->ids, name, data_ptr,
> > +                          (const void **)&old_key, (void **)&old_data);
> > +       if (ret)
> > +               free(data_ptr);
> > +
> > +       pr_debug2("adding ref metric %s: %s\n",
> > +                 ref->metric_name, ref->metric_expr);
> > +
> > +       free(old_key);
> > +       free(old_data);
> > +       return ret;
> > +}
> > +
> >  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> >                  struct expr_id_data **data)
> >  {
> > diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> > index 2462abd0ac65..81d04ff7f857 100644
> > --- a/tools/perf/util/expr.h
> > +++ b/tools/perf/util/expr.h
> > @@ -11,12 +11,22 @@
> >  #include "util/hashmap.h"
> >  //#endif
> >
> > +struct metric_ref;
> > +
> >  struct expr_parse_ctx {
> >         struct hashmap ids;
> >  };
> >
> >  struct expr_id_data {
> > -       double  val;
> > +       union {
> > +               double val;
> > +               struct {
> > +                       const char *metric_name;
> > +                       const char *metric_expr;
> > +               } ref;
> > +       };
> > +
> > +       bool is_ref;
> >  };
> >
> >  struct expr_scanner_ctx {
> > @@ -29,6 +39,7 @@ void expr__ctx_clear(struct expr_parse_ctx *ctx);
> >  void expr__del_id(struct expr_parse_ctx *ctx, const char *id);
> >  int expr__add_id(struct expr_parse_ctx *ctx, const char *id);
> >  int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> > +int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
> >  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> >                  struct expr_id_data **data);
> >  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> > diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
> > index fc9ac4b4218e..e1ba6c1b916a 100644
> > --- a/tools/perf/util/stat-shadow.c
> > +++ b/tools/perf/util/stat-shadow.c
> > @@ -731,13 +731,14 @@ static void print_smi_cost(struct perf_stat_config *config,
> >  }
> >
> >  static int prepare_metric(struct evsel **metric_events,
> > +                         struct metric_ref *metric_refs,
> >                           struct expr_parse_ctx *pctx,
> >                           int cpu,
> >                           struct runtime_stat *st)
> >  {
> >         double scale;
> >         char *n, *pn;
> > -       int i;
> > +       int i, j, ret;
> >
> >         expr__ctx_init(pctx);
> >         for (i = 0; metric_events[i]; i++) {
> > @@ -778,12 +779,19 @@ static int prepare_metric(struct evsel **metric_events,
> >                         expr__add_id_val(pctx, n, avg_stats(stats)*scale);
> >         }
> >
> > +       for (j = 0; metric_refs && metric_refs[j].metric_name; j++) {
> > +               ret = expr__add_ref(pctx, &metric_refs[j]);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> >         return i;
> >  }
> >
> >  static void generic_metric(struct perf_stat_config *config,
> >                            const char *metric_expr,
> >                            struct evsel **metric_events,
> > +                          struct metric_ref *metric_refs,
> >                            char *name,
> >                            const char *metric_name,
> >                            const char *metric_unit,
> > @@ -798,7 +806,7 @@ static void generic_metric(struct perf_stat_config *config,
> >         int i;
> >         void *ctxp = out->ctx;
> >
> > -       i = prepare_metric(metric_events, &pctx, cpu, st);
> > +       i = prepare_metric(metric_events, metric_refs, &pctx, cpu, st);
> >         if (i < 0)
> >                 return;
> >
> > @@ -847,7 +855,7 @@ double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_sta
> >         struct expr_parse_ctx pctx;
> >         double ratio;
> >
> > -       if (prepare_metric(mexp->metric_events, &pctx, cpu, st) < 0)
> > +       if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0)
> >                 return 0.;
> >
> >         if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1))
> > @@ -1064,8 +1072,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
> >                 else
> >                         print_metric(config, ctxp, NULL, NULL, name, 0);
> >         } else if (evsel->metric_expr) {
> > -               generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name,
> > -                               evsel->metric_name, NULL, 1, cpu, out, st);
> > +               generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
> > +                               evsel->name, evsel->metric_name, NULL, 1, cpu, out, st);
> >         } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) {
> >                 char unit = 'M';
> >                 char unit_buf[10];
> > @@ -1093,7 +1101,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
> >                         if (num++ > 0)
> >                                 out->new_line(config, ctxp);
> >                         generic_metric(config, mexp->metric_expr, mexp->metric_events,
> > -                                       evsel->name, mexp->metric_name,
> > +                                       mexp->metric_refs, evsel->name, mexp->metric_name,
> >                                         mexp->metric_unit, mexp->runtime, cpu, out, st);
> >                 }
> >         }
> > --
> > 2.25.4
> >

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 11/19] perf metric: Compute referenced metrics
  2020-07-26  9:19   ` kajoljain
@ 2020-07-28 12:33     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:33 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:49:04PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Adding computation (expr__parse call) of referenced metric at
> > the point when it needs to be resolved during the parent metric
> > computation.
> > 
> > Once the inner metric is computed, the result is stored and
> > used if there's another usage of that metric.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> > ---
> >  tools/perf/util/expr.c | 31 +++++++++++++++++++++++++++++++
> >  tools/perf/util/expr.h |  3 +++
> >  tools/perf/util/expr.y |  4 ++--
> >  3 files changed, 36 insertions(+), 2 deletions(-)
> > 
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index d3997c2b4a90..a346ca590513 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -112,6 +112,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
> >  	 */
> >  	data_ptr->ref.metric_name = ref->metric_name;
> >  	data_ptr->ref.metric_expr = ref->metric_expr;
> > +	data_ptr->ref.counted = false;
> >  	data_ptr->is_ref = true;
> >  
> >  	ret = hashmap__set(&ctx->ids, name, data_ptr,
> > @@ -133,6 +134,34 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> >  	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
> >  }
> >  
> > +int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
> > +		     struct expr_id_data **datap)
> > +{
> > +	struct expr_id_data *data;
> > +
> > +	if (expr__get_id(ctx, id, datap) || !*datap) {
> > +		pr_debug("%s not found\n", id);
> > +		return -1;
> > +	}
> > +
> > +	data = *datap;
> > +
> > +	pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n",
> > +		  data->is_ref, data->ref.counted, data->val, id);
> > +
> > +	if (data->is_ref && !data->ref.counted) {
> > +		data->ref.counted = true;
> > +		pr_debug("processing metric: %s ENTRY\n", id);
> > +		if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) {
> > +			pr_debug("%s failed to count\n", id);
> > +			return -1;
> > +		}
> > +		pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
> >  {
> >  	struct expr_id_data *old_val = NULL;
> > @@ -173,6 +202,8 @@ __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
> >  	void *scanner;
> >  	int ret;
> >  
> > +	pr_debug2("parsing metric: %s\n", expr);
> > +
> >  	ret = expr_lex_init_extra(&scanner_ctx, &scanner);
> >  	if (ret)
> >  		return ret;
> > diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> > index 81d04ff7f857..9ed208d93418 100644
> > --- a/tools/perf/util/expr.h
> > +++ b/tools/perf/util/expr.h
> > @@ -23,6 +23,7 @@ struct expr_id_data {
> >  		struct {
> >  			const char *metric_name;
> >  			const char *metric_expr;
> > +			bool counted;
> >  		} ref;
> >  	};
> >  
> > @@ -42,6 +43,8 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
> >  int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
> >  int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
> >  		 struct expr_id_data **data);
> > +int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
> > +		     struct expr_id_data **datap);
> >  int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
> >  		const char *expr, int runtime);
> >  int expr__find_other(const char *expr, const char *one,
> > diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
> > index 0d4f5d324be7..d34b370391c6 100644
> > --- a/tools/perf/util/expr.y
> > +++ b/tools/perf/util/expr.y
> > @@ -88,11 +88,11 @@ expr:	  NUMBER
> >  	| ID			{
> >  					struct expr_id_data *data;
> >  
> > -					if (expr__get_id(ctx, $1, &data) || !data) {
> > -						pr_debug("%s not found\n", $1);
> > +					if (expr__resolve_id(ctx, $1, &data)) {
> >  						free($1);
> >  						YYABORT;
> >  					}
> > +
> >  					$$ = data->val;
> >  					free($1);
> >  				}
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 12/19] perf metric: Add events for the current list
  2020-07-19 22:34   ` Ian Rogers
  2020-07-26  9:19     ` kajoljain
@ 2020-07-28 12:33     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:33 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 19, 2020 at 03:34:48PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > There's no need to iterate the whole list of groups,
> > when adding new events. The currently created groups
> > are the ones we want to add.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Ian
> 
> > ---
> >  tools/perf/util/metricgroup.c | 9 ++++++---
> >  1 file changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index bb5757b9419d..332414d93f7a 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -813,6 +813,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >  {
> >         struct pmu_event *pe;
> >         struct egroup *eg;
> > +       LIST_HEAD(list);
> >         int i, ret;
> >         bool has_match = false;
> >
> > @@ -820,7 +821,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                 has_match = true;
> >                 eg = NULL;
> >
> > -               ret = add_metric(group_list, pe, metric_no_group, &eg);
> > +               ret = add_metric(&list, pe, metric_no_group, &eg);
> >                 if (ret)
> >                         return ret;
> >
> > @@ -829,7 +830,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                  * included in the expression.
> >                  */
> >                 ret = resolve_metric(eg, metric_no_group,
> > -                                    group_list, map);
> > +                                    &list, map);
> >                 if (ret)
> >                         return ret;
> >         }
> > @@ -838,7 +839,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >         if (!has_match)
> >                 return -EINVAL;
> >
> > -       list_for_each_entry(eg, group_list, nd) {
> > +       list_for_each_entry(eg, &list, nd) {
> >                 if (events->len > 0)
> >                         strbuf_addf(events, ",");
> >
> > @@ -850,6 +851,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                                                            &eg->pctx);
> >                 }
> >         }
> > +
> > +       list_splice(&list, group_list);
> >         return 0;
> >  }
> >
> > --
> > 2.25.4
> >

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test
  2020-07-26  9:19   ` kajoljain
@ 2020-07-28 12:34     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:34 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:49:35PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Adding test that compute metric with other metrics in it.
> > 
> >   cache_miss_cycles = metric:dcache_miss_cpi + metric:icache_miss_cycles
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> > ---
> >  tools/perf/tests/parse-metric.c | 33 +++++++++++++++++++++++++++++++++
> >  1 file changed, 33 insertions(+)
> > 
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 8c48251425e1..28f33893338b 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -11,6 +11,8 @@
> >  #include "debug.h"
> >  #include "expr.h"
> >  #include "stat.h"
> > +#include <perf/cpumap.h>
> > +#include <perf/evlist.h>
> >  
> >  static struct pmu_event pme_test[] = {
> >  {
> > @@ -22,6 +24,18 @@ static struct pmu_event pme_test[] = {
> >  			  "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
> >  	.metric_name	= "Frontend_Bound_SMT",
> >  },
> > +{
> > +	.metric_expr	= "l1d\\-loads\\-misses / inst_retired.any",
> > +	.metric_name	= "dcache_miss_cpi",
> > +},
> > +{
> > +	.metric_expr	= "l1i\\-loads\\-misses / inst_retired.any",
> > +	.metric_name	= "icache_miss_cycles",
> > +},
> > +{
> > +	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
> > +	.metric_name	= "cache_miss_cycles",
> > +},
> >  };
> >  
> >  static struct pmu_events_map map = {
> > @@ -162,9 +176,28 @@ static int test_frontend(void)
> >  	return 0;
> >  }
> >  
> > +static int test_cache_miss_cycles(void)
> > +{
> > +	double ratio;
> > +	struct value vals[] = {
> > +		{ .event = "l1d-loads-misses",  .val = 300 },
> > +		{ .event = "l1i-loads-misses",  .val = 200 },
> > +		{ .event = "inst_retired.any",  .val = 400 },
> > +		{ 0 },
> > +	};
> > +
> > +	TEST_ASSERT_VAL("failed to compute metric",
> > +			compute_metric("cache_miss_cycles", vals, &ratio) == 0);
> > +
> > +	TEST_ASSERT_VAL("cache_miss_cycles failed, wrong ratio",
> > +			ratio == 1.25);
> > +	return 0;
> > +}
> > +
> >  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
> >  {
> >  	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
> >  	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
> > +	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> >  	return 0;
> >  }
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 14/19] perf metric: Add DCache_L2 to metric parse test
  2020-07-26  9:19   ` kajoljain
@ 2020-07-28 12:34     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:34 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, Ian Rogers, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 26, 2020 at 02:49:46PM +0530, kajoljain escreveu:
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Adding test that compute DCache_L2 metrics with other related metrics in it.
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> > ---
> >  tools/perf/tests/parse-metric.c | 71 +++++++++++++++++++++++++++++++++
> >  1 file changed, 71 insertions(+)
> > 
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 28f33893338b..aa4d5a9f09a8 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -36,6 +36,27 @@ static struct pmu_event pme_test[] = {
> >  	.metric_expr	= "(dcache_miss_cpi + icache_miss_cycles)",
> >  	.metric_name	= "cache_miss_cycles",
> >  },
> > +{
> > +	.metric_expr	= "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
> > +	.metric_name	= "DCache_L2_All_Hits",
> > +},
> > +{
> > +	.metric_expr	= "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
> > +			  "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
> > +	.metric_name	= "DCache_L2_All_Miss",
> > +},
> > +{
> > +	.metric_expr	= "dcache_l2_all_hits + dcache_l2_all_miss",
> > +	.metric_name	= "DCache_L2_All",
> > +},
> > +{
> > +	.metric_expr	= "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
> > +	.metric_name	= "DCache_L2_Hits",
> > +},
> > +{
> > +	.metric_expr	= "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
> > +	.metric_name	= "DCache_L2_Misses",
> > +},
> >  };
> >  
> >  static struct pmu_events_map map = {
> > @@ -194,10 +215,60 @@ static int test_cache_miss_cycles(void)
> >  	return 0;
> >  }
> >  
> > +
> > +/*
> > + * DCache_L2_All_Hits = l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hi
> > + * DCache_L2_All_Miss = max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) +
> > + *                      l2_rqsts.pf_miss + l2_rqsts.rfo_miss
> > + * DCache_L2_All      = dcache_l2_all_hits + dcache_l2_all_miss
> > + * DCache_L2_Hits     = d_ratio(dcache_l2_all_hits, dcache_l2_all)
> > + * DCache_L2_Misses   = d_ratio(dcache_l2_all_miss, dcache_l2_all)
> > + *
> > + * l2_rqsts.demand_data_rd_hit = 100
> > + * l2_rqsts.pf_hit             = 200
> > + * l2_rqsts.rfo_hi             = 300
> > + * l2_rqsts.all_demand_data_rd = 400
> > + * l2_rqsts.pf_miss            = 500
> > + * l2_rqsts.rfo_miss           = 600
> > + *
> > + * DCache_L2_All_Hits = 600
> > + * DCache_L2_All_Miss = MAX(400 - 100, 0) + 500 + 600 = 1400
> > + * DCache_L2_All      = 600 + 1400  = 2000
> > + * DCache_L2_Hits     = 600 / 2000  = 0.3
> > + * DCache_L2_Misses   = 1400 / 2000 = 0.7
> > + */
> > +static int test_dcache_l2(void)
> > +{
> > +	double ratio;
> > +	struct value vals[] = {
> > +		{ .event = "l2_rqsts.demand_data_rd_hit", .val = 100 },
> > +		{ .event = "l2_rqsts.pf_hit",             .val = 200 },
> > +		{ .event = "l2_rqsts.rfo_hit",            .val = 300 },
> > +		{ .event = "l2_rqsts.all_demand_data_rd", .val = 400 },
> > +		{ .event = "l2_rqsts.pf_miss",            .val = 500 },
> > +		{ .event = "l2_rqsts.rfo_miss",           .val = 600 },
> > +		{ 0 },
> > +	};
> > +
> > +	TEST_ASSERT_VAL("failed to compute metric",
> > +			compute_metric("DCache_L2_Hits", vals, &ratio) == 0);
> > +
> > +	TEST_ASSERT_VAL("DCache_L2_Hits failed, wrong ratio",
> > +			ratio == 0.3);
> > +
> > +	TEST_ASSERT_VAL("failed to compute metric",
> > +			compute_metric("DCache_L2_Misses", vals, &ratio) == 0);
> > +
> > +	TEST_ASSERT_VAL("DCache_L2_Misses failed, wrong ratio",
> > +			ratio == 0.7);
> > +	return 0;
> > +}
> > +
> >  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
> >  {
> >  	TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
> >  	TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
> >  	TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> > +	TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
> >  	return 0;
> >  }
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 15/19] perf metric: Add recursion check when processing nested metrics
  2020-07-19 22:40   ` Ian Rogers
  2020-07-26  9:20     ` kajoljain
@ 2020-07-28 12:35     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:35 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 19, 2020 at 03:40:26PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Keeping the stack of nested metrics via 'struct expr_id' objects
> > and checking if we are in recursion via already processed metric.
> >
> > The stack is implemented as static array within the struct egroup
> > with 100 entries, which should be enough nesting depth for any
> > metric we have or plan to have at the moment.
> >
> > Adding test that simulates the recursion and checks we can
> > detect it.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Ian
> 
> > ---
> >  tools/perf/tests/parse-metric.c |  34 +++++++++-
> >  tools/perf/util/expr.c          |   2 +
> >  tools/perf/util/expr.h          |   9 ++-
> >  tools/perf/util/metricgroup.c   | 117 +++++++++++++++++++++++++++++---
> >  4 files changed, 149 insertions(+), 13 deletions(-)
> >
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index aa4d5a9f09a8..01370ccb9ed9 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -57,6 +57,18 @@ static struct pmu_event pme_test[] = {
> >         .metric_expr    = "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
> >         .metric_name    = "DCache_L2_Misses",
> >  },
> > +{
> > +       .metric_expr    = "ipc + m2",
> > +       .metric_name    = "M1",
> > +},
> > +{
> > +       .metric_expr    = "ipc + m1",
> > +       .metric_name    = "M2",
> > +},
> > +{
> > +       .metric_expr    = "1/m3",
> > +       .metric_name    = "M3",
> > +}
> >  };
> >
> >  static struct pmu_events_map map = {
> > @@ -139,8 +151,8 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
> >         err = metricgroup__parse_groups_test(evlist, &map, name,
> >                                              false, false,
> >                                              &metric_events);
> > -
> > -       TEST_ASSERT_VAL("failed to parse metric", err == 0);
> > +       if (err)
> > +               return err;
> >
> >         if (perf_evlist__alloc_stats(evlist, false))
> >                 return -1;
> > @@ -264,11 +276,29 @@ static int test_dcache_l2(void)
> >         return 0;
> >  }
> >
> > +static int test_recursion_fail(void)
> > +{
> > +       double ratio;
> > +       struct value vals[] = {
> > +               { .event = "inst_retired.any",        .val = 300 },
> > +               { .event = "cpu_clk_unhalted.thread", .val = 200 },
> > +               { 0 },
> > +       };
> > +
> > +       TEST_ASSERT_VAL("failed to find recursion",
> > +                       compute_metric("M1", vals, &ratio) == -1);
> > +
> > +       TEST_ASSERT_VAL("failed to find recursion",
> > +                       compute_metric("M3", vals, &ratio) == -1);
> > +       return 0;
> > +}
> > +
> >  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
> >  {
> >         TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
> >         TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
> >         TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> >         TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
> > +       TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
> >         return 0;
> >  }
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index a346ca590513..53482ef53c41 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -47,6 +47,8 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
> >         if (!data_ptr)
> >                 return -ENOMEM;
> >
> > +       data_ptr->parent = ctx->parent;
> > +
> >         ret = hashmap__set(&ctx->ids, id, data_ptr,
> >                            (const void **)&old_key, (void **)&old_data);
> >         if (ret)
> > diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
> > index 9ed208d93418..fc2b5e824a66 100644
> > --- a/tools/perf/util/expr.h
> > +++ b/tools/perf/util/expr.h
> > @@ -13,8 +13,14 @@
> >
> >  struct metric_ref;
> >
> > +struct expr_id {
> > +       char            *id;
> > +       struct expr_id  *parent;
> > +};
> > +
> >  struct expr_parse_ctx {
> > -       struct hashmap ids;
> > +       struct hashmap   ids;
> > +       struct expr_id  *parent;
> >  };
> >
> >  struct expr_id_data {
> > @@ -25,6 +31,7 @@ struct expr_id_data {
> >                         const char *metric_expr;
> >                         bool counted;
> >                 } ref;
> > +               struct expr_id  *parent;
> >         };
> >
> >         bool is_ref;
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 332414d93f7a..2a45ee94fd61 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -24,6 +24,7 @@
> >  #include <subcmd/parse-options.h>
> >  #include <api/fs/fs.h>
> >  #include "util.h"
> > +#include <asm/bug.h>
> >
> >  struct metric_event *metricgroup__lookup(struct rblist *metric_events,
> >                                          struct evsel *evsel,
> > @@ -126,6 +127,28 @@ struct egroup {
> >         bool has_constraint;
> >  };
> >
> > +#define RECURSION_ID_MAX 100
> > +
> > +struct expr_ids {
> > +       struct expr_id  id[RECURSION_ID_MAX];
> > +       int             cnt;
> > +};
> > +
> > +static struct expr_id *expr_ids__alloc(struct expr_ids *ids)
> > +{
> > +       if (ids->cnt >= RECURSION_ID_MAX)
> > +               return NULL;
> > +       return &ids->id[ids->cnt++];
> > +}
> > +
> > +static void expr_ids__exit(struct expr_ids *ids)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < ids->cnt; i++)
> > +               free(ids->id[i].id);
> > +}
> > +
> >  /**
> >   * Find a group of events in perf_evlist that correpond to those from a parsed
> >   * metric expression. Note, as find_evsel_group is called in the same order as
> > @@ -620,7 +643,9 @@ static int __add_metric(struct list_head *group_list,
> >                         struct pmu_event *pe,
> >                         bool metric_no_group,
> >                         int runtime,
> > -                       struct egroup **egp)
> > +                       struct egroup **egp,
> > +                       struct expr_id *parent,
> > +                       struct expr_ids *ids)
> >  {
> >         struct metric_ref_node *ref;
> >         struct egroup *eg;
> > @@ -630,7 +655,7 @@ static int __add_metric(struct list_head *group_list,
> >                  * We got in here for the parent group,
> >                  * allocate it and put it on the list.
> >                  */
> > -               eg = malloc(sizeof(*eg));
> > +               eg = zalloc(sizeof(*eg));
> >                 if (!eg)
> >                         return -ENOMEM;
> >
> > @@ -643,6 +668,18 @@ static int __add_metric(struct list_head *group_list,
> >                 INIT_LIST_HEAD(&eg->metric_refs);
> >                 eg->metric_refs_cnt = 0;
> >                 *egp = eg;
> > +
> > +               parent = expr_ids__alloc(ids);
> > +               if (!parent) {
> > +                       free(eg);
> > +                       return -EINVAL;
> > +               }
> > +
> > +               parent->id = strdup(pe->metric_name);
> > +               if (!parent->id) {
> > +                       free(eg);
> > +                       return -ENOMEM;
> > +               }
> >         } else {
> >                 /*
> >                  * We got here for the referenced metric, via the
> > @@ -668,6 +705,10 @@ static int __add_metric(struct list_head *group_list,
> >                 eg->metric_refs_cnt++;
> >         }
> >
> > +       /* Force all found IDs in metric to have us as parent ID. */
> > +       WARN_ON_ONCE(!parent);
> > +       eg->pctx.parent = parent;
> > +
> >         /*
> >          * For both the parent and referenced metrics, we parse
> >          * all the metric's IDs and add it to the parent context.
> > @@ -728,15 +769,62 @@ static struct pmu_event *find_metric(const char *metric, struct pmu_events_map *
> >         return NULL;
> >  }
> >
> > +static int recursion_check(struct egroup *eg, const char *id, struct expr_id **parent,
> > +                          struct expr_ids *ids)
> > +{
> > +       struct expr_id_data *data;
> > +       struct expr_id *p;
> > +       int ret;
> > +
> > +       /*
> > +        * We get the parent referenced by 'id' argument and
> > +        * traverse through all the parent object IDs to check
> > +        * if we already processed 'id', if we did, it's recursion
> > +        * and we fail.
> > +        */
> > +       ret = expr__get_id(&eg->pctx, id, &data);
> > +       if (ret)
> > +               return ret;
> > +
> > +       p = data->parent;
> > +
> > +       while (p->parent) {
> > +               if (!strcmp(p->id, id)) {
> > +                       pr_err("failed: recursion detected for %s\n", id);
> > +                       return -1;
> > +               }
> > +               p = p->parent;
> > +       }
> > +
> > +       /*
> > +        * If we are over the limit of static entris, the metric
> > +        * is too difficult/nested to process, fail as well.
> > +        */
> > +       p = expr_ids__alloc(ids);
> > +       if (!p) {
> > +               pr_err("failed: too many nested metrics\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       p->id     = strdup(id);
> > +       p->parent = data->parent;
> > +       *parent   = p;
> > +
> > +       return p->id ? 0 : -ENOMEM;
> > +}
> > +
> >  static int add_metric(struct list_head *group_list,
> >                       struct pmu_event *pe,
> >                       bool metric_no_group,
> > -                     struct egroup **egp);
> > +                     struct egroup **egp,
> > +                     struct expr_id *parent,
> > +                     struct expr_ids *ids);
> >
> >  static int resolve_metric(struct egroup *eg,
> >                           bool metric_no_group,
> >                           struct list_head *group_list,
> > -                         struct pmu_events_map *map)
> > +                         struct pmu_events_map *map,
> > +                         struct expr_ids *ids)
> >  {
> >         struct hashmap_entry *cur;
> >         size_t bkt;
> > @@ -750,18 +838,23 @@ static int resolve_metric(struct egroup *eg,
> >         do {
> >                 all = true;
> >                 hashmap__for_each_entry((&eg->pctx.ids), cur, bkt) {
> > +                       struct expr_id *parent;
> >                         struct pmu_event *pe;
> >
> >                         pe = find_metric(cur->key, map);
> >                         if (!pe)
> >                                 continue;
> >
> > +                       ret = recursion_check(eg, cur->key, &parent, ids);
> > +                       if (ret)
> > +                               return ret;
> > +
> >                         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);
> > +                       ret = add_metric(group_list, pe, metric_no_group, &eg, parent, ids);
> >                         if (ret)
> >                                 return ret;
> >
> > @@ -779,14 +872,16 @@ static int resolve_metric(struct egroup *eg,
> >  static int add_metric(struct list_head *group_list,
> >                       struct pmu_event *pe,
> >                       bool metric_no_group,
> > -                     struct egroup **egp)
> > +                     struct egroup **egp,
> > +                     struct expr_id *parent,
> > +                     struct expr_ids *ids)
> >  {
> >         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, egp);
> > +               ret = __add_metric(group_list, pe, metric_no_group, 1, egp, parent, ids);
> >         } else {
> >                 int j, count;
> >
> > @@ -798,7 +893,7 @@ static int add_metric(struct list_head *group_list,
> >                  */
> >
> >                 for (j = 0; j < count && !ret; j++) {
> > -                       ret = __add_metric(group_list, pe, metric_no_group, j, egp);
> > +                       ret = __add_metric(group_list, pe, metric_no_group, j, egp, parent, ids);
> >                 }
> >         }
> >
> > @@ -811,6 +906,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                                    struct pmu_events_map *map)
> >
> >  {
> > +       struct expr_ids ids = { 0 };
> >         struct pmu_event *pe;
> >         struct egroup *eg;
> >         LIST_HEAD(list);
> > @@ -821,7 +917,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                 has_match = true;
> >                 eg = NULL;
> >
> > -               ret = add_metric(&list, pe, metric_no_group, &eg);
> > +               ret = add_metric(&list, pe, metric_no_group, &eg, NULL, &ids);
> >                 if (ret)
> >                         return ret;
> >
> > @@ -830,7 +926,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >                  * included in the expression.
> >                  */
> >                 ret = resolve_metric(eg, metric_no_group,
> > -                                    &list, map);
> > +                                    &list, map, &ids);
> >                 if (ret)
> >                         return ret;
> >         }
> > @@ -853,6 +949,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >         }
> >
> >         list_splice(&list, group_list);
> > +       expr_ids__exit(&ids);
> >         return 0;
> >  }
> >
> > --
> > 2.25.4
> >

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 16/19] perf metric: Make compute_single function more precise
  2020-07-19 18:13 ` [PATCH 16/19] perf metric: Make compute_single function more precise Jiri Olsa
@ 2020-07-28 12:36   ` Arnaldo Carvalho de Melo
  2020-07-28 17:26     ` Ian Rogers
  0 siblings, 1 reply; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:36 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Em Sun, Jul 19, 2020 at 08:13:17PM +0200, Jiri Olsa escreveu:
> So far compute_single function relies on the fact, that
> there's only single metric defined within evlist in all
> tests. In following patch we will add test for metric
> group, so we need to be able to compute metric by given
> name.
> 
> Adding the name argument to compute_single and iterating
> evlist and evsel's expression to find the given metric.

Applied, thanks.

Ian, Kajol, I didn't notice your Acked-by or Reviewed-by, like for the
other patches, can you check?

- Arnaldo
 
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/perf/tests/parse-metric.c | 22 +++++++++++++---------
>  1 file changed, 13 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 01370ccb9ed9..5ac32f80f8ea 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -108,17 +108,21 @@ static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist,
>  }
>  
>  static double compute_single(struct rblist *metric_events, struct evlist *evlist,
> -			     struct runtime_stat *st)
> +			     struct runtime_stat *st, const char *name)
>  {
> -	struct evsel *evsel = evlist__first(evlist);
> +	struct metric_expr *mexp;
>  	struct metric_event *me;
> +	struct evsel *evsel;
>  
> -	me = metricgroup__lookup(metric_events, evsel, false);
> -	if (me != NULL) {
> -		struct metric_expr *mexp;
> -
> -		mexp = list_first_entry(&me->head, struct metric_expr, nd);
> -		return test_generic_metric(mexp, 0, st);
> +	evlist__for_each_entry(evlist, evsel) {
> +		me = metricgroup__lookup(metric_events, evsel, false);
> +		if (me != NULL) {
> +			list_for_each_entry (mexp, &me->head, nd) {
> +				if (strcmp(mexp->metric_name, name))
> +					continue;
> +				return test_generic_metric(mexp, 0, st);
> +			}
> +		}
>  	}
>  	return 0.;
>  }
> @@ -162,7 +166,7 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>  	load_runtime_stat(&st, evlist, vals);
>  
>  	/* And execute the metric */
> -	*ratio = compute_single(&metric_events, evlist, &st);
> +	*ratio = compute_single(&metric_events, evlist, &st, name);
>  
>  	/* ... clenup. */
>  	metricgroup__rblist_exit(&metric_events);
> -- 
> 2.25.4
> 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 17/19] perf metric: Add metric group test
  2020-07-19 22:41   ` Ian Rogers
  2020-07-26  9:20     ` kajoljain
@ 2020-07-28 12:37     ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:37 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Sun, Jul 19, 2020 at 03:41:14PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Adding test for metric group plus compute_metric_group
> > function to get metrics values within the group.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Ian
> 
> > ---
> >  tools/perf/tests/parse-metric.c | 48 +++++++++++++++++++++++++++++++--
> >  1 file changed, 46 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 5ac32f80f8ea..f2ba5b2c5557 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -18,6 +18,7 @@ static struct pmu_event pme_test[] = {
> >  {
> >         .metric_expr    = "inst_retired.any / cpu_clk_unhalted.thread",
> >         .metric_name    = "IPC",
> > +       .metric_group   = "group1",
> >  },
> >  {
> >         .metric_expr    = "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
> > @@ -35,6 +36,7 @@ static struct pmu_event pme_test[] = {
> >  {
> >         .metric_expr    = "(dcache_miss_cpi + icache_miss_cycles)",
> >         .metric_name    = "cache_miss_cycles",
> > +       .metric_group   = "group1",
> >  },
> >  {
> >         .metric_expr    = "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
> > @@ -127,7 +129,9 @@ static double compute_single(struct rblist *metric_events, struct evlist *evlist
> >         return 0.;
> >  }
> >
> > -static int compute_metric(const char *name, struct value *vals, double *ratio)
> > +static int __compute_metric(const char *name, struct value *vals,
> > +                           const char *name1, double *ratio1,
> > +                           const char *name2, double *ratio2)
> >  {
> >         struct rblist metric_events = {
> >                 .nr_entries = 0,
> > @@ -166,7 +170,10 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
> >         load_runtime_stat(&st, evlist, vals);
> >
> >         /* And execute the metric */
> > -       *ratio = compute_single(&metric_events, evlist, &st, name);
> > +       if (name1 && ratio1)
> > +               *ratio1 = compute_single(&metric_events, evlist, &st, name1);
> > +       if (name2 && ratio2)
> > +               *ratio2 = compute_single(&metric_events, evlist, &st, name2);
> >
> >         /* ... clenup. */
> >         metricgroup__rblist_exit(&metric_events);
> > @@ -177,6 +184,18 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
> >         return 0;
> >  }
> >
> > +static int compute_metric(const char *name, struct value *vals, double *ratio)
> > +{
> > +       return __compute_metric(name, vals, name, ratio, NULL, NULL);
> > +}
> > +
> > +static int compute_metric_group(const char *name, struct value *vals,
> > +                               const char *name1, double *ratio1,
> > +                               const char *name2, double *ratio2)
> > +{
> > +       return __compute_metric(name, vals, name1, ratio1, name2, ratio2);
> > +}
> > +
> >  static int test_ipc(void)
> >  {
> >         double ratio;
> > @@ -297,6 +316,30 @@ static int test_recursion_fail(void)
> >         return 0;
> >  }
> >
> > +static int test_metric_group(void)
> > +{
> > +       double ratio1, ratio2;
> > +       struct value vals[] = {
> > +               { .event = "cpu_clk_unhalted.thread", .val = 200 },
> > +               { .event = "l1d-loads-misses",        .val = 300 },
> > +               { .event = "l1i-loads-misses",        .val = 200 },
> > +               { .event = "inst_retired.any",        .val = 400 },
> > +               { 0 },
> > +       };
> > +
> > +       TEST_ASSERT_VAL("failed to find recursion",
> > +                       compute_metric_group("group1", vals,
> > +                                            "IPC", &ratio1,
> > +                                            "cache_miss_cycles", &ratio2) == 0);
> > +
> > +       TEST_ASSERT_VAL("group IPC failed, wrong ratio",
> > +                       ratio1 == 2.0);
> > +
> > +       TEST_ASSERT_VAL("group cache_miss_cycles failed, wrong ratio",
> > +                       ratio2 == 1.25);
> > +       return 0;
> > +}
> > +
> >  int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
> >  {
> >         TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
> > @@ -304,5 +347,6 @@ int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unu
> >         TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> >         TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
> >         TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
> > +       TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
> >         return 0;
> >  }
> > --
> > 2.25.4
> >

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 19/19] perf metric: Rename group_list to metric_list
  2020-07-26  9:21   ` kajoljain
@ 2020-07-28 12:38     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:38 UTC (permalink / raw)
  To: kajoljain
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian, Ian Rogers

Em Sun, Jul 26, 2020 at 02:51:19PM +0530, kajoljain escreveu:
> 
> 
> On 7/19/20 11:43 PM, Jiri Olsa wrote:
> > Following the previous change that rename egroup
> > to metric, there's no reason to call the list
> > 'group_list' anymore, renaming it to metric_list.
> > 
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> Reviewed-By : Kajol Jain<kjain@linux.ibm.com>

Thanks, applied.

- Arnaldo
 
> Thanks,
> Kajol Jain
> > ---
> >  tools/perf/util/metricgroup.c | 42 +++++++++++++++++------------------
> >  1 file changed, 21 insertions(+), 21 deletions(-)
> > 
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 9d5fff36042d..6f179b9903a0 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -639,7 +639,7 @@ int __weak arch_get_runtimeparam(void)
> >  	return 1;
> >  }
> >  
> > -static int __add_metric(struct list_head *group_list,
> > +static int __add_metric(struct list_head *metric_list,
> >  			struct pmu_event *pe,
> >  			bool metric_no_group,
> >  			int runtime,
> > @@ -726,13 +726,13 @@ static int __add_metric(struct list_head *group_list,
> >  	if (m->metric_refs_cnt)
> >  		return 0;
> >  
> > -	if (list_empty(group_list))
> > -		list_add(&m->nd, group_list);
> > +	if (list_empty(metric_list))
> > +		list_add(&m->nd, metric_list);
> >  	else {
> >  		struct list_head *pos;
> >  
> >  		/* Place the largest groups at the front. */
> > -		list_for_each_prev(pos, group_list) {
> > +		list_for_each_prev(pos, metric_list) {
> >  			struct metric *old = list_entry(pos, struct metric, nd);
> >  
> >  			if (hashmap__size(&m->pctx.ids) <=
> > @@ -813,7 +813,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa
> >  	return p->id ? 0 : -ENOMEM;
> >  }
> >  
> > -static int add_metric(struct list_head *group_list,
> > +static int add_metric(struct list_head *metric_list,
> >  		      struct pmu_event *pe,
> >  		      bool metric_no_group,
> >  		      struct metric **mp,
> > @@ -822,7 +822,7 @@ static int add_metric(struct list_head *group_list,
> >  
> >  static int resolve_metric(struct metric *m,
> >  			  bool metric_no_group,
> > -			  struct list_head *group_list,
> > +			  struct list_head *metric_list,
> >  			  struct pmu_events_map *map,
> >  			  struct expr_ids *ids)
> >  {
> > @@ -854,7 +854,7 @@ static int resolve_metric(struct metric *m,
> >  			expr__del_id(&m->pctx, cur->key);
> >  
> >  			/* ... and it gets resolved to the parent context. */
> > -			ret = add_metric(group_list, pe, metric_no_group, &m, parent, ids);
> > +			ret = add_metric(metric_list, pe, metric_no_group, &m, parent, ids);
> >  			if (ret)
> >  				return ret;
> >  
> > @@ -869,7 +869,7 @@ static int resolve_metric(struct metric *m,
> >  	return 0;
> >  }
> >  
> > -static int add_metric(struct list_head *group_list,
> > +static int add_metric(struct list_head *metric_list,
> >  		      struct pmu_event *pe,
> >  		      bool metric_no_group,
> >  		      struct metric **m,
> > @@ -881,7 +881,7 @@ static int add_metric(struct list_head *group_list,
> >  	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, m, parent, ids);
> > +		ret = __add_metric(metric_list, pe, metric_no_group, 1, m, parent, ids);
> >  	} else {
> >  		int j, count;
> >  
> > @@ -889,11 +889,11 @@ static int add_metric(struct list_head *group_list,
> >  
> >  		/* This loop is added to create multiple
> >  		 * events depend on count value and add
> > -		 * those events to group_list.
> > +		 * those events to metric_list.
> >  		 */
> >  
> >  		for (j = 0; j < count && !ret; j++) {
> > -			ret = __add_metric(group_list, pe, metric_no_group, j, m, parent, ids);
> > +			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
> >  		}
> >  	}
> >  
> > @@ -902,7 +902,7 @@ static int add_metric(struct list_head *group_list,
> >  
> >  static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >  				   struct strbuf *events,
> > -				   struct list_head *group_list,
> > +				   struct list_head *metric_list,
> >  				   struct pmu_events_map *map)
> >  
> >  {
> > @@ -948,14 +948,14 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
> >  		}
> >  	}
> >  
> > -	list_splice(&list, group_list);
> > +	list_splice(&list, metric_list);
> >  	expr_ids__exit(&ids);
> >  	return 0;
> >  }
> >  
> >  static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >  					struct strbuf *events,
> > -					struct list_head *group_list,
> > +					struct list_head *metric_list,
> >  					struct pmu_events_map *map)
> >  {
> >  	char *llist, *nlist, *p;
> > @@ -971,7 +971,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >  
> >  	while ((p = strsep(&llist, ",")) != NULL) {
> >  		ret = metricgroup__add_metric(p, metric_no_group, events,
> > -					      group_list, map);
> > +					      metric_list, map);
> >  		if (ret == -EINVAL) {
> >  			fprintf(stderr, "Cannot find metric or group `%s'\n",
> >  					p);
> > @@ -996,11 +996,11 @@ static void metric__free_refs(struct metric *metric)
> >  	}
> >  }
> >  
> > -static void metricgroup__free_metrics(struct list_head *group_list)
> > +static void metricgroup__free_metrics(struct list_head *metric_list)
> >  {
> >  	struct metric *m, *tmp;
> >  
> > -	list_for_each_entry_safe (m, tmp, group_list, nd) {
> > +	list_for_each_entry_safe (m, tmp, metric_list, nd) {
> >  		metric__free_refs(m);
> >  		expr__ctx_clear(&m->pctx);
> >  		list_del_init(&m->nd);
> > @@ -1017,13 +1017,13 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> >  {
> >  	struct parse_events_error parse_error;
> >  	struct strbuf extra_events;
> > -	LIST_HEAD(group_list);
> > +	LIST_HEAD(metric_list);
> >  	int ret;
> >  
> >  	if (metric_events->nr_entries == 0)
> >  		metricgroup__rblist_init(metric_events);
> >  	ret = metricgroup__add_metric_list(str, metric_no_group,
> > -					   &extra_events, &group_list, map);
> > +					   &extra_events, &metric_list, map);
> >  	if (ret)
> >  		return ret;
> >  	pr_debug("adding %s\n", extra_events.buf);
> > @@ -1034,10 +1034,10 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> >  		goto out;
> >  	}
> >  	strbuf_release(&extra_events);
> > -	ret = metricgroup__setup_events(&group_list, metric_no_merge,
> > +	ret = metricgroup__setup_events(&metric_list, metric_no_merge,
> >  					perf_evlist, metric_events);
> >  out:
> > -	metricgroup__free_metrics(&group_list);
> > +	metricgroup__free_metrics(&metric_list);
> >  	return ret;
> >  }
> >  
> > 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-20 19:16           ` Jiri Olsa
  2020-07-24  5:52             ` kajoljain
@ 2020-07-28 12:39             ` Arnaldo Carvalho de Melo
  2020-07-28 12:54               ` Jiri Olsa
  1 sibling, 1 reply; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:39 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: kajoljain, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Em Mon, Jul 20, 2020 at 09:16:25PM +0200, Jiri Olsa escreveu:
> On Mon, Jul 20, 2020 at 02:32:40PM +0530, kajoljain wrote:
> > 
> > 
> > On 7/20/20 1:49 PM, Jiri Olsa wrote:
> > > On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:
> > > 
> > > SNIP
> > > 
> > >> This is with your perf/metric branch:
> > >> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
> > >> assertion failed at util/metricgroup.c:709
> > >> #           time             counts unit events
> > >>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> > >>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
> > >>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> > >>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
> > >>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
> > >>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
> > >> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
> > >>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
> > >>
> > >>  Performance counter stats for 'CPU(s) 0':
> > >>
> > >>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
> > >>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
> > >>
> > >>        3.259505529 seconds time elapsed
> > > 
> > > I found the bug, we are not adding runtime metrics as standalone ones,
> > > but as referenced metrics.. will fix and try to add test for that
> > > 
> > > as for testing.. do I need some special ppc server to have support for this? 
> > 
> > Hi jiri,
> >     We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
> > enabled.
> 
> could you please try with following patch on top?

So, can you point me to the cset that this should be merged into? Or can
it come as a separate patch? I'll put what I have in the tmp.perf/core
branch, and will do testing, please let me know if you want to fold it
or as a followup patch.

- Arnaldo
 
> thanks,
> jirka
> 
> 
> ---
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 6f179b9903a0..03aa4bd4a38b 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -820,11 +820,11 @@ static int add_metric(struct list_head *metric_list,
>  		      struct expr_id *parent,
>  		      struct expr_ids *ids);
>  
> -static int resolve_metric(struct metric *m,
> -			  bool metric_no_group,
> -			  struct list_head *metric_list,
> -			  struct pmu_events_map *map,
> -			  struct expr_ids *ids)
> +static int __resolve_metric(struct metric *m,
> +			    bool metric_no_group,
> +			    struct list_head *metric_list,
> +			    struct pmu_events_map *map,
> +			    struct expr_ids *ids)
>  {
>  	struct hashmap_entry *cur;
>  	size_t bkt;
> @@ -869,6 +869,23 @@ static int resolve_metric(struct metric *m,
>  	return 0;
>  }
>  
> +static int resolve_metric(bool metric_no_group,
> +			  struct list_head *metric_list,
> +			  struct pmu_events_map *map,
> +			  struct expr_ids *ids)
> +{
> +	struct metric *m;
> +	int err;
> +
> +	list_for_each_entry(m, metric_list, nd) {
> +		err = __resolve_metric(m, metric_no_group, metric_list, map, ids);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
>  static int add_metric(struct list_head *metric_list,
>  		      struct pmu_event *pe,
>  		      bool metric_no_group,
> @@ -876,6 +893,7 @@ static int add_metric(struct list_head *metric_list,
>  		      struct expr_id *parent,
>  		      struct expr_ids *ids)
>  {
> +	struct metric *orig = *m;
>  	int ret = 0;
>  
>  	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
> @@ -892,7 +910,7 @@ static int add_metric(struct list_head *metric_list,
>  		 * those events to metric_list.
>  		 */
>  
> -		for (j = 0; j < count && !ret; j++) {
> +		for (j = 0; j < count && !ret; j++, *m = orig) {
>  			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
>  		}
>  	}
> @@ -907,8 +925,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  
>  {
>  	struct expr_ids ids = { 0 };
> +	struct metric *m = NULL;
>  	struct pmu_event *pe;
> -	struct metric *m;
>  	LIST_HEAD(list);
>  	int i, ret;
>  	bool has_match = false;
> @@ -925,7 +943,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
>  		 * Process any possible referenced metrics
>  		 * included in the expression.
>  		 */
> -		ret = resolve_metric(m, metric_no_group,
> +		ret = resolve_metric(metric_no_group,
>  				     &list, map, &ids);
>  		if (ret)
>  			return ret;
> 

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-23 15:59     ` Paul A. Clarke
  2020-07-25 11:52       ` Jiri Olsa
@ 2020-07-28 12:42       ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 12:42 UTC (permalink / raw)
  To: Paul A. Clarke
  Cc: Jiri Olsa, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	Kajol Jain, John Garry, Stephane Eranian, Ian Rogers

Em Thu, Jul 23, 2020 at 10:59:58AM -0500, Paul A. Clarke escreveu:
> On Wed, Jul 22, 2020 at 08:11:58PM +0200, Jiri Olsa wrote:
> > On Tue, Jul 21, 2020 at 09:48:48AM -0500, Paul A. Clarke wrote:
> > > On Sun, Jul 19, 2020 at 08:13:01PM +0200, Jiri Olsa wrote:
> > > > hi,
> > > > this patchset is adding the support to reused metric in
> > > > another metric.
> > > > 
> > > > For example, to define IPC by using CPI with change like:
> > > > 
> > > >      {
> > > >          "BriefDescription": "Instructions Per Cycle (per Logical Processor)",
> > > > -        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
> > > > +        "MetricExpr": "1/CPI",
> > > >          "MetricGroup": "TopDownL1",
> > > >          "MetricName": "IPC"
> > > >      },
> > > > 
> > > > I won't be able to find all the possible places we could
> > > > use this at, so I wonder you guys (who was asking for this)
> > > > would try it and come up with comments if there's something
> > > > missing or we could already use it at some places.
> > > > 
> > > > It's based on Arnaldo's tmp.perf/core.
> > > > 
> > > > v3 changes:
> > > >   - added some acks
> > > >   - some patches got merged
> > > >   - added missing zalloc include [John Garry]
> > > >   - added ids array outside the egroup object [Ian]
> > > >   - removed wrong m->has_constraint assignment [Ian]
> > > >   - renamed 'list' to 'metric_list' [Ian]
> > > >   - fixed group metric and added test for it [Paul A. Clarke]
> > > >   - fixed memory leak [Arnaldo]
> > > >   - using lowercase keys for metrics in hashmap, because jevents
> > > >     converts metric_expr to lowercase
> > > > 
> > > > Also available in here:
> > > >   git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> > > >   perf/metric
> > > 
> > > These changes seem to be mostly working for me.
> > > 
> > > I attempted to exploit the new capability in the metrics definitions in
> > > tools/perf/pmu-events/arch/powerpc/power9/metrics.json.  Those changes
> > > are included below.
> > > 
> > > The one problem I found is with the "cpi_breakdown" metric group, as it
> > > no longer works:
> > > ```
> > > # perf stat --metrics cpi_breakdown ./command
> > > Cannot find metric or group `cpi_breakdown'
> > > ```
> > > 
> > > "cpi_breakdown" does show up in `perf list --metricgroup`, and all of the
> > > (95!) metrics listed in that group are usable, so it's not obvious whether
> > > my changes have a problem, or merely provoke one.
> > 
> > I underestimated the recursion depth setup for groups,
> > your change is working for me with following change:
> > 
> > -#define RECURSION_ID_MAX 100
> > +#define RECURSION_ID_MAX 1000
> 
> That indeed addressed the issue.

Thanks, I made that change on the cset that added this define.

- Arnaldo
 
> Is there a point where that limit was being hit and the code silently fails?
> If so, should that failure be less silent?
> 
> PC

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-28 12:39             ` Arnaldo Carvalho de Melo
@ 2020-07-28 12:54               ` Jiri Olsa
  2020-07-28 13:01                 ` Jiri Olsa
  0 siblings, 1 reply; 88+ messages in thread
From: Jiri Olsa @ 2020-07-28 12:54 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: kajoljain, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

On Tue, Jul 28, 2020 at 09:39:55AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Mon, Jul 20, 2020 at 09:16:25PM +0200, Jiri Olsa escreveu:
> > On Mon, Jul 20, 2020 at 02:32:40PM +0530, kajoljain wrote:
> > > 
> > > 
> > > On 7/20/20 1:49 PM, Jiri Olsa wrote:
> > > > On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:
> > > > 
> > > > SNIP
> > > > 
> > > >> This is with your perf/metric branch:
> > > >> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
> > > >> assertion failed at util/metricgroup.c:709
> > > >> #           time             counts unit events
> > > >>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> > > >>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > >>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> > > >>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > >>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
> > > >>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > >> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
> > > >>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > >>
> > > >>  Performance counter stats for 'CPU(s) 0':
> > > >>
> > > >>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
> > > >>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > >>
> > > >>        3.259505529 seconds time elapsed
> > > > 
> > > > I found the bug, we are not adding runtime metrics as standalone ones,
> > > > but as referenced metrics.. will fix and try to add test for that
> > > > 
> > > > as for testing.. do I need some special ppc server to have support for this? 
> > > 
> > > Hi jiri,
> > >     We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
> > > enabled.
> > 
> > could you please try with following patch on top?
> 
> So, can you point me to the cset that this should be merged into? Or can
> it come as a separate patch? I'll put what I have in the tmp.perf/core
> branch, and will do testing, please let me know if you want to fold it
> or as a followup patch.

sorry for delay.. I planned to squash the change in, but if you already
pushed something out, I'll rebase on top, I will post new version tomorrow

1st 7 patches are good to go in any case

thanks,
jirka


^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-28 12:54               ` Jiri Olsa
@ 2020-07-28 13:01                 ` Jiri Olsa
  2020-07-28 13:34                   ` [PATCHv3 20/19] perf metric: Fix runtime metric for powerpc Jiri Olsa
  2020-07-28 15:22                   ` [PATCHv3 00/19] perf metric: Add support to reuse metric Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-28 13:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: kajoljain, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

On Tue, Jul 28, 2020 at 02:54:56PM +0200, Jiri Olsa wrote:
> On Tue, Jul 28, 2020 at 09:39:55AM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Mon, Jul 20, 2020 at 09:16:25PM +0200, Jiri Olsa escreveu:
> > > On Mon, Jul 20, 2020 at 02:32:40PM +0530, kajoljain wrote:
> > > > 
> > > > 
> > > > On 7/20/20 1:49 PM, Jiri Olsa wrote:
> > > > > On Mon, Jul 20, 2020 at 01:39:24PM +0530, kajoljain wrote:
> > > > > 
> > > > > SNIP
> > > > > 
> > > > >> This is with your perf/metric branch:
> > > > >> command# ./perf stat -M PowerBUS_Frequency -C 0 -I 1000
> > > > >> assertion failed at util/metricgroup.c:709
> > > > >> #           time             counts unit events
> > > > >>      1.000054545          7,807,505      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> > > > >>      1.000054545          7,807,485      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > > >>      2.000232761          7,807,500      hv_24x7/pm_pb_cyc,chip=0/ #      2.0 GHz  PowerBUS_Frequency_0
> > > > >>      2.000232761          7,807,478      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > > >>      3.000363762          7,799,665      hv_24x7/pm_pb_cyc,chip=0/ #      1.9 GHz  PowerBUS_Frequency_0
> > > > >>      3.000363762          7,807,502      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > > >> ^C     3.259418599          2,022,150      hv_24x7/pm_pb_cyc,chip=0/ #      0.5 GHz  PowerBUS_Frequency_0
> > > > >>      3.259418599          2,022,164      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > > >>
> > > > >>  Performance counter stats for 'CPU(s) 0':
> > > > >>
> > > > >>         25,436,820      hv_24x7/pm_pb_cyc,chip=0/ #      6.4 GHz  PowerBUS_Frequency_0
> > > > >>         25,444,629      hv_24x7/pm_pb_cyc,chip=1/                                   
> > > > >>
> > > > >>        3.259505529 seconds time elapsed
> > > > > 
> > > > > I found the bug, we are not adding runtime metrics as standalone ones,
> > > > > but as referenced metrics.. will fix and try to add test for that
> > > > > 
> > > > > as for testing.. do I need some special ppc server to have support for this? 
> > > > 
> > > > Hi jiri,
> > > >     We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
> > > > enabled.
> > > 
> > > could you please try with following patch on top?
> > 
> > So, can you point me to the cset that this should be merged into? Or can
> > it come as a separate patch? I'll put what I have in the tmp.perf/core
> > branch, and will do testing, please let me know if you want to fold it
> > or as a followup patch.
> 
> sorry for delay.. I planned to squash the change in, but if you already
> pushed something out, I'll rebase on top, I will post new version tomorrow
> 
> 1st 7 patches are good to go in any case

ok, I just saw it's pushed out, I'll post a patch on top of it

jirka


^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCHv3 20/19] perf metric: Fix runtime metric for powerpc
  2020-07-28 13:01                 ` Jiri Olsa
@ 2020-07-28 13:34                   ` Jiri Olsa
  2020-07-28 15:22                   ` [PATCHv3 00/19] perf metric: Add support to reuse metric Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-28 13:34 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: kajoljain, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Recent code factoring screwed up runtime metrics for powerpc,
because we did not treat separate runtime metrics as single
metrics, but added them as referenced ones.

Fixing this by zero-ing parent metric object for __add_metric
call. Also there's no need to pass metric object to resolve_metric
function, we just need to iterate the metric_list.

Tested/Reviewed-By : Kajol Jain<kjain@linux.ibm.com>
Fixes: e975d61c466b ("perf metric: Collect referenced metrics in struct metric_ref_node")
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/metricgroup.c | 35 ++++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index e91a625fa1be..50bd485094ba 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -820,11 +820,11 @@ static int add_metric(struct list_head *metric_list,
 		      struct expr_id *parent,
 		      struct expr_ids *ids);
 
-static int resolve_metric(struct metric *m,
-			  bool metric_no_group,
-			  struct list_head *metric_list,
-			  struct pmu_events_map *map,
-			  struct expr_ids *ids)
+static int __resolve_metric(struct metric *m,
+			    bool metric_no_group,
+			    struct list_head *metric_list,
+			    struct pmu_events_map *map,
+			    struct expr_ids *ids)
 {
 	struct hashmap_entry *cur;
 	size_t bkt;
@@ -869,6 +869,23 @@ static int resolve_metric(struct metric *m,
 	return 0;
 }
 
+static int resolve_metric(bool metric_no_group,
+			  struct list_head *metric_list,
+			  struct pmu_events_map *map,
+			  struct expr_ids *ids)
+{
+	struct metric *m;
+	int err;
+
+	list_for_each_entry(m, metric_list, nd) {
+		err = __resolve_metric(m, metric_no_group, metric_list, map, ids);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int add_metric(struct list_head *metric_list,
 		      struct pmu_event *pe,
 		      bool metric_no_group,
@@ -876,6 +893,7 @@ static int add_metric(struct list_head *metric_list,
 		      struct expr_id *parent,
 		      struct expr_ids *ids)
 {
+	struct metric *orig = *m;
 	int ret = 0;
 
 	pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
@@ -892,9 +910,8 @@ static int add_metric(struct list_head *metric_list,
 		 * those events to metric_list.
 		 */
 
-		for (j = 0; j < count && !ret; j++) {
+		for (j = 0; j < count && !ret; j++, *m = orig)
 			ret = __add_metric(metric_list, pe, metric_no_group, j, m, parent, ids);
-		}
 	}
 
 	return ret;
@@ -907,8 +924,8 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 
 {
 	struct expr_ids ids = { 0 };
+	struct metric *m = NULL;
 	struct pmu_event *pe;
-	struct metric *m;
 	LIST_HEAD(list);
 	int i, ret;
 	bool has_match = false;
@@ -925,7 +942,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 		 * Process any possible referenced metrics
 		 * included in the expression.
 		 */
-		ret = resolve_metric(m, metric_no_group,
+		ret = resolve_metric(metric_no_group,
 				     &list, map, &ids);
 		if (ret)
 			return ret;
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCHv3 00/19] perf metric: Add support to reuse metric
  2020-07-28 13:01                 ` Jiri Olsa
  2020-07-28 13:34                   ` [PATCHv3 20/19] perf metric: Fix runtime metric for powerpc Jiri Olsa
@ 2020-07-28 15:22                   ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-28 15:22 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: kajoljain, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian, Ian Rogers

Em Tue, Jul 28, 2020 at 03:01:00PM +0200, Jiri Olsa escreveu:
> On Tue, Jul 28, 2020 at 02:54:56PM +0200, Jiri Olsa wrote:
> > On Tue, Jul 28, 2020 at 09:39:55AM -0300, Arnaldo Carvalho de Melo wrote:
> > > Em Mon, Jul 20, 2020 at 09:16:25PM +0200, Jiri Olsa escreveu:
> > > > On Mon, Jul 20, 2020 at 02:32:40PM +0530, kajoljain wrote:
> > > > > Hi jiri,
> > > > >     We need power9 lpar machine and need to make sure `CONFIG_HV_PERF_CTRS` is
> > > > > enabled.

> > > > could you please try with following patch on top?

> > > So, can you point me to the cset that this should be merged into? Or can
> > > it come as a separate patch? I'll put what I have in the tmp.perf/core
> > > branch, and will do testing, please let me know if you want to fold it
> > > or as a followup patch.

> > sorry for delay.. I planned to squash the change in, but if you already
> > pushed something out, I'll rebase on top, I will post new version tomorrow

> > 1st 7 patches are good to go in any case

> ok, I just saw it's pushed out, I'll post a patch on top of it

See, the tmp.perf/core experimentation is about making it available what
would be just my local tree for wider consumption, what I have in
perf/core is what is non-rebase material, I try to push things there
only after testing and then recording the tests performed as signed
tags, see:

https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tag/?h=perf-tools-tests-2020-07-17

So if we find something wrong with material made available via my
tmp.perf/core branch, we can go back in time and fix it, to try and have
a more solid bisection base.

It may be confusing (it seems so from how you responded to this thread),
and if it ends up being so confusing, I'll just ditch it and go back to
having just local branches, would be a pity as I'm keen on having a good
bisection history so I'll probably take more time to publish things.

Opinions about this, of course, more than welcome.

Back to this specific case, when sending fixes for things in
tmp.perf/core, please state what is the cset that needs folding into.

Thanks,

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 16/19] perf metric: Make compute_single function more precise
  2020-07-28 12:36   ` Arnaldo Carvalho de Melo
@ 2020-07-28 17:26     ` Ian Rogers
  2020-07-28 20:17       ` kajoljain
  0 siblings, 1 reply; 88+ messages in thread
From: Ian Rogers @ 2020-07-28 17:26 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, Kajol Jain,
	John Garry, Paul A. Clarke, Stephane Eranian

On Tue, Jul 28, 2020 at 5:36 AM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> Em Sun, Jul 19, 2020 at 08:13:17PM +0200, Jiri Olsa escreveu:
> > So far compute_single function relies on the fact, that
> > there's only single metric defined within evlist in all
> > tests. In following patch we will add test for metric
> > group, so we need to be able to compute metric by given
> > name.
> >
> > Adding the name argument to compute_single and iterating
> > evlist and evsel's expression to find the given metric.
>
> Applied, thanks.
>
> Ian, Kajol, I didn't notice your Acked-by or Reviewed-by, like for the
> other patches, can you check?


Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> - Arnaldo
>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  tools/perf/tests/parse-metric.c | 22 +++++++++++++---------
> >  1 file changed, 13 insertions(+), 9 deletions(-)
> >
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 01370ccb9ed9..5ac32f80f8ea 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -108,17 +108,21 @@ static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist,
> >  }
> >
> >  static double compute_single(struct rblist *metric_events, struct evlist *evlist,
> > -                          struct runtime_stat *st)
> > +                          struct runtime_stat *st, const char *name)
> >  {
> > -     struct evsel *evsel = evlist__first(evlist);
> > +     struct metric_expr *mexp;
> >       struct metric_event *me;
> > +     struct evsel *evsel;
> >
> > -     me = metricgroup__lookup(metric_events, evsel, false);
> > -     if (me != NULL) {
> > -             struct metric_expr *mexp;
> > -
> > -             mexp = list_first_entry(&me->head, struct metric_expr, nd);
> > -             return test_generic_metric(mexp, 0, st);
> > +     evlist__for_each_entry(evlist, evsel) {
> > +             me = metricgroup__lookup(metric_events, evsel, false);
> > +             if (me != NULL) {
> > +                     list_for_each_entry (mexp, &me->head, nd) {
> > +                             if (strcmp(mexp->metric_name, name))
> > +                                     continue;
> > +                             return test_generic_metric(mexp, 0, st);
> > +                     }
> > +             }
> >       }
> >       return 0.;
> >  }
> > @@ -162,7 +166,7 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
> >       load_runtime_stat(&st, evlist, vals);
> >
> >       /* And execute the metric */
> > -     *ratio = compute_single(&metric_events, evlist, &st);
> > +     *ratio = compute_single(&metric_events, evlist, &st, name);
> >
> >       /* ... clenup. */
> >       metricgroup__rblist_exit(&metric_events);
> > --
> > 2.25.4
> >
>
> --
>
> - Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 16/19] perf metric: Make compute_single function more precise
  2020-07-28 17:26     ` Ian Rogers
@ 2020-07-28 20:17       ` kajoljain
  2020-07-29 11:08         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 88+ messages in thread
From: kajoljain @ 2020-07-28 20:17 UTC (permalink / raw)
  To: Ian Rogers, Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
	Peter Zijlstra, Michael Petlan, Andi Kleen, John Garry,
	Paul A. Clarke, Stephane Eranian



On 7/28/20 10:56 PM, Ian Rogers wrote:
> On Tue, Jul 28, 2020 at 5:36 AM Arnaldo Carvalho de Melo
> <acme@kernel.org> wrote:
>>
>> Em Sun, Jul 19, 2020 at 08:13:17PM +0200, Jiri Olsa escreveu:
>>> So far compute_single function relies on the fact, that
>>> there's only single metric defined within evlist in all
>>> tests. In following patch we will add test for metric
>>> group, so we need to be able to compute metric by given
>>> name.
>>>
>>> Adding the name argument to compute_single and iterating
>>> evlist and evsel's expression to find the given metric.
>>
>> Applied, thanks.
>>
>> Ian, Kajol, I didn't notice your Acked-by or Reviewed-by, like for the
>> other patches, can you check?
> 
> 
> Acked-by: Ian Rogers <irogers@google.com>

Reviewed-By: Kajol Jain<kjain@linux.ibm.com>

Thanks,
Kajol Jain
> 
> Thanks,
> Ian
> 
>> - Arnaldo
>>
>>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
>>> ---
>>>  tools/perf/tests/parse-metric.c | 22 +++++++++++++---------
>>>  1 file changed, 13 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
>>> index 01370ccb9ed9..5ac32f80f8ea 100644
>>> --- a/tools/perf/tests/parse-metric.c
>>> +++ b/tools/perf/tests/parse-metric.c
>>> @@ -108,17 +108,21 @@ static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist,
>>>  }
>>>
>>>  static double compute_single(struct rblist *metric_events, struct evlist *evlist,
>>> -                          struct runtime_stat *st)
>>> +                          struct runtime_stat *st, const char *name)
>>>  {
>>> -     struct evsel *evsel = evlist__first(evlist);
>>> +     struct metric_expr *mexp;
>>>       struct metric_event *me;
>>> +     struct evsel *evsel;
>>>
>>> -     me = metricgroup__lookup(metric_events, evsel, false);
>>> -     if (me != NULL) {
>>> -             struct metric_expr *mexp;
>>> -
>>> -             mexp = list_first_entry(&me->head, struct metric_expr, nd);
>>> -             return test_generic_metric(mexp, 0, st);
>>> +     evlist__for_each_entry(evlist, evsel) {
>>> +             me = metricgroup__lookup(metric_events, evsel, false);
>>> +             if (me != NULL) {
>>> +                     list_for_each_entry (mexp, &me->head, nd) {
>>> +                             if (strcmp(mexp->metric_name, name))
>>> +                                     continue;
>>> +                             return test_generic_metric(mexp, 0, st);
>>> +                     }
>>> +             }
>>>       }
>>>       return 0.;
>>>  }
>>> @@ -162,7 +166,7 @@ static int compute_metric(const char *name, struct value *vals, double *ratio)
>>>       load_runtime_stat(&st, evlist, vals);
>>>
>>>       /* And execute the metric */
>>> -     *ratio = compute_single(&metric_events, evlist, &st);
>>> +     *ratio = compute_single(&metric_events, evlist, &st, name);
>>>
>>>       /* ... clenup. */
>>>       metricgroup__rblist_exit(&metric_events);
>>> --
>>> 2.25.4
>>>
>>
>> --
>>
>> - Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH 16/19] perf metric: Make compute_single function more precise
  2020-07-28 20:17       ` kajoljain
@ 2020-07-29 11:08         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 88+ messages in thread
From: Arnaldo Carvalho de Melo @ 2020-07-29 11:08 UTC (permalink / raw)
  To: kajoljain
  Cc: Ian Rogers, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Peter Zijlstra, Michael Petlan, Andi Kleen,
	John Garry, Paul A. Clarke, Stephane Eranian

Em Wed, Jul 29, 2020 at 01:47:01AM +0530, kajoljain escreveu:
> 
> 
> On 7/28/20 10:56 PM, Ian Rogers wrote:
> > On Tue, Jul 28, 2020 at 5:36 AM Arnaldo Carvalho de Melo
> > <acme@kernel.org> wrote:
> >>
> >> Em Sun, Jul 19, 2020 at 08:13:17PM +0200, Jiri Olsa escreveu:
> >>> So far compute_single function relies on the fact, that
> >>> there's only single metric defined within evlist in all
> >>> tests. In following patch we will add test for metric
> >>> group, so we need to be able to compute metric by given
> >>> name.
> >>>
> >>> Adding the name argument to compute_single and iterating
> >>> evlist and evsel's expression to find the given metric.
> >>
> >> Applied, thanks.
> >>
> >> Ian, Kajol, I didn't notice your Acked-by or Reviewed-by, like for the
> >> other patches, can you check?
> > 
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> 
> Reviewed-By: Kajol Jain<kjain@linux.ibm.com>

Thanks, updated the patch with both tags,

- Arnaldo

^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCH 11/19] perf metric: Compute referenced metrics
  2020-07-29  9:18 [PATCHv4 " Jiri Olsa
@ 2020-07-29  9:19 ` Jiri Olsa
  0 siblings, 0 replies; 88+ messages in thread
From: Jiri Olsa @ 2020-07-29  9:19 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Kajol Jain, Ian Rogers, Alexander Shishkin, Andi Kleen,
	John Garry, Michael Petlan, Namhyung Kim, Paul Clarke,
	Peter Zijlstra, Stephane Eranian, lkml, Ingo Molnar,
	Peter Zijlstra

Adding computation (expr__parse call) of referenced metric at
the point when it needs to be resolved during the parent metric
computation.

Once the inner metric is computed, the result is stored and
used if there's another usage of that metric.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Kajol Jain <kjain@linux.ibm.com>
Acked-by: Ian Rogers <irogers@google.com>
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-12-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/expr.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/util/expr.h |  3 +++
 tools/perf/util/expr.y |  4 ++--
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index d3997c2b4a90..a346ca590513 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -112,6 +112,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
 	 */
 	data_ptr->ref.metric_name = ref->metric_name;
 	data_ptr->ref.metric_expr = ref->metric_expr;
+	data_ptr->ref.counted = false;
 	data_ptr->is_ref = true;
 
 	ret = hashmap__set(&ctx->ids, name, data_ptr,
@@ -133,6 +134,34 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
 }
 
+int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
+		     struct expr_id_data **datap)
+{
+	struct expr_id_data *data;
+
+	if (expr__get_id(ctx, id, datap) || !*datap) {
+		pr_debug("%s not found\n", id);
+		return -1;
+	}
+
+	data = *datap;
+
+	pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n",
+		  data->is_ref, data->ref.counted, data->val, id);
+
+	if (data->is_ref && !data->ref.counted) {
+		data->ref.counted = true;
+		pr_debug("processing metric: %s ENTRY\n", id);
+		if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) {
+			pr_debug("%s failed to count\n", id);
+			return -1;
+		}
+		pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
+	}
+
+	return 0;
+}
+
 void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
 {
 	struct expr_id_data *old_val = NULL;
@@ -173,6 +202,8 @@ __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
 	void *scanner;
 	int ret;
 
+	pr_debug2("parsing metric: %s\n", expr);
+
 	ret = expr_lex_init_extra(&scanner_ctx, &scanner);
 	if (ret)
 		return ret;
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 81d04ff7f857..9ed208d93418 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -23,6 +23,7 @@ struct expr_id_data {
 		struct {
 			const char *metric_name;
 			const char *metric_expr;
+			bool counted;
 		} ref;
 	};
 
@@ -42,6 +43,8 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val);
 int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref);
 int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 		 struct expr_id_data **data);
+int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
+		     struct expr_id_data **datap);
 int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
 		const char *expr, int runtime);
 int expr__find_other(const char *expr, const char *one,
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index 0d4f5d324be7..d34b370391c6 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -88,11 +88,11 @@ expr:	  NUMBER
 	| ID			{
 					struct expr_id_data *data;
 
-					if (expr__get_id(ctx, $1, &data) || !data) {
-						pr_debug("%s not found\n", $1);
+					if (expr__resolve_id(ctx, $1, &data)) {
 						free($1);
 						YYABORT;
 					}
+
 					$$ = data->val;
 					free($1);
 				}
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 88+ messages in thread

end of thread, other threads:[~2020-07-29 11:08 UTC | newest]

Thread overview: 88+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-19 18:13 [PATCHv3 00/19] perf metric: Add support to reuse metric Jiri Olsa
2020-07-19 18:13 ` [PATCH 01/19] perf metric: Fix memory leak in expr__add_id function Jiri Olsa
2020-07-19 21:41   ` Ian Rogers
2020-07-28 12:26     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 02/19] perf metric: Add " Jiri Olsa
2020-07-26  9:16   ` kajoljain
2020-07-28 12:27     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 03/19] perf metric: Change expr__get_id to return struct expr_id_data Jiri Olsa
2020-07-26  9:17   ` kajoljain
2020-07-28 12:28     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 04/19] perf metric: Add expr__del_id function Jiri Olsa
2020-07-26  9:17   ` kajoljain
2020-07-28 12:28     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 05/19] perf metric: Add macros for iterating map events Jiri Olsa
2020-07-19 21:46   ` Ian Rogers
2020-07-28 12:29     ` Arnaldo Carvalho de Melo
2020-07-26  9:17   ` kajoljain
2020-07-19 18:13 ` [PATCH 06/19] perf metric: Add add_metric function Jiri Olsa
2020-07-26  9:17   ` kajoljain
2020-07-28 12:30     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 07/19] perf metric: Rename __metricgroup__add_metric to __add_metric Jiri Olsa
2020-07-26  9:18   ` kajoljain
2020-07-28 12:30     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 08/19] perf metric: Collect referenced metrics in struct metric_ref_node Jiri Olsa
2020-07-19 22:18   ` Ian Rogers
2020-07-26  9:18     ` kajoljain
2020-07-28 12:31     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 09/19] perf metric: Collect referenced metrics in struct metric_expr Jiri Olsa
2020-07-26  9:18   ` kajoljain
2020-07-28 12:32     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 10/19] perf metric: Add referenced metrics to hash data Jiri Olsa
2020-07-19 22:32   ` Ian Rogers
2020-07-26  9:18     ` kajoljain
2020-07-28 12:32     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 11/19] perf metric: Compute referenced metrics Jiri Olsa
2020-07-26  9:19   ` kajoljain
2020-07-28 12:33     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 12/19] perf metric: Add events for the current list Jiri Olsa
2020-07-19 22:34   ` Ian Rogers
2020-07-26  9:19     ` kajoljain
2020-07-28 12:33     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 13/19] perf metric: Add cache_miss_cycles to metric parse test Jiri Olsa
2020-07-26  9:19   ` kajoljain
2020-07-28 12:34     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 14/19] perf metric: Add DCache_L2 " Jiri Olsa
2020-07-26  9:19   ` kajoljain
2020-07-28 12:34     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 15/19] perf metric: Add recursion check when processing nested metrics Jiri Olsa
2020-07-19 22:40   ` Ian Rogers
2020-07-26  9:20     ` kajoljain
2020-07-28 12:35     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 16/19] perf metric: Make compute_single function more precise Jiri Olsa
2020-07-28 12:36   ` Arnaldo Carvalho de Melo
2020-07-28 17:26     ` Ian Rogers
2020-07-28 20:17       ` kajoljain
2020-07-29 11:08         ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 17/19] perf metric: Add metric group test Jiri Olsa
2020-07-19 22:41   ` Ian Rogers
2020-07-26  9:20     ` kajoljain
2020-07-28 12:37     ` Arnaldo Carvalho de Melo
2020-07-19 18:13 ` [PATCH 18/19] perf metric: Rename struct egroup to metric Jiri Olsa
2020-07-26  9:20   ` kajoljain
2020-07-19 18:13 ` [PATCH 19/19] perf metric: Rename group_list to metric_list Jiri Olsa
2020-07-19 22:42   ` Ian Rogers
2020-07-26  9:21   ` kajoljain
2020-07-28 12:38     ` Arnaldo Carvalho de Melo
2020-07-20  6:44 ` [PATCHv3 00/19] perf metric: Add support to reuse metric kajoljain
2020-07-20  7:22   ` Jiri Olsa
2020-07-20  8:09     ` kajoljain
2020-07-20  8:19       ` Jiri Olsa
2020-07-20  9:02         ` kajoljain
2020-07-20 19:16           ` Jiri Olsa
2020-07-24  5:52             ` kajoljain
2020-07-25 11:51               ` Jiri Olsa
2020-07-26  9:14                 ` kajoljain
2020-07-28 12:39             ` Arnaldo Carvalho de Melo
2020-07-28 12:54               ` Jiri Olsa
2020-07-28 13:01                 ` Jiri Olsa
2020-07-28 13:34                   ` [PATCHv3 20/19] perf metric: Fix runtime metric for powerpc Jiri Olsa
2020-07-28 15:22                   ` [PATCHv3 00/19] perf metric: Add support to reuse metric Arnaldo Carvalho de Melo
2020-07-21 14:48 ` Paul A. Clarke
2020-07-22 18:11   ` Jiri Olsa
2020-07-23 15:59     ` Paul A. Clarke
2020-07-25 11:52       ` Jiri Olsa
2020-07-28 12:42       ` Arnaldo Carvalho de Melo
2020-07-23 17:14     ` Paul A. Clarke
2020-07-23 17:40       ` Andi Kleen
2020-07-29  9:18 [PATCHv4 " Jiri Olsa
2020-07-29  9:19 ` [PATCH 11/19] perf metric: Compute referenced metrics Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).