* [PATCH 02/10] perf, tools, stat: Collapse identically named events
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 03/10] perf, tools: Factor out PMU matching in parser Andi Kleen
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
The uncore PMU has a lot of duplicated PMUs for different subsystems.
When expanding an uncore alias we usually end up with a large
number of identically named aliases, which makes perf stat
output difficult to read.
Automatically sum them up in perf stat, unless --no-merge is specified.
This can be default because only the uncores generally have duplicated
aliases. Other PMUs have unique names.
Before:
% perf stat --no-merge -a -e unc_c_llc_lookup.any sleep 1
Performance counter stats for 'system wide':
694,976 Bytes unc_c_llc_lookup.any
706,304 Bytes unc_c_llc_lookup.any
956,608 Bytes unc_c_llc_lookup.any
782,720 Bytes unc_c_llc_lookup.any
605,696 Bytes unc_c_llc_lookup.any
442,816 Bytes unc_c_llc_lookup.any
659,328 Bytes unc_c_llc_lookup.any
509,312 Bytes unc_c_llc_lookup.any
263,936 Bytes unc_c_llc_lookup.any
592,448 Bytes unc_c_llc_lookup.any
672,448 Bytes unc_c_llc_lookup.any
608,640 Bytes unc_c_llc_lookup.any
641,024 Bytes unc_c_llc_lookup.any
856,896 Bytes unc_c_llc_lookup.any
808,832 Bytes unc_c_llc_lookup.any
684,864 Bytes unc_c_llc_lookup.any
710,464 Bytes unc_c_llc_lookup.any
538,304 Bytes unc_c_llc_lookup.any
1.002577660 seconds time elapsed
After:
% perf stat -a -e unc_c_llc_lookup.any sleep 1
Performance counter stats for 'system wide':
2,685,120 Bytes unc_c_llc_lookup.any
1.002648032 seconds time elapsed
v2: Split collect_aliases. Rename alias flag.
v3: Make sure unsupported/not counted is always printed.
v4: Factor out callback change into separate patch.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/Documentation/perf-stat.txt | 3 +++
tools/perf/builtin-stat.c | 31 +++++++++++++++++++++++++++++++
tools/perf/util/evsel.h | 1 +
3 files changed, 35 insertions(+)
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index d96ccd4844df..320d8020bc5b 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -237,6 +237,9 @@ To interpret the results it is usually needed to know on which
CPUs the workload runs on. If needed the CPUs can be forced using
taskset.
+--no-merge::
+Do not merge results from same PMUs.
+
EXAMPLES
--------
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 43a7ef3d71ed..389c8e457bf0 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -140,6 +140,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */
static bool forever = false;
static bool metric_only = false;
static bool force_metric_only = false;
+static bool no_merge = false;
static struct timespec ref_time;
static struct cpu_map *aggr_map;
static aggr_get_id_t aggr_get_id;
@@ -1178,12 +1179,34 @@ static void aggr_update_shadow(void)
}
}
+static void collect_all_aliases(struct perf_evsel *counter,
+ void (*cb)(struct perf_evsel *counter, void *data,
+ bool first),
+ void *data)
+{
+ struct perf_evsel *alias;
+
+ alias = list_prepare_entry(counter, &(evsel_list->entries), node);
+ list_for_each_entry_continue (alias, &evsel_list->entries, node) {
+ if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
+ alias->scale != counter->scale ||
+ alias->cgrp != counter->cgrp ||
+ strcmp(alias->unit, counter->unit) ||
+ nsec_counter(alias) != nsec_counter(counter))
+ break;
+ alias->merged_stat = true;
+ cb(alias, data, false);
+ }
+}
+
static void collect_data(struct perf_evsel *counter,
void (*cb)(struct perf_evsel *counter, void *data,
bool first),
void *data)
{
cb(counter, data, true);
+ if (!no_merge)
+ collect_all_aliases(counter, cb, data);
}
struct aggr_data {
@@ -1250,6 +1273,8 @@ static void print_aggr(char *prefix)
ad.id = id = aggr_map->map[s];
first = true;
evlist__for_each_entry(evsel_list, counter) {
+ if (counter->merged_stat)
+ continue;
ad.val = ad.ena = ad.run = 0;
ad.nr = 0;
collect_data(counter, aggr_cb, &ad);
@@ -1325,6 +1350,8 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
double uval;
struct caggr_data cd = { .avg = 0.0 };
+ if (counter->merged_stat)
+ return;
collect_data(counter, counter_aggr_cb, &cd);
if (prefix && !metric_only)
@@ -1357,6 +1384,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
double uval;
int cpu;
+ if (counter->merged_stat)
+ return;
+
for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
struct aggr_data ad = { .cpu = cpu };
@@ -1701,6 +1731,7 @@ static const struct option stat_options[] = {
"list of cpus to monitor in system-wide"),
OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
"disable CPU count aggregation", AGGR_NONE),
+ OPT_BOOLEAN(0, "no-merge", &no_merge, "Do not merge identical named events"),
OPT_STRING('x', "field-separator", &csv_sep, "separator",
"print counts with custom separator"),
OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 06ef6f29efa1..bd2e9b112d49 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -131,6 +131,7 @@ struct perf_evsel {
bool cmdline_group_boundary;
struct list_head config_terms;
int bpf_fd;
+ bool merged_stat;
};
union u64_swap {
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/10] perf, tools: Factor out PMU matching in parser
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
2017-02-24 0:10 ` [PATCH 02/10] perf, tools, stat: Collapse identically named events Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-27 8:35 ` Jiri Olsa
2017-02-24 0:10 ` [PATCH 04/10] perf, tools: Expand PMU events by prefix match Andi Kleen
` (8 subsequent siblings)
10 siblings, 1 reply; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Factor out the PMU name matching in the event parser into a separate function,
to use the same code for other grammar rules later.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/util/parse-events.c | 46 ++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/parse-events.h | 5 +++++
tools/perf/util/parse-events.y | 30 +--------------------------
3 files changed, 52 insertions(+), 29 deletions(-)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 281e44af31e2..5563c47c92df 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1259,6 +1259,52 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
return evsel ? 0 : -ENOMEM;
}
+int parse_events_multi_pmu_add(struct parse_events_evlist *data,
+ char *str, struct list_head **listp)
+{
+ struct list_head *head;
+ struct parse_events_term *term;
+ struct list_head *list;
+ struct perf_pmu *pmu = NULL;
+ int ok = 0;
+
+ *listp = NULL;
+ /* Add it for all PMUs that support the alias */
+ list = malloc(sizeof(struct list_head));
+ if (!list)
+ return -1;
+ INIT_LIST_HEAD(list);
+ while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ struct perf_pmu_alias *alias;
+
+ list_for_each_entry(alias, &pmu->aliases, list) {
+ if (!strcasecmp(alias->name, str)) {
+ head = malloc(sizeof(struct list_head));
+ if (!head)
+ return -1;
+ INIT_LIST_HEAD(head);
+ if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+ str, 1, &str, NULL) < 0)
+ return -1;
+ list_add_tail(&term->list, head);
+
+ if (!parse_events_add_pmu(data, list,
+ pmu->name, head)) {
+ pr_debug("%s -> %s/%s/\n", str,
+ pmu->name, alias->str);
+ ok++;
+ }
+
+ parse_events_terms__delete(head);
+ }
+ }
+ }
+ if (!ok)
+ return -1;
+ *listp = list;
+ return 0;
+}
+
int parse_events__modifier_group(struct list_head *list,
char *event_mod)
{
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index da246a3ddb69..fb755ec248ab 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -164,6 +164,11 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
int parse_events_add_pmu(struct parse_events_evlist *data,
struct list_head *list, char *name,
struct list_head *head_config);
+
+int parse_events_multi_pmu_add(struct parse_events_evlist *data,
+ char *str,
+ struct list_head **listp);
+
enum perf_pmu_event_symbol_type
perf_pmu__parse_check(const char *name);
void parse_events__set_leader(char *name, struct list_head *list);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index a14b47ab3879..6b2bc918fc94 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -236,37 +236,9 @@ PE_NAME opt_event_config
|
PE_KERNEL_PMU_EVENT sep_dc
{
- struct parse_events_evlist *data = _data;
- struct list_head *head;
- struct parse_events_term *term;
struct list_head *list;
- struct perf_pmu *pmu = NULL;
- int ok = 0;
- /* Add it for all PMUs that support the alias */
- ALLOC_LIST(list);
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- struct perf_pmu_alias *alias;
-
- list_for_each_entry(alias, &pmu->aliases, list) {
- if (!strcasecmp(alias->name, $1)) {
- ALLOC_LIST(head);
- ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
- $1, 1, &@1, NULL));
- list_add_tail(&term->list, head);
-
- if (!parse_events_add_pmu(data, list,
- pmu->name, head)) {
- pr_debug("%s -> %s/%s/\n", $1,
- pmu->name, alias->str);
- ok++;
- }
-
- parse_events_terms__delete(head);
- }
- }
- }
- if (!ok)
+ if (parse_events_multi_pmu_add(_data, $1, &list) < 0)
YYABORT;
$$ = list;
}
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 03/10] perf, tools: Factor out PMU matching in parser
2017-02-24 0:10 ` [PATCH 03/10] perf, tools: Factor out PMU matching in parser Andi Kleen
@ 2017-02-27 8:35 ` Jiri Olsa
0 siblings, 0 replies; 15+ messages in thread
From: Jiri Olsa @ 2017-02-27 8:35 UTC (permalink / raw)
To: Andi Kleen; +Cc: acme, jolsa, linux-kernel, Andi Kleen
On Thu, Feb 23, 2017 at 04:10:14PM -0800, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
>
> Factor out the PMU name matching in the event parser into a separate function,
> to use the same code for other grammar rules later.
>
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
this will no longer apply because we changed the
parse_events_term__num interface..
jirka
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 04/10] perf, tools: Expand PMU events by prefix match
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
2017-02-24 0:10 ` [PATCH 02/10] perf, tools, stat: Collapse identically named events Andi Kleen
2017-02-24 0:10 ` [PATCH 03/10] perf, tools: Factor out PMU matching in parser Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 05/10] perf, tools: Special case uncore_ prefix Andi Kleen
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
When the user specifies a pmu directly, expand it automatically
with a prefix match for all available PMUs, similar as we do for
the normal aliases now.
This allows to specify attributes for duplicated boxes quickly.
For example uncore_cbox_{0,6}/.../ can be now specified as uncore_cbox/.../
and it gets automatically expanded for all boxes.
This generally makes it more concise to write uncore specifications, and
also avoids the need to know the exact topology of the system.
Before
% perf stat -a -e uncore_cbox_0/event=0x35,umask=0x1,filter_opc=0x19C/,\
uncore_cbox_1/event=0x35,umask=0x1,filter_opc=0x19C/,\
uncore_cbox_2/event=0x35,umask=0x1,filter_opc=0x19C/,\
uncore_cbox_3/event=0x35,umask=0x1,filter_opc=0x19C/,\
uncore_cbox_4/event=0x35,umask=0x1,filter_opc=0x19C/,\
uncore_cbox_5/event=0x35,umask=0x1,filter_opc=0x19C/ sleep 1
After
% perf stat -a -e uncore_cbox/event=0x35,umask=0x1,filter_opc=0x19C/ sleep 1
v2: Handle all bison rules. Move multi add code to separate function.
Handle uncore_ prefix correctly.
v3: Move parse_events_multi_pmu_add to separate patch. Move uncore
prefix check to separate patch.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/util/parse-events.c | 25 +++++++++++++++++++++++++
tools/perf/util/parse-events.h | 3 +++
tools/perf/util/parse-events.y | 40 ++++++++++++++++++++++++++--------------
3 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5563c47c92df..d693e2acbda7 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -2450,6 +2450,31 @@ int parse_events_term__clone(struct parse_events_term **new,
term->err_term, term->err_val);
}
+int parse_events_copy_term_list(struct list_head *old,
+ struct list_head **new)
+{
+ struct parse_events_term *term, *n;
+ int ret;
+
+ if (!old) {
+ *new = NULL;
+ return 0;
+ }
+
+ *new = malloc(sizeof(struct list_head));
+ if (!*new)
+ return -ENOMEM;
+ INIT_LIST_HEAD(*new);
+
+ list_for_each_entry (term, old, list) {
+ ret = parse_events_term__clone(&n, term);
+ if (ret)
+ return ret;
+ list_add_tail(&n->list, *new);
+ }
+ return 0;
+}
+
void parse_events_terms__purge(struct list_head *terms)
{
struct parse_events_term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index fb755ec248ab..33b3e52cd9b8 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -169,6 +169,9 @@ int parse_events_multi_pmu_add(struct parse_events_evlist *data,
char *str,
struct list_head **listp);
+int parse_events_copy_term_list(struct list_head *old,
+ struct list_head **new);
+
enum perf_pmu_event_symbol_type
perf_pmu__parse_check(const char *name);
void parse_events__set_leader(char *name, struct list_head *list);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 6b2bc918fc94..3209f18cd5d8 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -226,11 +226,32 @@ event_pmu:
PE_NAME opt_event_config
{
struct parse_events_evlist *data = _data;
- struct list_head *list;
+ struct list_head *list, *orig_terms, *terms;
+
+ if (parse_events_copy_term_list($2, &orig_terms))
+ YYABORT;
ALLOC_LIST(list);
- ABORT_ON(parse_events_add_pmu(data, list, $1, $2));
+ if (parse_events_add_pmu(data, list, $1, $2)) {
+ struct perf_pmu *pmu = NULL;
+ int ok = 0;
+
+ while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ char *name = pmu->name;
+
+ if (!strncmp($1, name, strlen($1))) {
+ if (parse_events_copy_term_list(orig_terms, &terms))
+ YYABORT;
+ if (!parse_events_add_pmu(data, list, pmu->name, terms))
+ ok++;
+ parse_events_terms__delete(terms);
+ }
+ }
+ if (!ok)
+ YYABORT;
+ }
parse_events_terms__delete($2);
+ parse_events_terms__delete(orig_terms);
$$ = list;
}
|
@@ -245,21 +266,12 @@ PE_KERNEL_PMU_EVENT sep_dc
|
PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
{
- struct parse_events_evlist *data = _data;
- struct list_head *head;
- struct parse_events_term *term;
struct list_head *list;
char pmu_name[128];
- snprintf(&pmu_name, 128, "%s-%s", $1, $3);
- ALLOC_LIST(head);
- ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
- &pmu_name, 1, &@1, NULL));
- list_add_tail(&term->list, head);
-
- ALLOC_LIST(list);
- ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
- parse_events_terms__delete(head);
+ snprintf(&pmu_name, 128, "%s-%s", $1, $3);
+ if (parse_events_multi_pmu_add(_data, pmu_name, &list) < 0)
+ YYABORT;
$$ = list;
}
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/10] perf, tools: Special case uncore_ prefix
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (2 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 04/10] perf, tools: Expand PMU events by prefix match Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 06/10] perf, tools: Add a simple expression parser for JSON Andi Kleen
` (6 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Special case uncore_ prefix in PMU match, to allow for shorter event
uncore specifications.
Before
perf stat -a -e uncore_cbox/event=0x35,umask=0x1,filter_opc=0x19C/ sleep 1
After
perf stat -a -e cbox/event=0x35,umask=0x1,filter_opc=0x19C/ sleep 1
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/util/parse-events.y | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 3209f18cd5d8..eed371b971a8 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -239,6 +239,9 @@ PE_NAME opt_event_config
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
char *name = pmu->name;
+ if (!strncmp(name, "uncore_", 7) &&
+ strncmp($1, "uncore_", 7))
+ name += 7;
if (!strncmp($1, name, strlen($1))) {
if (parse_events_copy_term_list(orig_terms, &terms))
YYABORT;
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/10] perf, tools: Add a simple expression parser for JSON
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (3 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 05/10] perf, tools: Special case uncore_ prefix Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 07/10] perf, tools: Support MetricExpr header in JSON event list Andi Kleen
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Add a simple expression parser good enough to parse JSON relation
expressions. The parser is implemented using bison.
v2: Use expr__ prefix instead of expr_
Support multiple free variables for parser
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/tests/Build | 1 +
tools/perf/tests/builtin-test.c | 4 +
tools/perf/tests/expr.c | 55 +++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/util/Build | 5 ++
tools/perf/util/expr.h | 25 ++++++
tools/perf/util/expr.y | 173 ++++++++++++++++++++++++++++++++++++++++
7 files changed, 264 insertions(+)
create mode 100644 tools/perf/tests/expr.c
create mode 100644 tools/perf/util/expr.h
create mode 100644 tools/perf/util/expr.y
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 1cb3d9b540e9..af58ebc243ef 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -38,6 +38,7 @@ perf-y += cpumap.o
perf-y += stat.o
perf-y += event_update.o
perf-y += event-times.o
+perf-y += expr.o
perf-y += backward-ring-buffer.o
perf-y += sdt.o
perf-y += is_printable_array.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 37e326bfd2dc..db03e853ba7f 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -44,6 +44,10 @@ static struct test generic_tests[] = {
.func = test__parse_events,
},
{
+ .desc = "Simple expression parser",
+ .func = test__expr,
+ },
+ {
.desc = "PERF_RECORD_* events & perf_sample fields",
.func = test__PERF_RECORD,
},
diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c
new file mode 100644
index 000000000000..554695c06c5b
--- /dev/null
+++ b/tools/perf/tests/expr.c
@@ -0,0 +1,55 @@
+#include "util/debug.h"
+#include "util/expr.h"
+#include "tests.h"
+
+static int test(struct parse_ctx *ctx, const char *e, double val2)
+{
+ double val;
+
+ if (expr__parse(&val, ctx, &e))
+ TEST_ASSERT_VAL("parse test failed", 0);
+ TEST_ASSERT_VAL("unexpected value", val == val2);
+ return 0;
+}
+
+int test__expr(int subtest __maybe_unused)
+{
+ const char *p;
+ const char **other;
+ double val;
+ int ret;
+ struct parse_ctx ctx;
+ int num_other;
+
+ expr__ctx_init(&ctx);
+ expr__add_id(&ctx, "FOO", 1);
+ expr__add_id(&ctx, "BAR", 2);
+
+ ret = test(&ctx, "1+1", 2);
+ ret |= test(&ctx, "FOO+BAR", 3);
+ ret |= test(&ctx, "(BAR/2)%2", 1);
+ ret |= test(&ctx, "1 - -4", 5);
+ ret |= test(&ctx, "(FOO-1)*2 + (BAR/2)%2 - -4", 5);
+
+ if (ret)
+ return ret;
+
+ p = "FOO/0";
+ ret = expr__parse(&val, &ctx, &p);
+ TEST_ASSERT_VAL("division by zero", ret == 1);
+
+ p = "BAR/";
+ ret = expr__parse(&val, &ctx, &p);
+ TEST_ASSERT_VAL("missing operand", ret == 1);
+
+ TEST_ASSERT_VAL("find other",
+ expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", &other, &num_other) == 0);
+ TEST_ASSERT_VAL("find other", num_other == 3);
+ TEST_ASSERT_VAL("find other", !strcmp(other[0], "BAR"));
+ TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ"));
+ TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO"));
+ TEST_ASSERT_VAL("find other", other[3] == NULL);
+ free((void *)other);
+
+ return 0;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 1fa9b9d83aa5..631859629403 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -62,6 +62,7 @@ int test__sample_parsing(int subtest);
int test__keep_tracking(int subtest);
int test__parse_no_sample_id_all(int subtest);
int test__dwarf_unwind(int subtest);
+int test__expr(int subtest);
int test__hists_filter(int subtest);
int test__mmap_thread_lookup(int subtest);
int test__thread_mg_share(int subtest);
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5da376bc1afc..3dff5f5960d9 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -88,6 +88,7 @@ libperf-y += mem-events.o
libperf-y += vsprintf.o
libperf-y += drv_configs.o
libperf-y += time-utils.o
+libperf-y += expr-bison.o
libperf-$(CONFIG_LIBBPF) += bpf-loader.o
libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -140,6 +141,10 @@ $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
$(call rule_mkdir)
$(Q)$(call echo-cmd,bison)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $@ -p parse_events_
+$(OUTPUT)util/expr-bison.c: util/expr.y
+ $(call rule_mkdir)
+ $(Q)$(call echo-cmd,bison)$(BISON) -v util/expr.y -d $(PARSER_DEBUG_BISON) -o $@ -p expr__
+
$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
$(call rule_mkdir)
$(Q)$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
new file mode 100644
index 000000000000..9c2760a1a96e
--- /dev/null
+++ b/tools/perf/util/expr.h
@@ -0,0 +1,25 @@
+#ifndef PARSE_CTX_H
+#define PARSE_CTX_H 1
+
+#define EXPR_MAX_OTHER 8
+#define MAX_PARSE_ID EXPR_MAX_OTHER
+
+struct parse_id {
+ const char *name;
+ double val;
+};
+
+struct parse_ctx {
+ int num_ids;
+ struct parse_id ids[MAX_PARSE_ID];
+};
+
+void expr__ctx_init(struct parse_ctx *ctx);
+void expr__add_id(struct parse_ctx *ctx, const char *id, double val);
+#ifndef IN_EXPR_Y
+int expr__parse(double *final_val, struct parse_ctx *ctx, const char **pp);
+#endif
+int expr__find_other(const char *p, const char *one, const char ***other,
+ int *num_other);
+
+#endif
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
new file mode 100644
index 000000000000..a8daa7a93605
--- /dev/null
+++ b/tools/perf/util/expr.y
@@ -0,0 +1,173 @@
+/* Simple expression parser */
+%{
+#include "util.h"
+#include "util/debug.h"
+#define IN_EXPR_Y 1
+#include "expr.h"
+#include <string.h>
+
+#define MAXIDLEN 256
+%}
+
+%define api.pure full
+%parse-param { double *final_val }
+%parse-param { struct parse_ctx *ctx }
+%parse-param { const char **pp }
+%lex-param { const char **pp }
+
+%union {
+ double num;
+ char id[MAXIDLEN+1];
+}
+
+%token <num> NUMBER
+%token <id> ID
+%left '|'
+%left '^'
+%left '&'
+%left '-' '+'
+%left '*' '/' '%'
+%left NEG NOT
+%type <num> expr
+
+%{
+static int expr__lex(YYSTYPE *res, const char **pp);
+
+static void expr__error(double *final_val __maybe_unused,
+ struct parse_ctx *ctx __maybe_unused,
+ const char **pp __maybe_unused,
+ const char *s)
+{
+ pr_debug("%s\n", s);
+}
+
+static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
+{
+ int i;
+
+ for (i = 0; i < ctx->num_ids; i++) {
+ if (!strcasecmp(ctx->ids[i].name, id)) {
+ *val = ctx->ids[i].val;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+%}
+%%
+
+all_expr: expr { *final_val = $1; }
+ ;
+
+expr: NUMBER
+ | ID { if (lookup_id(ctx, $1, &$$) < 0) {
+ pr_debug("%s not found", $1);
+ YYABORT;
+ }
+ }
+ | expr '+' expr { $$ = $1 + $3; }
+ | expr '-' expr { $$ = $1 - $3; }
+ | expr '*' expr { $$ = $1 * $3; }
+ | expr '/' expr { if ($3 == 0) YYABORT; $$ = $1 / $3; }
+ | expr '%' expr { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; }
+ | '-' expr %prec NEG { $$ = -$2; }
+ | '(' expr ')' { $$ = $2; }
+ ;
+
+%%
+
+static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
+{
+ char *dst = res->id;
+ const char *s = p;
+
+ while (isalnum(*p) || *p == '_' || *p == '.') {
+ if (p - s >= MAXIDLEN)
+ return -1;
+ *dst++ = *p++;
+ }
+ *dst = 0;
+ *pp = p;
+ return ID;
+}
+
+static int expr__lex(YYSTYPE *res, const char **pp)
+{
+ int tok;
+ const char *s;
+ const char *p = *pp;
+
+ while (isspace(*p))
+ p++;
+ s = p;
+ switch (*p++) {
+ case 'a' ... 'z':
+ case 'A' ... 'Z':
+ return expr__symbol(res, p - 1, pp);
+ case '0' ... '9': case '.':
+ res->num = strtod(s, (char **)&p);
+ tok = NUMBER;
+ break;
+ default:
+ tok = *s;
+ break;
+ }
+ *pp = p;
+ return tok;
+}
+
+/* Caller must make sure id is allocated */
+void expr__add_id(struct parse_ctx *ctx, const char *name, double val)
+{
+ int idx;
+ assert(ctx->num_ids < MAX_PARSE_ID);
+ idx = ctx->num_ids++;
+ ctx->ids[idx].name = name;
+ ctx->ids[idx].val = val;
+}
+
+void expr__ctx_init(struct parse_ctx *ctx)
+{
+ ctx->num_ids = 0;
+}
+
+int expr__find_other(const char *p, const char *one, const char ***other,
+ int *num_otherp)
+{
+ const char *orig = p;
+ int err = -1;
+ int num_other;
+
+ *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *));
+ if (!*other)
+ return -1;
+
+ num_other = 0;
+ for (;;) {
+ YYSTYPE val;
+ int tok = expr__lex(&val, &p);
+ if (tok == 0) {
+ err = 0;
+ break;
+ }
+ if (tok == ID && strcasecmp(one, val.id)) {
+ if (num_other >= EXPR_MAX_OTHER - 1) {
+ pr_debug("Too many extra events in %s\n", orig);
+ break;
+ }
+ (*other)[num_other] = strdup(val.id);
+ if (!(*other)[num_other])
+ return -1;
+ num_other++;
+ }
+ }
+ (*other)[num_other] = NULL;
+ *num_otherp = num_other;
+ if (err) {
+ *num_otherp = 0;
+ free(*other);
+ *other = NULL;
+ }
+ return err;
+}
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/10] perf, tools: Support MetricExpr header in JSON event list
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (4 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 06/10] perf, tools: Add a simple expression parser for JSON Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 08/10] perf, tools, stat: Output JSON MetricExpr metric Andi Kleen
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Add support for parsing the MetricExpr header in the JSON event lists and
storing them in the alias structure.
Used in the next patch.
v2: Change DividedBy to MetricExpr
v3: Really catch all uses of DividedBy
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/pmu-events/jevents.c | 18 ++++++++++++++----
tools/perf/pmu-events/jevents.h | 2 +-
tools/perf/pmu-events/pmu-events.h | 1 +
tools/perf/util/pmu.c | 9 ++++++---
tools/perf/util/pmu.h | 1 +
5 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index eed09346a72a..0735dc2a167a 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -291,7 +291,8 @@ static void print_events_table_prefix(FILE *fp, const char *tblname)
static int print_events_table_entry(void *data, char *name, char *event,
char *desc, char *long_desc,
- char *pmu, char *unit, char *perpkg)
+ char *pmu, char *unit, char *perpkg,
+ char *metric_expr)
{
struct perf_entry_data *pd = data;
FILE *outfp = pd->outfp;
@@ -315,6 +316,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
fprintf(outfp, "\t.unit = \"%s\",\n", unit);
if (perpkg)
fprintf(outfp, "\t.perpkg = \"%s\",\n", perpkg);
+ if (metric_expr)
+ fprintf(outfp, "\t.metric_expr = \"%s\",\n", metric_expr);
fprintf(outfp, "},\n");
return 0;
@@ -362,7 +365,8 @@ static char *real_event(const char *name, char *event)
int json_events(const char *fn,
int (*func)(void *data, char *name, char *event, char *desc,
char *long_desc,
- char *pmu, char *unit, char *perpkg),
+ char *pmu, char *unit, char *perpkg,
+ char *metric_expr),
void *data)
{
int err = -EIO;
@@ -388,6 +392,7 @@ int json_events(const char *fn,
char *filter = NULL;
char *perpkg = NULL;
char *unit = NULL;
+ char *metric_expr = NULL;
unsigned long long eventcode = 0;
struct msrmap *msr = NULL;
jsmntok_t *msrval = NULL;
@@ -398,6 +403,7 @@ int json_events(const char *fn,
for (j = 0; j < obj->size; j += 2) {
jsmntok_t *field, *val;
int nz;
+ char *s;
field = tok + j;
EXPECT(field->type == JSMN_STRING, tok + j,
@@ -444,7 +450,6 @@ int json_events(const char *fn,
NULL);
} else if (json_streq(map, field, "Unit")) {
const char *ppmu;
- char *s;
ppmu = field_to_perf(unit_to_pmu, map, val);
if (ppmu) {
@@ -464,6 +469,10 @@ int json_events(const char *fn,
addfield(map, &unit, "", "", val);
} else if (json_streq(map, field, "PerPkg")) {
addfield(map, &perpkg, "", "", val);
+ } else if (json_streq(map, field, "MetricExpr")) {
+ addfield(map, &metric_expr, "", "", val);
+ for (s = metric_expr; *s; s++)
+ *s = tolower(*s);
}
/* ignore unknown fields */
}
@@ -488,7 +497,7 @@ int json_events(const char *fn,
fixname(name);
err = func(data, name, real_event(name, event), desc, long_desc,
- pmu, unit, perpkg);
+ pmu, unit, perpkg, metric_expr);
free(event);
free(desc);
free(name);
@@ -498,6 +507,7 @@ int json_events(const char *fn,
free(filter);
free(perpkg);
free(unit);
+ free(metric_expr);
if (err)
break;
tok += j;
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
index 71e13de31092..57e111bf2168 100644
--- a/tools/perf/pmu-events/jevents.h
+++ b/tools/perf/pmu-events/jevents.h
@@ -5,7 +5,7 @@ int json_events(const char *fn,
int (*func)(void *data, char *name, char *event, char *desc,
char *long_desc,
char *pmu,
- char *unit, char *perpkg),
+ char *unit, char *perpkg, char *metric_expr),
void *data);
char *get_cpu_str(void);
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index c669a3cdb9f0..d046e3a4ce46 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -13,6 +13,7 @@ struct pmu_event {
const char *pmu;
const char *unit;
const char *perpkg;
+ const char *metric_expr;
};
/*
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 49bfee0e3d9e..0583e1bdc762 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -231,7 +231,8 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
char *desc, char *val,
char *long_desc, char *topic,
- char *unit, char *perpkg)
+ char *unit, char *perpkg,
+ char *metric_expr)
{
struct perf_pmu_alias *alias;
int ret;
@@ -265,6 +266,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
perf_pmu__parse_snapshot(alias, dir, name);
}
+ alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
alias->desc = desc ? strdup(desc) : NULL;
alias->long_desc = long_desc ? strdup(long_desc) :
desc ? strdup(desc) : NULL;
@@ -294,7 +296,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
buf[ret] = 0;
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
- NULL);
+ NULL, NULL);
}
static inline bool pmu_alias_info_file(char *name)
@@ -564,7 +566,8 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
__perf_pmu__new_alias(head, NULL, (char *)pe->name,
(char *)pe->desc, (char *)pe->event,
(char *)pe->long_desc, (char *)pe->topic,
- (char *)pe->unit, (char *)pe->perpkg);
+ (char *)pe->unit, (char *)pe->perpkg,
+ (char *)pe->metric_expr);
}
out:
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 00852ddc7741..3dccb15f29e9 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -50,6 +50,7 @@ struct perf_pmu_alias {
double scale;
bool per_pkg;
bool snapshot;
+ char *metric_expr;
};
struct perf_pmu *perf_pmu__find(const char *name);
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/10] perf, tools, stat: Output JSON MetricExpr metric
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (5 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 07/10] perf, tools: Support MetricExpr header in JSON event list Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 09/10] perf, tools, list: Support printing MetricExpr with -v Andi Kleen
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Add generic infrastructure to perf stat to output ratios for "MetricExpr"
entries in the event lists. Many events are more useful as ratios
than in raw form, typically some count in relation to total ticks.
Transfer the MetricExpr information from the alias to the evsel.
We mark the events that need to be collected for MetricExpr, and also
link the events using them with a pointer. The code is careful
to always prefer the right event in the same group to minimize
multiplexing errors. At the moment only a single relation is supported.
Then add a rblist to the stat shadow code that remembers stats based
on the cpu and context.
Then finally update and retrieve and print these values similarly to the
existing hardcoded perf metrics. We use the simple expression parser
added earlier to evaluate the expression.
Normally we just output the result without further commentary,
but for --metric-only this would lead to empty columns. So for this
case use the original event as description.
So far there is no attempt to automatically add the MetricExpr event,
if it is missing, however we suggest it to the user.
$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}'
1.000228813 800,139,950 unc_p_clockticks
1.000228813 789,833,783 unc_p_freq_max_os_cycles # 98.7
2.000654229 800,308,990 unc_p_clockticks
2.000654229 396,214,238 unc_p_freq_max_os_cycles # 49.5
$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}' --metric-only
1.000206740 48.0
2.000451543 48.1
v2: Change from DivideBy to MetricExpr
v3: Use expr__ prefix. Support more than one other event.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-stat.c | 3 +
tools/perf/util/evsel.c | 3 +
tools/perf/util/evsel.h | 3 +
tools/perf/util/parse-events.c | 1 +
tools/perf/util/pmu.c | 2 +
tools/perf/util/pmu.h | 1 +
tools/perf/util/stat-shadow.c | 188 +++++++++++++++++++++++++++++++++++++++++
tools/perf/util/stat.h | 2 +
8 files changed, 203 insertions(+)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 389c8e457bf0..a6cc5ad479b9 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1141,6 +1141,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
out.print_metric = pm;
out.new_line = nl;
out.ctx = &os;
+ out.force_header = false;
if (csv_output && !metric_only) {
print_noise(counter, noise);
@@ -1478,6 +1479,7 @@ static void print_metric_headers(const char *prefix, bool no_indent)
out.ctx = &os;
out.print_metric = print_metric_header;
out.new_line = new_line_metric;
+ out.force_header = true;
os.evsel = counter;
perf_stat__print_shadow_stats(counter, 0,
0,
@@ -2460,6 +2462,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
(const char **) stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
+ perf_stat__collect_metric_expr(evsel_list);
perf_stat__init_shadow_stats();
if (csv_sep) {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ac59710b79e0..a25dc688ab74 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -236,6 +236,9 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
perf_evsel__calc_id_pos(evsel);
evsel->cmdline_group_boundary = false;
+ evsel->metric_expr = NULL;
+ evsel->metric_events = NULL;
+ evsel->collect_stat = false;
}
struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index bd2e9b112d49..8f1f61826fdf 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -132,6 +132,9 @@ struct perf_evsel {
struct list_head config_terms;
int bpf_fd;
bool merged_stat;
+ const char * metric_expr;
+ struct perf_evsel **metric_events;
+ bool collect_stat;
};
union u64_swap {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d693e2acbda7..fcb0b6854642 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1254,6 +1254,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
evsel->scale = info.scale;
evsel->per_pkg = info.per_pkg;
evsel->snapshot = info.snapshot;
+ evsel->metric_expr = info.metric_expr;
}
return evsel ? 0 : -ENOMEM;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 0583e1bdc762..4d9632390ab1 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -985,6 +985,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
info->unit = NULL;
info->scale = 0.0;
info->snapshot = false;
+ info->metric_expr = NULL;
list_for_each_entry_safe(term, h, head_terms, list) {
alias = pmu_find_alias(pmu, term);
@@ -1000,6 +1001,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
if (alias->per_pkg)
info->per_pkg = true;
+ info->metric_expr = alias->metric_expr;
list_del(&term->list);
free(term);
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 3dccb15f29e9..27f078ccc594 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -31,6 +31,7 @@ struct perf_pmu {
struct perf_pmu_info {
const char *unit;
+ const char *metric_expr;
double scale;
bool per_pkg;
bool snapshot;
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 8a2bbd2a4d82..e8e76744fa32 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -3,6 +3,9 @@
#include "stat.h"
#include "color.h"
#include "pmu.h"
+#include "rblist.h"
+#include "evlist.h"
+#include "expr.h"
enum {
CTX_BIT_USER = 1 << 0,
@@ -41,13 +44,73 @@ static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS];
static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS];
static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS];
static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS];
+static struct rblist runtime_saved_values;
static bool have_frontend_stalled;
struct stats walltime_nsecs_stats;
+struct saved_value {
+ struct rb_node rb_node;
+ struct perf_evsel *evsel;
+ int cpu;
+ int ctx;
+ struct stats stats;
+};
+
+static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
+{
+ struct saved_value *a = container_of(rb_node,
+ struct saved_value,
+ rb_node);
+ const struct saved_value *b = entry;
+
+ if (a->ctx != b->ctx)
+ return a->ctx - b->ctx;
+ if (a->cpu != b->cpu)
+ return a->cpu - b->cpu;
+ return a->evsel - b->evsel;
+}
+
+static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
+ const void *entry)
+{
+ struct saved_value *nd = malloc(sizeof(struct saved_value));
+
+ if (!nd)
+ return NULL;
+ memcpy(nd, entry, sizeof(struct saved_value));
+ return &nd->rb_node;
+}
+
+static struct saved_value *saved_value_lookup(struct perf_evsel *evsel,
+ int cpu, int ctx,
+ bool create)
+{
+ struct rb_node *nd;
+ struct saved_value dm = {
+ .cpu = cpu,
+ .ctx = ctx,
+ .evsel = evsel,
+ };
+ nd = rblist__find(&runtime_saved_values, &dm);
+ if (nd)
+ return container_of(nd, struct saved_value, rb_node);
+ if (create) {
+ rblist__add_node(&runtime_saved_values, &dm);
+ nd = rblist__find(&runtime_saved_values, &dm);
+ if (nd)
+ return container_of(nd, struct saved_value, rb_node);
+ }
+ return NULL;
+}
+
void perf_stat__init_shadow_stats(void)
{
have_frontend_stalled = pmu_have_event("cpu", "stalled-cycles-frontend");
+ rblist__init(&runtime_saved_values);
+ runtime_saved_values.node_cmp = saved_value_cmp;
+ runtime_saved_values.node_new = saved_value_new;
+ /* No delete for now */
}
static int evsel_context(struct perf_evsel *evsel)
@@ -70,6 +133,8 @@ static int evsel_context(struct perf_evsel *evsel)
void perf_stat__reset_shadow_stats(void)
{
+ struct rb_node *pos, *next;
+
memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats));
memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats));
memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats));
@@ -92,6 +157,15 @@ void perf_stat__reset_shadow_stats(void)
memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued));
memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles));
memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles));
+
+ next = rb_first(&runtime_saved_values.entries);
+ while (next) {
+ pos = next;
+ next = rb_next(pos);
+ memset(&container_of(pos, struct saved_value, rb_node)->stats,
+ 0,
+ sizeof(struct stats));
+ }
}
/*
@@ -143,6 +217,12 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]);
else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]);
+
+ if (counter->collect_stat) {
+ struct saved_value *v = saved_value_lookup(counter, cpu, ctx,
+ true);
+ update_stats(&v->stats, count[0]);
+ }
}
/* used for get_ratio_color() */
@@ -172,6 +252,88 @@ static const char *get_ratio_color(enum grc_type type, double ratio)
return color;
}
+static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list,
+ const char *name)
+{
+ struct perf_evsel *c2;
+
+ evlist__for_each_entry (evsel_list, c2) {
+ if (!strcasecmp(c2->name, name))
+ return c2;
+ }
+ return NULL;
+}
+
+/* Mark MetricExpr target events and link events using them to them. */
+void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list)
+{
+ struct perf_evsel *counter, *leader, **metric_events, *oc;
+ bool found;
+ const char **metric_names;
+ int i;
+ int num_metric_names;
+
+ evlist__for_each_entry(evsel_list, counter) {
+ bool invalid = false;
+
+ leader = counter->leader;
+ if (!counter->metric_expr)
+ continue;
+ metric_events = counter->metric_events;
+ if (!metric_events) {
+ if (expr__find_other(counter->metric_expr, counter->name,
+ &metric_names, &num_metric_names) < 0)
+ continue;
+
+ metric_events = calloc(sizeof(struct perf_evsel *),
+ num_metric_names + 1);
+ if (!metric_events)
+ return;
+ counter->metric_events = metric_events;
+ }
+
+ for (i = 0; i < num_metric_names; i++) {
+ found = false;
+ if (leader) {
+ /* Search in group */
+ for_each_group_member (oc, leader) {
+ if (!strcasecmp(oc->name, metric_names[i])) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ /* Search ignoring groups */
+ oc = perf_stat__find_event(evsel_list, metric_names[i]);
+ }
+ if (!oc) {
+ /*
+ * Adding events automatically would be difficult, because
+ * it would risk creating groups that are not schedulable.
+ * perf stat doesn't understand all the scheduling constraints
+ * of events. So we ask the user instead to add the missing
+ * events.
+ */
+ fprintf(stderr, "Add %s event to groups to get metric expression for %s\n",
+ metric_names[i],
+ counter->name);
+ invalid = true;
+ continue;
+ }
+ metric_events[i] = oc;
+ oc->collect_stat = true;
+ }
+ metric_events[i] = NULL;
+ free(metric_names);
+ if (invalid) {
+ free(metric_events);
+ counter->metric_events = NULL;
+ counter->metric_expr = NULL;
+ }
+ }
+}
+
static void print_stalled_cycles_frontend(int cpu,
struct perf_evsel *evsel, double avg,
struct perf_stat_output_ctx *out)
@@ -614,6 +776,32 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
be_bound * 100.);
else
print_metric(ctxp, NULL, NULL, name, 0);
+ } else if (evsel->metric_expr) {
+ struct parse_ctx pctx;
+ int i;
+
+ expr__ctx_init(&pctx);
+ expr__add_id(&pctx, evsel->name, avg);
+ for (i = 0; evsel->metric_events[i]; i++) {
+ struct saved_value *v;
+
+ v = saved_value_lookup(evsel->metric_events[i], cpu, ctx, false);
+ if (!v)
+ break;
+ expr__add_id(&pctx, evsel->metric_events[i]->name,
+ avg_stats(&v->stats));
+ }
+ if (!evsel->metric_events[i]) {
+ const char *p = evsel->metric_expr;
+
+ if (expr__parse(&ratio, &pctx, &p) == 0)
+ print_metric(ctxp, NULL, "%8.1f",
+ out->force_header ? evsel->name : "",
+ ratio);
+ else
+ print_metric(ctxp, NULL, NULL, "", 0);
+ } else
+ print_metric(ctxp, NULL, NULL, "", 0);
} else if (runtime_nsecs_stats[cpu].n != 0) {
char unit = 'M';
char unit_buf[10];
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index c29bb94c48a4..0a65ae23f495 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -85,11 +85,13 @@ struct perf_stat_output_ctx {
void *ctx;
print_metric_t print_metric;
new_line_t new_line;
+ bool force_header;
};
void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
double avg, int cpu,
struct perf_stat_output_ctx *out);
+void perf_stat__collect_metric_expr(struct perf_evlist *);
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
void perf_evlist__free_stats(struct perf_evlist *evlist);
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/10] perf, tools, list: Support printing MetricExpr with -v
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (6 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 08/10] perf, tools, stat: Output JSON MetricExpr metric Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 0:10 ` [PATCH 10/10] perf, tools: Add support for MetricName JSON attribute Andi Kleen
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Output the metric expr in perf list when -v is specified, so that the user
can check the formula.
Before:
% perf list -v
...
unc_m_power_channel_ppd
[Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd. Unit:
uncore_imc]
uncore_imc_2/event=0x85/
After:
% perf list -v
...
unc_m_power_channel_ppd
[Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd. Unit:
uncore_imc]
Perf: uncore_imc_2/event=0x85/ MetricExpr: (unc_m_power_channel_ppd / unc_m_clockticks) * 100.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/util/pmu.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 4d9632390ab1..2cb463ababb8 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1096,6 +1096,7 @@ struct sevent {
char *topic;
char *str;
char *pmu;
+ char *metric_expr;
};
static int cmp_sevent(const void *a, const void *b)
@@ -1194,6 +1195,7 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
aliases[j].topic = alias->topic;
aliases[j].str = alias->str;
aliases[j].pmu = pmu->name;
+ aliases[j].metric_expr = alias->metric_expr;
j++;
}
if (pmu->selectable &&
@@ -1228,8 +1230,12 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
printf("%*s", 8, "[");
wordwrap(aliases[j].desc, 8, columns, 0);
printf("]\n");
- if (verbose)
- printf("%*s%s/%s/\n", 8, "", aliases[j].pmu, aliases[j].str);
+ if (verbose) {
+ printf("%*sPerf: %s/%s/", 8, "", aliases[j].pmu, aliases[j].str);
+ if (aliases[j].metric_expr)
+ printf(" MetricExpr: %s", aliases[j].metric_expr);
+ putchar('\n');
+ }
} else
printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
printed++;
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/10] perf, tools: Add support for MetricName JSON attribute
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (7 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 09/10] perf, tools, list: Support printing MetricExpr with -v Andi Kleen
@ 2017-02-24 0:10 ` Andi Kleen
2017-02-24 8:37 ` [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Jiri Olsa
2017-02-26 23:28 ` Jiri Olsa
10 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 0:10 UTC (permalink / raw)
To: acme; +Cc: jolsa, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Add support for a new JSON event attribute to name MetricExpr for better output
in perf stat.
If the event has no MetricName it uses the normal event name instead to describe
the metric.
So far no names are added.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/pmu-events/jevents.c | 14 +++++++++++---
tools/perf/pmu-events/jevents.h | 3 ++-
tools/perf/pmu-events/pmu-events.h | 1 +
tools/perf/util/evsel.c | 1 +
tools/perf/util/evsel.h | 1 +
tools/perf/util/parse-events.c | 1 +
tools/perf/util/pmu.c | 15 ++++++++++++---
tools/perf/util/pmu.h | 2 ++
tools/perf/util/stat-shadow.c | 4 +++-
9 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index 0735dc2a167a..81f2ef3b15cf 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -292,7 +292,8 @@ static void print_events_table_prefix(FILE *fp, const char *tblname)
static int print_events_table_entry(void *data, char *name, char *event,
char *desc, char *long_desc,
char *pmu, char *unit, char *perpkg,
- char *metric_expr)
+ char *metric_expr,
+ char *metric_name)
{
struct perf_entry_data *pd = data;
FILE *outfp = pd->outfp;
@@ -318,6 +319,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
fprintf(outfp, "\t.perpkg = \"%s\",\n", perpkg);
if (metric_expr)
fprintf(outfp, "\t.metric_expr = \"%s\",\n", metric_expr);
+ if (metric_name)
+ fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
fprintf(outfp, "},\n");
return 0;
@@ -366,7 +369,8 @@ int json_events(const char *fn,
int (*func)(void *data, char *name, char *event, char *desc,
char *long_desc,
char *pmu, char *unit, char *perpkg,
- char *metric_expr),
+ char *metric_expr,
+ char *metric_name),
void *data)
{
int err = -EIO;
@@ -393,6 +397,7 @@ int json_events(const char *fn,
char *perpkg = NULL;
char *unit = NULL;
char *metric_expr = NULL;
+ char *metric_name = NULL;
unsigned long long eventcode = 0;
struct msrmap *msr = NULL;
jsmntok_t *msrval = NULL;
@@ -469,6 +474,8 @@ int json_events(const char *fn,
addfield(map, &unit, "", "", val);
} else if (json_streq(map, field, "PerPkg")) {
addfield(map, &perpkg, "", "", val);
+ } else if (json_streq(map, field, "MetricName")) {
+ addfield(map, &metric_name, "", "", val);
} else if (json_streq(map, field, "MetricExpr")) {
addfield(map, &metric_expr, "", "", val);
for (s = metric_expr; *s; s++)
@@ -497,7 +504,7 @@ int json_events(const char *fn,
fixname(name);
err = func(data, name, real_event(name, event), desc, long_desc,
- pmu, unit, perpkg, metric_expr);
+ pmu, unit, perpkg, metric_expr, metric_name);
free(event);
free(desc);
free(name);
@@ -508,6 +515,7 @@ int json_events(const char *fn,
free(perpkg);
free(unit);
free(metric_expr);
+ free(metric_name);
if (err)
break;
tok += j;
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
index 57e111bf2168..611fac01913d 100644
--- a/tools/perf/pmu-events/jevents.h
+++ b/tools/perf/pmu-events/jevents.h
@@ -5,7 +5,8 @@ int json_events(const char *fn,
int (*func)(void *data, char *name, char *event, char *desc,
char *long_desc,
char *pmu,
- char *unit, char *perpkg, char *metric_expr),
+ char *unit, char *perpkg, char *metric_expr,
+ char *metric_name),
void *data);
char *get_cpu_str(void);
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index d046e3a4ce46..569eab3688dd 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -14,6 +14,7 @@ struct pmu_event {
const char *unit;
const char *perpkg;
const char *metric_expr;
+ const char *metric_name;
};
/*
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a25dc688ab74..c16a1e1253a2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -237,6 +237,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
perf_evsel__calc_id_pos(evsel);
evsel->cmdline_group_boundary = false;
evsel->metric_expr = NULL;
+ evsel->metric_name = NULL;
evsel->metric_events = NULL;
evsel->collect_stat = false;
}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 8f1f61826fdf..d101695c482c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -133,6 +133,7 @@ struct perf_evsel {
int bpf_fd;
bool merged_stat;
const char * metric_expr;
+ const char * metric_name;
struct perf_evsel **metric_events;
bool collect_stat;
};
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index fcb0b6854642..4b063ff01410 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1255,6 +1255,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
evsel->per_pkg = info.per_pkg;
evsel->snapshot = info.snapshot;
evsel->metric_expr = info.metric_expr;
+ evsel->metric_name = info.metric_name;
}
return evsel ? 0 : -ENOMEM;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2cb463ababb8..633530fbfe1e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -232,7 +232,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
char *desc, char *val,
char *long_desc, char *topic,
char *unit, char *perpkg,
- char *metric_expr)
+ char *metric_expr,
+ char *metric_name)
{
struct perf_pmu_alias *alias;
int ret;
@@ -267,6 +268,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
}
alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
+ alias->metric_name = metric_name ? strdup(metric_name): NULL;
alias->desc = desc ? strdup(desc) : NULL;
alias->long_desc = long_desc ? strdup(long_desc) :
desc ? strdup(desc) : NULL;
@@ -296,7 +298,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
buf[ret] = 0;
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
- NULL, NULL);
+ NULL, NULL, NULL);
}
static inline bool pmu_alias_info_file(char *name)
@@ -567,7 +569,8 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
(char *)pe->desc, (char *)pe->event,
(char *)pe->long_desc, (char *)pe->topic,
(char *)pe->unit, (char *)pe->perpkg,
- (char *)pe->metric_expr);
+ (char *)pe->metric_expr,
+ (char *)pe->metric_name);
}
out:
@@ -986,6 +989,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
info->scale = 0.0;
info->snapshot = false;
info->metric_expr = NULL;
+ info->metric_name = NULL;
list_for_each_entry_safe(term, h, head_terms, list) {
alias = pmu_find_alias(pmu, term);
@@ -1002,6 +1006,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
if (alias->per_pkg)
info->per_pkg = true;
info->metric_expr = alias->metric_expr;
+ info->metric_name = alias->metric_name;
list_del(&term->list);
free(term);
@@ -1097,6 +1102,7 @@ struct sevent {
char *str;
char *pmu;
char *metric_expr;
+ char *metric_name;
};
static int cmp_sevent(const void *a, const void *b)
@@ -1196,6 +1202,7 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
aliases[j].str = alias->str;
aliases[j].pmu = pmu->name;
aliases[j].metric_expr = alias->metric_expr;
+ aliases[j].metric_name = alias->metric_name;
j++;
}
if (pmu->selectable &&
@@ -1232,6 +1239,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
printf("]\n");
if (verbose) {
printf("%*sPerf: %s/%s/", 8, "", aliases[j].pmu, aliases[j].str);
+ if (aliases[j].metric_name)
+ printf(" MetricName: %s", aliases[j].metric_name);
if (aliases[j].metric_expr)
printf(" MetricExpr: %s", aliases[j].metric_expr);
putchar('\n');
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 27f078ccc594..3d4b703f5d89 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -32,6 +32,7 @@ struct perf_pmu {
struct perf_pmu_info {
const char *unit;
const char *metric_expr;
+ const char *metric_name;
double scale;
bool per_pkg;
bool snapshot;
@@ -52,6 +53,7 @@ struct perf_pmu_alias {
bool per_pkg;
bool snapshot;
char *metric_expr;
+ char *metric_name;
};
struct perf_pmu *perf_pmu__find(const char *name);
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index e8e76744fa32..6883f429c742 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -796,7 +796,9 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
if (expr__parse(&ratio, &pctx, &p) == 0)
print_metric(ctxp, NULL, "%8.1f",
- out->force_header ? evsel->name : "",
+ evsel->metric_name ?
+ evsel->metric_name :
+ out->force_header ? evsel->name : "",
ratio);
else
print_metric(ctxp, NULL, NULL, "", 0);
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (8 preceding siblings ...)
2017-02-24 0:10 ` [PATCH 10/10] perf, tools: Add support for MetricName JSON attribute Andi Kleen
@ 2017-02-24 8:37 ` Jiri Olsa
2017-02-24 15:29 ` Andi Kleen
2017-02-26 23:28 ` Jiri Olsa
10 siblings, 1 reply; 15+ messages in thread
From: Jiri Olsa @ 2017-02-24 8:37 UTC (permalink / raw)
To: Andi Kleen; +Cc: acme, jolsa, linux-kernel, Andi Kleen
On Thu, Feb 23, 2017 at 04:10:12PM -0800, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
>
> To be used in next patch to support automatic summing of alias
> events.
>
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
hi,
I did not get the cover (0/...) letter with changes history..
jirka
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values
2017-02-24 8:37 ` [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Jiri Olsa
@ 2017-02-24 15:29 ` Andi Kleen
0 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2017-02-24 15:29 UTC (permalink / raw)
To: Jiri Olsa; +Cc: Andi Kleen, acme, jolsa, linux-kernel
On Fri, Feb 24, 2017 at 09:37:20AM +0100, Jiri Olsa wrote:
> On Thu, Feb 23, 2017 at 04:10:12PM -0800, Andi Kleen wrote:
> > From: Andi Kleen <ak@linux.intel.com>
> >
> > To be used in next patch to support automatic summing of alias
> > events.
> >
> > Signed-off-by: Andi Kleen <ak@linux.intel.com>
>
> hi,
> I did not get the cover (0/...) letter with changes history..
I dropped it because it was obsolete because Arnaldo already
merged a lot of the uncore base patches. The changes are all
described in the individual patches.
-Andi
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values
2017-02-24 0:10 [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Andi Kleen
` (9 preceding siblings ...)
2017-02-24 8:37 ` [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values Jiri Olsa
@ 2017-02-26 23:28 ` Jiri Olsa
10 siblings, 0 replies; 15+ messages in thread
From: Jiri Olsa @ 2017-02-26 23:28 UTC (permalink / raw)
To: Andi Kleen; +Cc: acme, jolsa, linux-kernel, Andi Kleen
On Thu, Feb 23, 2017 at 04:10:12PM -0800, Andi Kleen wrote:
SNIP
> +static void aggr_cb(struct perf_evsel *counter, void *data, bool first)
> +{
> + struct aggr_data *ad = data;
> + int cpu, cpu2, s2;
> +
> + for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
> + struct perf_counts_values *counts;
> +
> + cpu2 = perf_evsel__cpus(counter)->map[cpu];
> + s2 = aggr_get_id(evsel_list->cpus, cpu2);
> + if (s2 != ad->id)
> + continue;
> + if (first)
> + ad->nr++;
> + counts = perf_counts(counter->counts, cpu, 0);
> + /*
> + * When any result is bad, make them all to give
> + * consistent output in interval mode.
> + */
> + if (counts->ena == 0 || counts->run == 0 ||
> + counter->counts->scaled == -1) {
> + ad->ena = 0;
> + ad->run = 0;
> + break;
> + }
that's new, please make this a separate change
thanks,
jirka
^ permalink raw reply [flat|nested] 15+ messages in thread