diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index 3b4cdfc5efd6..5c15589522fd 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -7,6 +7,11 @@
#include <string.h>
#include <linux/stringify.h>
#include "header.h"
+#include "metricgroup.h"
+#include "evlist.h"
+#include <dirent.h>
+#include "pmu.h"
+#include <api/fs/fs.h>
#define mfspr(rn) ({unsigned long rval; \
asm volatile("mfspr %0," __stringify(rn) \@@ -16,6 +21,8 @@
#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
+#define SOCKETS_INFO_FILE_PATH "/devices/hv_24x7/interface/"
+
int
get_cpuid(char *buffer, size_t sz)
{@@ -44,3 +51,43 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
return bufp;
}
+
+int arch_get_runtimeparam(void)
+{
+ int count = 0;
+ DIR *dir;
+ char path[PATH_MAX];
+ const char *sysfs = sysfs__mountpoint();
+ char filename[] = "sockets";
+ FILE *file;
+ char buf[16], *num;
+ int data;
+
+ if (!sysfs)
+ goto out;
+
+ snprintf(path, PATH_MAX,
+ "%s" SOCKETS_INFO_FILE_PATH, sysfs);
+ dir = opendir(path);
+
+ if (!dir)
+ goto out;
+
+ strcat(path, filename);
+ file = fopen(path, "r");
+
+ if (!file)
+ goto out;
+
+ data = fread(buf, 1, sizeof(buf), file);
+
+ if (data == 0)
+ goto out;
+
+ count = strtol(buf, &num, 10);
+out:
+ if (!count)
+ count = 1;
+
+ return count;
+}diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 28a0a2dfbd8c..7f7c902bff46 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -15,6 +15,7 @@ struct parse_ctx {
struct parse_id ids[MAX_PARSE_ID];
};
+int expr__runtimeparam;
void expr__ctx_init(struct parse_ctx *ctx);
void expr__add_id(struct parse_ctx *ctx, const char *id, double val);
int expr__parse(double *final_val, struct parse_ctx *ctx, const char *expr);diff --git a/tools/perf/util/expr.l b/tools/perf/util/expr.l
index 1928f2a3dddc..2cc6fa4b1960 100644
--- a/tools/perf/util/expr.l
+++ b/tools/perf/util/expr.l
@@ -45,6 +45,20 @@ static char *normalize(char *str)
*dst++ = '/';
else if (*str == '\\')
*dst++ = *++str;
+ else if (*str == '?') {
+ int size = snprintf(NULL, 0, "%d", expr__runtimeparam);
+ char * paramval = (char *)malloc(size);
+ int i = 0;
+
+ if(!paramval)
+ *dst++ = '0';
+ else {
+ sprintf(paramval, "%d", expr__runtimeparam);
+ while(i < size)
+ *dst++ = paramval[i++];
+ free(paramval);
+ }
+ }
else
*dst++ = *str;
str++;@@ -72,8 +86,8 @@ number [0-9]+
sch [-,=]
spec \\{sch}
-sym [0-9a-zA-Z_\.:@]+
-symbol {spec}*{sym}*{spec}*{sym}*
+sym [0-9a-zA-Z_\.:@?]+
+symbol {spec}*{sym}*{spec}*{sym}*{spec}*{sym}
%%
{diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index 4720cbe79357..0f3ef0f37bf4 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -38,6 +38,8 @@
%type <num> expr if_expr
%{
+int expr__runtimeparam;
+
static void expr_error(double *final_val __maybe_unused,
struct parse_ctx *ctx __maybe_unused,
void *scanner,diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 02aee946b6c1..f629828cc0de 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -399,6 +399,11 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
strlist__delete(metriclist);
}
+int __weak arch_get_runtimeparam(void)
+{
+ return 1;
+}
+
static int metricgroup__add_metric(const char *metric, struct strbuf *events,
struct list_head *group_list)
{@@ -419,52 +424,77 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events,
continue;
if (match_metric(pe->metric_group, metric) ||
match_metric(pe->metric_name, metric)) {
- const char **ids;
- int idnum;
- struct egroup *eg;
- bool no_group = false;
+ int k, count;
+
+ if (strstr(pe->metric_expr, "?"))
+ count = arch_get_runtimeparam();
+ else
+ count = 1;
+
+ /* This loop is added to create multiple
+ * events depend on count value and add
+ * those events to group_list.
+ */
+ for (k = 0; k < count; k++) {
+ const char **ids;
+ int idnum;
+ struct egroup *eg;
+ bool no_group = false;
+ char value[PATH_MAX];
+
+ pr_debug("metric expr %s for %s\n",
+ pe->metric_expr, pe->metric_name);
+ expr__runtimeparam = k;
+ if (expr__find_other(pe->metric_expr, NULL,
+ &ids, &idnum) < 0)
+ continue;
+ if (events->len > 0)
+ strbuf_addf(events, ",");
+ for (j = 0; j < idnum; j++) {
+ pr_debug("found event %s\n", ids[j]);
+ /*
+ * Duration time maps to a software
+ * event and can make groups not count.
+ * Always use it outside a group.
+ */
+ if (!strcmp(ids[j], "duration_time")) {
+ if (j > 0)
+ strbuf_addf(events,
+ "}:W,");
+ strbuf_addf(events,
+ "duration_time");
+ no_group = true;
+ continue;
+ }
+ strbuf_addf(events, "%s%s",
+ j == 0 || no_group ? "{" :
+ ",", ids[j]);
+ no_group = false;
+ }
+ if (!no_group)
+ strbuf_addf(events, "}:W");
- pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
+ eg = malloc(sizeof(struct egroup));
+ if (!eg) {
+ ret = -ENOMEM;
+ break;
+ }
+ eg->ids = ids;
+ eg->idnum = idnum;
- if (expr__find_other(pe->metric_expr,
- NULL, &ids, &idnum) < 0)
- continue;
- if (events->len > 0)
- strbuf_addf(events, ",");
- for (j = 0; j < idnum; j++) {
- pr_debug("found event %s\n", ids[j]);
- /*
- * Duration time maps to a software event and can make
- * groups not count. Always use it outside a
- * group.
- */
- if (!strcmp(ids[j], "duration_time")) {
- if (j > 0)
- strbuf_addf(events, "}:W,");
- strbuf_addf(events, "duration_time");
- no_group = true;
- continue;
+ if (strstr(pe->metric_expr, "?")) {
+ sprintf(value, "%s%c%d",
+ pe->metric_name, '_', k);
+ } else {
+ strcpy(value, pe->metric_name);
}
- strbuf_addf(events, "%s%s",
- j == 0 || no_group ? "{" : ",",
- ids[j]);
- no_group = false;
- }
- if (!no_group)
- strbuf_addf(events, "}:W");
- eg = malloc(sizeof(struct egroup));
- if (!eg) {
- ret = -ENOMEM;
- break;
+ eg->metric_name = strdup(value);
+ eg->metric_expr = pe->metric_expr;
+ eg->metric_unit = pe->unit;
+ list_add_tail(&eg->nd, group_list);
+ ret = 0;
}
- eg->ids = ids;
- eg->idnum = idnum;
- eg->metric_name = pe->metric_name;
- eg->metric_expr = pe->metric_expr;
- eg->metric_unit = pe->unit;
- list_add_tail(&eg->nd, group_list);
- ret = 0;
}
}
return ret;diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 475c7f912864..81224ba1270d 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -34,4 +34,5 @@ int metricgroup__parse_groups(const struct option *opt,
void metricgroup__print(bool metrics, bool groups, char *filter,
bool raw, bool details);
bool metricgroup__has_metric(const char *metric);
+int arch_get_runtimeparam(void);
#endif
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 0fd713d3674f..c1179f7d2b23 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -777,6 +777,12 @@ static void generic_metric(struct perf_stat_config *config,
}
if (!metric_events[i]) {
+ if (strstr(metric_expr, "?")) {
+ char *tmp = strrchr(metric_name, '_');
+
+ tmp++;
+ expr__runtimeparam = strtol(tmp, &tmp, 10);
+ }
if (expr__parse(&ratio, &pctx, metric_expr) == 0) {
char *unit;
char metric_bf[64];--
2.21.0