aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2018-06-14 02:11:29 -0400
committerIngo Molnar <mingo@kernel.org>2018-06-14 02:11:29 -0400
commita89d0c2acff952935cb37d501eaa702db5a63a05 (patch)
tree7f7b743635f9562137fa6384b58b81a6f634e977
parentd82991a8688ad128b46db1b42d5d84396487a508 (diff)
parentfad76d4333fe73cf3f73704aa34d4ce523b1c458 (diff)
Merge tag 'perf-urgent-for-mingo-4.18-20180611' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/urgent fixes and improvements from Arnaldo Carvalho de Melo: perf stat: - Fix metric column header display alignment (Jiri Olsa) - Improve error messages for default attributes, providing better output for error in command lines such as: $ perf stat -T Cannot set up transaction events event syntax error: '..cycles,cpu/cycles-t/,cpu/tx-start/,cpu/el-start/,cpu/cycles-ct/}' \___ unknown term Where the "event syntax error" line now appears (Jiri Olsa) - Add --interval-clear option, to provide a 'watch' like printing (Jiri Olsa) perf script: - Show hw-cache events too (Seeteena Thoufeek) perf c2c: - Fix data dependency problem in layout of 'struct c2c_hist_entry', where its member 'struct hist_entry' must be at the end because it has a ZLA as its last member, that gets space when handling callchains (Jiri Olsa) Core: - We cannot assume that a 'struct perf_evsel' is to be obtained from a container_of operation on a 'struct hists' as there are tools, such as 'perf c2c' that uses 'struct hist' instances without having them in container structs that also have 'struct perf_evsel' in a particular layout, so provide a different way of figuring out if a 'struct hists' and 'struct hist_entry' have callchains (Arnaldo Carvalho de Melo) - Fix error index in the PMU event parser, so that error messages can point to the problematic token (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Documentation/perf-stat.txt3
-rw-r--r--tools/perf/builtin-c2c.c10
-rw-r--r--tools/perf/builtin-script.c12
-rw-r--r--tools/perf/builtin-stat.c48
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/util/hist.c12
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/parse-events.y5
-rw-r--r--tools/perf/util/sort.h4
9 files changed, 67 insertions, 33 deletions
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 5dfe102fb5b5..b10a90b6a718 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -178,6 +178,9 @@ Print count deltas for fixed number of times.
178This option should be used together with "-I" option. 178This option should be used together with "-I" option.
179 example: 'perf stat -I 1000 --interval-count 2 -e cycles -a' 179 example: 'perf stat -I 1000 --interval-count 2 -e cycles -a'
180 180
181--interval-clear::
182Clear the screen before next interval.
183
181--timeout msecs:: 184--timeout msecs::
182Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). 185Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms).
183This option is not supported with the "-I" option. 186This option is not supported with the "-I" option.
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index 307b3594525f..6a8738f7ead3 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -56,16 +56,16 @@ struct c2c_hist_entry {
56 56
57 struct compute_stats cstats; 57 struct compute_stats cstats;
58 58
59 unsigned long paddr;
60 unsigned long paddr_cnt;
61 bool paddr_zero;
62 char *nodestr;
63
59 /* 64 /*
60 * must be at the end, 65 * must be at the end,
61 * because of its callchain dynamic entry 66 * because of its callchain dynamic entry
62 */ 67 */
63 struct hist_entry he; 68 struct hist_entry he;
64
65 unsigned long paddr;
66 unsigned long paddr_cnt;
67 bool paddr_zero;
68 char *nodestr;
69}; 69};
70 70
71static char const *coalesce_default = "pid,iaddr"; 71static char const *coalesce_default = "pid,iaddr";
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b3bf35512d21..a31d7082188e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -180,6 +180,18 @@ static struct {
180 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE 180 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
181 }, 181 },
182 182
183 [PERF_TYPE_HW_CACHE] = {
184 .user_set = false,
185
186 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
187 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
188 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
189 PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
190 PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
191
192 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
193 },
194
183 [PERF_TYPE_RAW] = { 195 [PERF_TYPE_RAW] = {
184 .user_set = false, 196 .user_set = false,
185 197
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 096ccb25c11f..22547a490e1f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -65,6 +65,7 @@
65#include "util/tool.h" 65#include "util/tool.h"
66#include "util/string2.h" 66#include "util/string2.h"
67#include "util/metricgroup.h" 67#include "util/metricgroup.h"
68#include "util/top.h"
68#include "asm/bug.h" 69#include "asm/bug.h"
69 70
70#include <linux/time64.h> 71#include <linux/time64.h>
@@ -144,6 +145,8 @@ static struct target target = {
144 145
145typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); 146typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);
146 147
148#define METRIC_ONLY_LEN 20
149
147static int run_count = 1; 150static int run_count = 1;
148static bool no_inherit = false; 151static bool no_inherit = false;
149static volatile pid_t child_pid = -1; 152static volatile pid_t child_pid = -1;
@@ -173,6 +176,7 @@ static struct cpu_map *aggr_map;
173static aggr_get_id_t aggr_get_id; 176static aggr_get_id_t aggr_get_id;
174static bool append_file; 177static bool append_file;
175static bool interval_count; 178static bool interval_count;
179static bool interval_clear;
176static const char *output_name; 180static const char *output_name;
177static int output_fd; 181static int output_fd;
178static int print_free_counters_hint; 182static int print_free_counters_hint;
@@ -180,6 +184,7 @@ static int print_mixed_hw_group_error;
180static u64 *walltime_run; 184static u64 *walltime_run;
181static bool ru_display = false; 185static bool ru_display = false;
182static struct rusage ru_data; 186static struct rusage ru_data;
187static unsigned int metric_only_len = METRIC_ONLY_LEN;
183 188
184struct perf_stat { 189struct perf_stat {
185 bool record; 190 bool record;
@@ -967,8 +972,6 @@ static void print_metric_csv(void *ctx,
967 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); 972 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
968} 973}
969 974
970#define METRIC_ONLY_LEN 20
971
972/* Filter out some columns that don't work well in metrics only mode */ 975/* Filter out some columns that don't work well in metrics only mode */
973 976
974static bool valid_only_metric(const char *unit) 977static bool valid_only_metric(const char *unit)
@@ -999,22 +1002,20 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt,
999{ 1002{
1000 struct outstate *os = ctx; 1003 struct outstate *os = ctx;
1001 FILE *out = os->fh; 1004 FILE *out = os->fh;
1002 int n; 1005 char buf[1024], str[1024];
1003 char buf[1024]; 1006 unsigned mlen = metric_only_len;
1004 unsigned mlen = METRIC_ONLY_LEN;
1005 1007
1006 if (!valid_only_metric(unit)) 1008 if (!valid_only_metric(unit))
1007 return; 1009 return;
1008 unit = fixunit(buf, os->evsel, unit); 1010 unit = fixunit(buf, os->evsel, unit);
1009 if (color)
1010 n = color_fprintf(out, color, fmt, val);
1011 else
1012 n = fprintf(out, fmt, val);
1013 if (n > METRIC_ONLY_LEN)
1014 n = METRIC_ONLY_LEN;
1015 if (mlen < strlen(unit)) 1011 if (mlen < strlen(unit))
1016 mlen = strlen(unit) + 1; 1012 mlen = strlen(unit) + 1;
1017 fprintf(out, "%*s", mlen - n, ""); 1013
1014 if (color)
1015 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
1016
1017 color_snprintf(str, sizeof(str), color ?: "", fmt, val);
1018 fprintf(out, "%*s ", mlen, str);
1018} 1019}
1019 1020
1020static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, 1021static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
@@ -1054,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused,
1054 if (csv_output) 1055 if (csv_output)
1055 fprintf(os->fh, "%s%s", unit, csv_sep); 1056 fprintf(os->fh, "%s%s", unit, csv_sep);
1056 else 1057 else
1057 fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit); 1058 fprintf(os->fh, "%*s ", metric_only_len, unit);
1058} 1059}
1059 1060
1060static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 1061static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
@@ -1704,9 +1705,12 @@ static void print_interval(char *prefix, struct timespec *ts)
1704 FILE *output = stat_config.output; 1705 FILE *output = stat_config.output;
1705 static int num_print_interval; 1706 static int num_print_interval;
1706 1707
1708 if (interval_clear)
1709 puts(CONSOLE_CLEAR);
1710
1707 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1711 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
1708 1712
1709 if (num_print_interval == 0 && !csv_output) { 1713 if ((num_print_interval == 0 && !csv_output) || interval_clear) {
1710 switch (stat_config.aggr_mode) { 1714 switch (stat_config.aggr_mode) {
1711 case AGGR_SOCKET: 1715 case AGGR_SOCKET:
1712 fprintf(output, "# time socket cpus"); 1716 fprintf(output, "# time socket cpus");
@@ -1719,7 +1723,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1719 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1723 fprintf(output, " counts %*s events\n", unit_width, "unit");
1720 break; 1724 break;
1721 case AGGR_NONE: 1725 case AGGR_NONE:
1722 fprintf(output, "# time CPU"); 1726 fprintf(output, "# time CPU ");
1723 if (!metric_only) 1727 if (!metric_only)
1724 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1728 fprintf(output, " counts %*s events\n", unit_width, "unit");
1725 break; 1729 break;
@@ -1738,7 +1742,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1738 } 1742 }
1739 } 1743 }
1740 1744
1741 if (num_print_interval == 0 && metric_only) 1745 if ((num_print_interval == 0 && metric_only) || interval_clear)
1742 print_metric_headers(" ", true); 1746 print_metric_headers(" ", true);
1743 if (++num_print_interval == 25) 1747 if (++num_print_interval == 25)
1744 num_print_interval = 0; 1748 num_print_interval = 0;
@@ -2057,6 +2061,8 @@ static const struct option stat_options[] = {
2057 "(overhead is possible for values <= 100ms)"), 2061 "(overhead is possible for values <= 100ms)"),
2058 OPT_INTEGER(0, "interval-count", &stat_config.times, 2062 OPT_INTEGER(0, "interval-count", &stat_config.times,
2059 "print counts for fixed number of times"), 2063 "print counts for fixed number of times"),
2064 OPT_BOOLEAN(0, "interval-clear", &interval_clear,
2065 "clear screen in between new interval"),
2060 OPT_UINTEGER(0, "timeout", &stat_config.timeout, 2066 OPT_UINTEGER(0, "timeout", &stat_config.timeout,
2061 "stop workload and print counts after a timeout period in ms (>= 10ms)"), 2067 "stop workload and print counts after a timeout period in ms (>= 10ms)"),
2062 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, 2068 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
@@ -2436,14 +2442,13 @@ static int add_default_attributes(void)
2436 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 2442 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
2437 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2443 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
2438}; 2444};
2445 struct parse_events_error errinfo;
2439 2446
2440 /* Set attrs if no event is selected and !null_run: */ 2447 /* Set attrs if no event is selected and !null_run: */
2441 if (null_run) 2448 if (null_run)
2442 return 0; 2449 return 0;
2443 2450
2444 if (transaction_run) { 2451 if (transaction_run) {
2445 struct parse_events_error errinfo;
2446
2447 if (pmu_have_event("cpu", "cycles-ct") && 2452 if (pmu_have_event("cpu", "cycles-ct") &&
2448 pmu_have_event("cpu", "el-start")) 2453 pmu_have_event("cpu", "el-start"))
2449 err = parse_events(evsel_list, transaction_attrs, 2454 err = parse_events(evsel_list, transaction_attrs,
@@ -2454,6 +2459,7 @@ static int add_default_attributes(void)
2454 &errinfo); 2459 &errinfo);
2455 if (err) { 2460 if (err) {
2456 fprintf(stderr, "Cannot set up transaction events\n"); 2461 fprintf(stderr, "Cannot set up transaction events\n");
2462 parse_events_print_error(&errinfo, transaction_attrs);
2457 return -1; 2463 return -1;
2458 } 2464 }
2459 return 0; 2465 return 0;
@@ -2479,10 +2485,11 @@ static int add_default_attributes(void)
2479 pmu_have_event("msr", "smi")) { 2485 pmu_have_event("msr", "smi")) {
2480 if (!force_metric_only) 2486 if (!force_metric_only)
2481 metric_only = true; 2487 metric_only = true;
2482 err = parse_events(evsel_list, smi_cost_attrs, NULL); 2488 err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
2483 } else { 2489 } else {
2484 fprintf(stderr, "To measure SMI cost, it needs " 2490 fprintf(stderr, "To measure SMI cost, it needs "
2485 "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); 2491 "msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
2492 parse_events_print_error(&errinfo, smi_cost_attrs);
2486 return -1; 2493 return -1;
2487 } 2494 }
2488 if (err) { 2495 if (err) {
@@ -2517,12 +2524,13 @@ static int add_default_attributes(void)
2517 if (topdown_attrs[0] && str) { 2524 if (topdown_attrs[0] && str) {
2518 if (warn) 2525 if (warn)
2519 arch_topdown_group_warn(); 2526 arch_topdown_group_warn();
2520 err = parse_events(evsel_list, str, NULL); 2527 err = parse_events(evsel_list, str, &errinfo);
2521 if (err) { 2528 if (err) {
2522 fprintf(stderr, 2529 fprintf(stderr,
2523 "Cannot set up top down events %s: %d\n", 2530 "Cannot set up top down events %s: %d\n",
2524 str, err); 2531 str, err);
2525 free(str); 2532 free(str);
2533 parse_events_print_error(&errinfo, str);
2526 return -1; 2534 return -1;
2527 } 2535 }
2528 } else { 2536 } else {
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index b085f1b3e34d..4ab663ec3e5e 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -382,7 +382,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
382 gtk_tree_store_set(store, &iter, col_idx++, s, -1); 382 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
383 } 383 }
384 384
385 if (hists__has_callchains(hists) && 385 if (hist_entry__has_callchains(h) &&
386 symbol_conf.use_callchain && hists__has(hists, sym)) { 386 symbol_conf.use_callchain && hists__has(hists, sym)) {
387 if (callchain_param.mode == CHAIN_GRAPH_REL) 387 if (callchain_param.mode == CHAIN_GRAPH_REL)
388 total = symbol_conf.cumulate_callchain ? 388 total = symbol_conf.cumulate_callchain ?
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 52e8fda93a47..828cb9794c76 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -370,9 +370,11 @@ void hists__delete_entries(struct hists *hists)
370 370
371static int hist_entry__init(struct hist_entry *he, 371static int hist_entry__init(struct hist_entry *he,
372 struct hist_entry *template, 372 struct hist_entry *template,
373 bool sample_self) 373 bool sample_self,
374 size_t callchain_size)
374{ 375{
375 *he = *template; 376 *he = *template;
377 he->callchain_size = callchain_size;
376 378
377 if (symbol_conf.cumulate_callchain) { 379 if (symbol_conf.cumulate_callchain) {
378 he->stat_acc = malloc(sizeof(he->stat)); 380 he->stat_acc = malloc(sizeof(he->stat));
@@ -473,7 +475,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
473 475
474 he = ops->new(callchain_size); 476 he = ops->new(callchain_size);
475 if (he) { 477 if (he) {
476 err = hist_entry__init(he, template, sample_self); 478 err = hist_entry__init(he, template, sample_self, callchain_size);
477 if (err) { 479 if (err) {
478 ops->free(he); 480 ops->free(he);
479 he = NULL; 481 he = NULL;
@@ -619,9 +621,11 @@ __hists__add_entry(struct hists *hists,
619 .raw_data = sample->raw_data, 621 .raw_data = sample->raw_data,
620 .raw_size = sample->raw_size, 622 .raw_size = sample->raw_size,
621 .ops = ops, 623 .ops = ops,
622 }; 624 }, *he = hists__findnew_entry(hists, &entry, al, sample_self);
623 625
624 return hists__findnew_entry(hists, &entry, al, sample_self); 626 if (!hists->has_callchains && he && he->callchain_size != 0)
627 hists->has_callchains = true;
628 return he;
625} 629}
626 630
627struct hist_entry *hists__add_entry(struct hists *hists, 631struct hist_entry *hists__add_entry(struct hists *hists,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 06607c434949..73049f7f0f60 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -85,6 +85,7 @@ struct hists {
85 struct events_stats stats; 85 struct events_stats stats;
86 u64 event_stream; 86 u64 event_stream;
87 u16 col_len[HISTC_NR_COLS]; 87 u16 col_len[HISTC_NR_COLS];
88 bool has_callchains;
88 int socket_filter; 89 int socket_filter;
89 struct perf_hpp_list *hpp_list; 90 struct perf_hpp_list *hpp_list;
90 struct list_head hpp_formats; 91 struct list_head hpp_formats;
@@ -222,8 +223,7 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
222 223
223static __pure inline bool hists__has_callchains(struct hists *hists) 224static __pure inline bool hists__has_callchains(struct hists *hists)
224{ 225{
225 const struct perf_evsel *evsel = hists_to_evsel(hists); 226 return hists->has_callchains;
226 return evsel__has_callchain(evsel);
227} 227}
228 228
229int hists__init(void); 229int hists__init(void);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 155d2570274f..da8fe57691b8 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -227,11 +227,16 @@ event_def: event_pmu |
227event_pmu: 227event_pmu:
228PE_NAME opt_pmu_config 228PE_NAME opt_pmu_config
229{ 229{
230 struct parse_events_state *parse_state = _parse_state;
231 struct parse_events_error *error = parse_state->error;
230 struct list_head *list, *orig_terms, *terms; 232 struct list_head *list, *orig_terms, *terms;
231 233
232 if (parse_events_copy_term_list($2, &orig_terms)) 234 if (parse_events_copy_term_list($2, &orig_terms))
233 YYABORT; 235 YYABORT;
234 236
237 if (error)
238 error->idx = @1.first_column;
239
235 ALLOC_LIST(list); 240 ALLOC_LIST(list);
236 if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) { 241 if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) {
237 struct perf_pmu *pmu = NULL; 242 struct perf_pmu *pmu = NULL;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 7cf2d5cc038e..8bf302cafcec 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -112,6 +112,8 @@ struct hist_entry {
112 112
113 char level; 113 char level;
114 u8 filtered; 114 u8 filtered;
115
116 u16 callchain_size;
115 union { 117 union {
116 /* 118 /*
117 * Since perf diff only supports the stdio output, TUI 119 * Since perf diff only supports the stdio output, TUI
@@ -153,7 +155,7 @@ struct hist_entry {
153 155
154static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) 156static __pure inline bool hist_entry__has_callchains(struct hist_entry *he)
155{ 157{
156 return hists__has_callchains(he->hists); 158 return he->callchain_size != 0;
157} 159}
158 160
159static inline bool hist_entry__has_pairs(struct hist_entry *he) 161static inline bool hist_entry__has_pairs(struct hist_entry *he)