perf: Improve support for uncore JSON event lists
This patch kit further improves support for Intel uncore events in the Linux perf user tool. The basic support has been already merged earlier, but this makes it nicer to use.
- Collapse counts from duplicated boxes to make the output easier to read.
- Support specifying events for multiple duplicated boxes in an abbreviated format to shorten event specifiers
- Add support for computing Metrics defined in the event lists, so that the event lists can extend the metrics in perf stat. This allows to represent many events in an easier to understand format.
Available from
git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-misc.git perf/builtin-json-28
v1: Initial post after being split off to own patchkit Adding MetricName support and support for more than two events in expressions.
v2: Address review comments. Move new hunk from refactor patchkit to patch adding new features. Improve changelogs slightly.
PATCH 1/10 perf, tools, stat: Factor out callback for collecting event values
From: Andi Kleen <[email protected]>
To be used in next patch to support automatic summing of alias events.
v2: Move check for bad results to next patch
--- tools/perf/builtin-stat.c | 104 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 23 deletions(-)
tools/perf/builtin-stat.c +81 -23
@@ -1178,11 +1178,47 @@ static void aggr_update_shadow(void) } } +static void collect_data (struct perf_evsel *counter, +void (*cb)(struct perf_evsel *counter,void *data, +bool first), +void *data) +{ +cb (counter, data, true); +} + +struct aggr_data { +u64 ena, run, val; +int id; +int nr; +int cpu; +}; + +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 ); + ad->val += counts->val; + ad->ena += counts->ena; + ad->run += counts->run; + } +} +static void print_aggr (char *prefix) {FILE *output = stat_config.output;struct perf_evsel *counter; -int cpu, s, s2, id, nr; +int s, id, nr;double uval;u64 ena, run, val;bool first;
@@ -1197,23 +1233,20 @@ static void print_aggr(char *prefix)* Without each counter has its own line. */ for (s =0 ; s < aggr_map->nr; s++) { +struct aggr_data ad;if (prefix && metric_only)fprintf (output,"%s" , prefix); - id = aggr_map->map[s]; + ad.id = id = aggr_map->map[s]; first = true;evlist__for_each_entry (evsel_list, counter) { - val = ena = run =0 ; - nr =0 ; -for (cpu =0 ; cpu <perf_evsel__nr_cpus (counter); cpu++) { - s2 =aggr_get_id (perf_evsel__cpus (counter), cpu); -if (s2 != id) -continue ; - val +=perf_counts (counter->counts, cpu,0 )->val; - ena +=perf_counts (counter->counts, cpu,0 )->ena; - run +=perf_counts (counter->counts, cpu,0 )->run; - nr++; - } + ad.val = ad.ena = ad.run =0 ; + ad.nr =0 ; +collect_data (counter, aggr_cb, &ad); + nr = ad.nr; + ena = ad.ena; + run = ad.run; + val = ad.val;if (first && metric_only) { first = false;aggr_printout (counter, id, nr);
@@ -1257,6 +1290,21 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix) } } +struct caggr_data { +double avg, avg_enabled, avg_running; +}; + +static void counter_aggr_cb (struct perf_evsel *counter,void *data, +bool first__maybe_unused ) +{ +struct caggr_data *cd = data; +struct perf_stat_evsel *ps = counter->priv; + + cd->avg +=avg_stats (&ps->res_stats[0 ]); + cd->avg_enabled +=avg_stats (&ps->res_stats[1 ]); + cd->avg_running +=avg_stats (&ps->res_stats[2 ]); +} +/* * Print out the results of a single counter: * aggregated counts in system-wide mode
@@ -1264,23 +1312,30 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)static void print_counter_aggr (struct perf_evsel *counter,char *prefix) {FILE *output = stat_config.output; -struct perf_stat_evsel *ps = counter->priv; -double avg =avg_stats (&ps->res_stats[0 ]);double uval; -double avg_enabled, avg_running; +struct caggr_data cd = { .avg =0.0 }; - avg_enabled =avg_stats (&ps->res_stats[1 ]); - avg_running =avg_stats (&ps->res_stats[2 ]); +collect_data (counter, counter_aggr_cb, &cd);if (prefix && !metric_only)fprintf (output,"%s" , prefix); - uval = avg * counter->scale; -printout (-1 ,0 , counter, uval, prefix, avg_running, avg_enabled, avg); + uval = cd.avg * counter->scale; +printout (-1 ,0 , counter, uval, prefix, cd.avg_running, cd.avg_enabled, cd.avg);if (!metric_only)fprintf (output,"\n" ); } +static void counter_cb (struct perf_evsel *counter,void *data, +bool first__maybe_unused ) +{ +struct aggr_data *ad = data; + + ad->val +=perf_counts (counter->counts, ad->cpu,0 )->val; + ad->ena +=perf_counts (counter->counts, ad->cpu,0 )->ena; + ad->run +=perf_counts (counter->counts, ad->cpu,0 )->run; +} +/* * Print out the results of a single counter: * does not use aggregated count in system-wide
@@ -1293,9 +1348,12 @@ static void print_counter(struct perf_evsel *counter, char *prefix)int cpu;for (cpu =0 ; cpu <perf_evsel__nr_cpus (counter); cpu++) { - val =perf_counts (counter->counts, cpu,0 )->val; - ena =perf_counts (counter->counts, cpu,0 )->ena; - run =perf_counts (counter->counts, cpu,0 )->run; +struct aggr_data ad = { .cpu = cpu }; + +collect_data (counter, counter_cb, &ad); + val = ad.val; + ena = ad.ena; + run = ad.run;if (prefix)fprintf (output,"%s" , prefix);
Signature · 1 line
2.9.3
Re: [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values
On Tue, Feb 28, 2017 at 10:49:15PM -0800, Andi Kleen wrote:
SNIP
Quoted 15 lines
tools/perf/builtin-stat.c +15
-0+static void collect_data (struct perf_evsel *counter, +void (*cb)(struct perf_evsel *counter,void *data, +bool first), +void *data) +{ +cb (counter, data, true); +} + +struct aggr_data { +u64 ena, run, val; +int id; +int nr; +int cpu; +}; +
tools/perf/builtin-stat.c static void aggr_update_shadow(void) · line 1205
Quoted 10 lines
tools/perf/builtin-stat.c +10
-0+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);
that does not match the removed code.. why?
s2 = aggr_get_id(perf_evsel__cpus(counter), cpu);
jirka
Re: [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values
Quoted 31 lines · Jiri Olsa
On Tue, Feb 28, 2017 at 10:49:15PM -0800, Andi Kleen wrote:
SNIP
Quoted 15 lines
tools/perf/builtin-stat.c +15
-0+static void collect_data (struct perf_evsel *counter, +void (*cb)(struct perf_evsel *counter,void *data, +bool first), +void *data) +{ +cb (counter, data, true); +} + +struct aggr_data { +u64 ena, run, val; +int id; +int nr; +int cpu; +}; +tools/perf/builtin-stat.c static void aggr_update_shadow(void) · line 1205
Quoted 10 lines
tools/perf/builtin-stat.c +10
-0+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);that does not match the removed code.. why?
Quoted 1 line
s2 = aggr_get_id(perf_evsel__cpus(counter), cpu);
I added it at some point during debugging. I think it's actually a nop here, but technically it's correct (we're always supposed to remap)
I can remove it, but it's really a small code cleanup.
-Andi
Re: [PATCH 01/10] perf, tools, stat: Factor out callback for collecting event values
Quoted 34 lines · Andi Kleen
Quoted 31 lines · Jiri Olsa
On Tue, Feb 28, 2017 at 10:49:15PM -0800, Andi Kleen wrote:
SNIP
Quoted 15 lines
tools/perf/builtin-stat.c +15
-0+static void collect_data (struct perf_evsel *counter, +void (*cb)(struct perf_evsel *counter,void *data, +bool first), +void *data) +{ +cb (counter, data, true); +} + +struct aggr_data { +u64 ena, run, val; +int id; +int nr; +int cpu; +}; +tools/perf/builtin-stat.c static void aggr_update_shadow(void) · line 1205
Quoted 10 lines
tools/perf/builtin-stat.c +10
-0+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);that does not match the removed code.. why?
Quoted 1 line
s2 = aggr_get_id(perf_evsel__cpus(counter), cpu);
Quoted 5 lines
I added it at some point during debugging. I think it's actually a nop here, but technically it's correct (we're always supposed to remap)
I can remove it, but it's really a small code cleanup.
please do, thanks
jirka
PATCH 2/10 perf, tools, stat: Collapse identically named events
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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 elapsedAfter:
% 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 elapsedv2: Split collect_aliases. Rename alias flag.
v3: Make sure unsupported/not counted is always printed.
v4: Factor out callback change into separate patch.
v5: Move check for bad results here
--- tools/perf/Documentation/perf-stat.txt | 3 +++ tools/perf/builtin-stat.c | 41 ++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 1 + 3 files changed, 45 insertions(+)
tools/perf/Documentation/perf-stat.txt +3 -0
@@ -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 --------
tools/perf/builtin-stat.c +41 -0
89 lines not on this page · raw message
tools/perf/util/evsel.h +1 -0
@@ -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 {
Signature · 1 line
2.9.3
Re: [PATCH 02/10] perf, tools, stat: Collapse identically named events
On Tue, Feb 28, 2017 at 10:49:16PM -0800, Andi Kleen wrote:
SNIP
Quoted 6 lines
struct
aggr_data{tools/perf/builtin-stat.c +0
-0@@ -1208,6 +1231,16 @@ static void aggr_cb(struct perf_evsel *counter, void *data, bool first)if (first) ad->nr++; counts =perf_counts (counter->counts, cpu,0 );
tools/perf/builtin-stat.c static void aggr_cb(struct perf_evsel *counter, void *data, bool first) · line 1243
Quoted 10 lines
tools/perf/builtin-stat.c +10
-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 ; + }
I think this needs to be in separate patch, showing the interval output before and after the change..
thanks,
jirka
Re: [PATCH 02/10] perf, tools, stat: Collapse identically named events
In reply to Andi KleenOn Tue, Feb 28, 2017 at 10:49:16PM -0800, Andi Kleen wrote:
SNIP
Quoted 18 lines
tools/perf/builtin-stat.c +15
-0} } +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 ;
tools/perf/builtin-stat.c static void aggr_update_shadow(void) · line 1206
Quoted 10 lines
tools/perf/builtin-stat.c +5
-0+ 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) {
could we place the merged_stat condition in here and have collect_data return value to process or not the current counter.. looks like we could get rid of 2 merged_stat conditions in print_counter_aggr and print_aggr
jirka
PATCH 3/10 perf, tools: Factor out PMU matching in parser
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
Factor out the PMU name matching in the event parser into a separate function, to use the same code for other grammar rules later.
--- 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(-)
tools/perf/util/parse-events.c +46 -0
@@ -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) {
tools/perf/util/parse-events.h +5 -0
@@ -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);
tools/perf/util/parse-events.y +1 -29
@@ -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; }
Signature · 1 line
2.9.3
Re: [PATCH 03/10] perf, tools: Factor out PMU matching in parser
On Tue, Feb 28, 2017 at 10:49:17PM -0800, Andi Kleen wrote:
SNIP
Quoted 16 lines
tools/perf/util/parse-events.y +0
-6@@ -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 */
tools/perf/util/parse-events.y PE_NAME opt_event_config · line 256
Quoted 10 lines
tools/perf/util/parse-events.y +0
-10- 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);
http://marc.info/?l=linux-kernel&m=148818456131560&w=2
jirka
PATCH 4/10 perf, tools: Expand PMU events by prefix match
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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.
--- 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(-)
tools/perf/util/parse-events.c +25 -0
@@ -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;
tools/perf/util/parse-events.h +3 -0
@@ -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);
tools/perf/util/parse-events.y +26 -14
@@ -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; }
Signature · 1 line
2.9.3
PATCH 5/10 perf, tools: Special case uncore_ prefix
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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
--- tools/perf/util/parse-events.y | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/util/parse-events.y +3 -0
@@ -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;
Signature · 1 line
2.9.3
PATCH 6/10 perf, tools: Add a simple expression parser for JSON
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
Add a simple expression parser good enough to parse JSON relation expressions. The parser is implemented using bison.
This is just intended as an simple parser for internal usage in the event lists, not the beginning of a "perf scripting language"
v2: Use expr__ prefix instead of expr_
Support multiple free variables for parser
--- 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
tools/perf/tests/Build +1 -0
@@ -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
tools/perf/tests/builtin-test.c +4 -0
@@ -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, },
tools/perf/tests/expr.c new file +55 -0
55 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -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);
tools/perf/util/Build +5 -0
@@ -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
tools/perf/util/expr.h new file +25 -0
@@ -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
tools/perf/util/expr.y new file +173 -0
173 lines not on this page · raw message
Signature · 1 line
2.9.3
PATCH 7/10 perf, tools: Support MetricExpr header in JSON event list
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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
--- 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(-)
tools/perf/pmu-events/jevents.c +14 -4
@@ -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;
tools/perf/pmu-events/jevents.h +1 -1
@@ -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 );
tools/perf/pmu-events/pmu-events.h +1 -0
@@ -13,6 +13,7 @@ struct pmu_event {const char *pmu;const char *unit;const char *perpkg; +const char *metric_expr; };/*
tools/perf/util/pmu.c +6 -3
@@ -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:
tools/perf/util/pmu.h +1 -0
@@ -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);
Signature · 1 line
2.9.3
PATCH 8/10 perf, tools, stat: Output JSON MetricExpr metric
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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.1v2: Change from DivideBy to MetricExpr
v3: Use expr__ prefix. Support more than one other event.
--- 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(+)
tools/perf/builtin-stat.c +3 -0
@@ -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) {
tools/perf/util/evsel.c +3 -0
@@ -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)
tools/perf/util/evsel.h +3 -0
@@ -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 {
tools/perf/util/parse-events.c +1 -0
@@ -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 ;
tools/perf/util/pmu.c +2 -0
@@ -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);
tools/perf/util/pmu.h +1 -0
@@ -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;
tools/perf/util/stat-shadow.c +188 -0
237 lines not on this page · raw message
tools/perf/util/stat.h +2 -0
@@ -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);
Signature · 1 line
2.9.3
Re: [PATCH 08/10] perf, tools, stat: Output JSON MetricExpr metric
Quoted 33 lines · Andi Kleen
From: Andi Kleen <[email protected]>
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
Quoted 3 lines
$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}' --metric-only
1.000206740 48.0
2.000451543 48.1The comment above suggest I'll see 'original event as description' in this example??
However, could you just make those metric names working in here? Displaying original event for metric value is misleading.
jirka
PATCH 9/10 perf, tools, list: Support printing MetricExpr with -v
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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.
--- tools/perf/util/pmu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/perf/util/pmu.c +8 -2
@@ -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++;
Signature · 1 line
2.9.3
PATCH 10/10 perf, tools: Add support for MetricName JSON attribute
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
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.
--- 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(-)
tools/perf/pmu-events/jevents.c +11 -3
@@ -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;
tools/perf/pmu-events/jevents.h +2 -1
@@ -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 );
tools/perf/pmu-events/pmu-events.h +1 -0
@@ -14,6 +14,7 @@ struct pmu_event {const char *unit;const char *perpkg;const char *metric_expr; +const char *metric_name; };/*
tools/perf/util/evsel.c +1 -0
@@ -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; }
tools/perf/util/evsel.h +1 -0
@@ -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; };
tools/perf/util/parse-events.c +1 -0
@@ -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 ;
tools/perf/util/pmu.c +12 -3
@@ -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' );
tools/perf/util/pmu.h +2 -0
@@ -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);
tools/perf/util/stat-shadow.c +3 -1
@@ -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 );
Signature · 1 line
2.9.3
Re: [PATCH 10/10] perf, tools: Add support for MetricName JSON attribute
Quoted 8 lines · Andi Kleen
From: Andi Kleen <[email protected]>
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.
when do you plan to add them?
jirka
Quoted 17 lines · Andi Kleen
This patch kit further improves support for Intel uncore events in the Linux perf user tool. The basic support has been already merged earlier, but this makes it nicer to use.
- Collapse counts from duplicated boxes to make the output easier to read.
- Support specifying events for multiple duplicated boxes in an abbreviated format to shorten event specifiers
- Add support for computing Metrics defined in the event lists, so that the event lists can extend the metrics in perf stat. This allows to represent many events in an easier to understand format.Available from
git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-misc.gitperf/builtin-json-28
Quoted 8 lines
v1: Initial post after being split off to own patchkit Adding MetricName support and support for more than two events in expressions.
v2: Address review comments. Move new hunk from refactor patchkit to patch adding new features. Improve changelogs slightly.
with my comments addressed, I'll be ok to ack it in next version
thanks,
jirka