[PATCH 10/19] perf metric: Add referenced metrics to hash data

2020-07-29 Thread Jiri Olsa
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 
Reviewed-by: Kajol Jain 
Acked-by: Ian Rogers 
Cc: Alexander Shishkin 
Cc: Andi Kleen 
Cc: John Garry 
Cc: Michael Petlan 
Cc: Namhyung Kim 
Cc: Paul Clarke 
Cc: Peter Zijlstra 
Cc: Stephane Eranian 
Link: http://lore.kernel.org/lkml/20200719181320.785305-11-jo...@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo 
---
 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 
 #include 
 #include 
+#include "metricgroup.h"
+#include "debug.h"
 #include "expr.h"
 #include "expr-bison.h"
 #include "expr-flex.h"
 #include 
+#include 
+#include 
 
 #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(>ids, id, data_ptr,
   (const void **)_key, (void **)_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(>ids, name, data_ptr,
+  (const void **)_key, (void **)_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++) {
@@ 

Re: [PATCH 10/19] perf metric: Add referenced metrics to hash data

2020-07-28 Thread Arnaldo Carvalho de Melo
Em Sun, Jul 19, 2020 at 03:32:26PM -0700, Ian Rogers escreveu:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa  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 
> 
> Acked-by: Ian Rogers 

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 
> >  #include 
> >  #include 
> > +#include "metricgroup.h"
> > +#include "debug.h"
> >  #include "expr.h"
> >  #include "expr-bison.h"
> >  #include "expr-flex.h"
> >  #include 
> > +#include 
> > +#include 
> >
> >  #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(>ids, id, data_ptr,
> >(const void **)_key, (void **)_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(>ids, name, data_ptr,
> > +  (const void **)_key, (void **)_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,

Re: [PATCH 10/19] perf metric: Add referenced metrics to hash data

2020-07-26 Thread kajoljain



On 7/20/20 4:02 AM, Ian Rogers wrote:
> On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa  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 
> 
> Acked-by: Ian Rogers 

Reviewed-By : Kajol Jain

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 
>>  #include 
>>  #include 
>> +#include "metricgroup.h"
>> +#include "debug.h"
>>  #include "expr.h"
>>  #include "expr-bison.h"
>>  #include "expr-flex.h"
>>  #include 
>> +#include 
>> +#include 
>>
>>  #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(>ids, id, data_ptr,
>>(const void **)_key, (void **)_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(>ids, name, data_ptr,
>> +  (const void **)_key, (void **)_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,
>>  

Re: [PATCH 10/19] perf metric: Add referenced metrics to hash data

2020-07-19 Thread Ian Rogers
On Sun, Jul 19, 2020 at 11:14 AM Jiri Olsa  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 

Acked-by: Ian Rogers 

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 
>  #include 
>  #include 
> +#include "metricgroup.h"
> +#include "debug.h"
>  #include "expr.h"
>  #include "expr-bison.h"
>  #include "expr-flex.h"
>  #include 
> +#include 
> +#include 
>
>  #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(>ids, id, data_ptr,
>(const void **)_key, (void **)_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(>ids, name, data_ptr,
> +  (const void **)_key, (void **)_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;
>
> 

[PATCH 10/19] perf metric: Add referenced metrics to hash data

2020-07-19 Thread Jiri Olsa
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 
---
 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 
 #include 
 #include 
+#include "metricgroup.h"
+#include "debug.h"
 #include "expr.h"
 #include "expr-bison.h"
 #include "expr-flex.h"
 #include 
+#include 
+#include 
 
 #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(>ids, id, data_ptr,
   (const void **)_key, (void **)_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(>ids, name, data_ptr,
+  (const void **)_key, (void **)_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, _refs[j]);
+   if (ret)
+