aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@kernel.org>2015-04-22 15:10:16 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-04-29 09:37:58 -0400
commitb39b839309ce8c5dd15cd95d26af153fa392c3e6 (patch)
treed7e9f99c2a722bd40cca5c6b594d2b68ad7791c3
parent70d73de4cd571df09670e2a7bf36a912e9ff5138 (diff)
perf tools: Add parse_events_error interface
Adding support to return error information from parse_events function. Following struct will be populated by parse_events function on return: struct parse_events_error { int idx; char *str; char *help; }; where 'idx' is the position in the string where the parsing failed, 'str' contains dynamically allocated error string describing the error and 'help' is optional help string. The change contains reporting function, which currently does not display anything. The code changes to supply error data for specific event types are coming in next patches. However this is what the expected output is: $ sudo perf record -e 'sched:krava' ls event syntax error: 'sched:krava' \___ unknown tracepoint ... $ perf record -e 'cpu/even=0x1/' ls event syntax error: 'cpu/even=0x1/' \___ unknown term valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type ... $ perf record -e cycles,cache-mises ls event syntax error: '..es,cache-mises' \___ parser error ... The output functions cut the beginning of the event string so the error starts up to 10th character and cut the end of the string of it crosses the terminal width. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1429729824-13932-2-git-send-email-jolsa@kernel.org [ Renamed 'error' variables to 'err', not to clash with util.h error() ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/builtin-stat.c2
-rw-r--r--tools/perf/tests/code-reading.c2
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_filter.c4
-rw-r--r--tools/perf/tests/hists_link.c4
-rw-r--r--tools/perf/tests/hists_output.c2
-rw-r--r--tools/perf/tests/keep-tracking.c4
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c2
-rw-r--r--tools/perf/tests/switch-tracking.c8
-rw-r--r--tools/perf/util/parse-events.c100
-rw-r--r--tools/perf/util/parse-events.h19
-rw-r--r--tools/perf/util/record.c4
14 files changed, 127 insertions, 32 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f7b8218785f6..3dbd8c59efc5 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1541,7 +1541,7 @@ static int setup_events(const char * const *attrs, unsigned len)
1541 unsigned i; 1541 unsigned i;
1542 1542
1543 for (i = 0; i < len; i++) { 1543 for (i = 0; i < len; i++) {
1544 if (parse_events(evsel_list, attrs[i])) 1544 if (parse_events(evsel_list, attrs[i], NULL))
1545 return -1; 1545 return -1;
1546 } 1546 }
1547 return 0; 1547 return 0;
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index f671ec37a7c4..ca0e480e741b 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -482,7 +482,7 @@ static int do_test_code_reading(bool try_kcore)
482 else 482 else
483 str = "cycles"; 483 str = "cycles";
484 pr_debug("Parsing event '%s'\n", str); 484 pr_debug("Parsing event '%s'\n", str);
485 ret = parse_events(evlist, str); 485 ret = parse_events(evlist, str, NULL);
486 if (ret < 0) { 486 if (ret < 0) {
487 pr_debug("parse_events failed\n"); 487 pr_debug("parse_events failed\n");
488 goto out_err; 488 goto out_err;
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index b8d8341b383e..3fa715987a5e 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -23,7 +23,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
23 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 23 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
24 __perf_evsel__hw_cache_type_op_res_name(type, op, i, 24 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
25 name, sizeof(name)); 25 name, sizeof(name));
26 err = parse_events(evlist, name); 26 err = parse_events(evlist, name, NULL);
27 if (err) 27 if (err)
28 ret = err; 28 ret = err;
29 } 29 }
@@ -71,7 +71,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
71 return -ENOMEM; 71 return -ENOMEM;
72 72
73 for (i = 0; i < nr_names; ++i) { 73 for (i = 0; i < nr_names; ++i) {
74 err = parse_events(evlist, names[i]); 74 err = parse_events(evlist, names[i], NULL);
75 if (err) { 75 if (err) {
76 pr_debug("failed to parse event '%s', err %d\n", 76 pr_debug("failed to parse event '%s', err %d\n",
77 names[i], err); 77 names[i], err);
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 18619966454c..b08a95a5ca1a 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -695,7 +695,7 @@ int test__hists_cumulate(void)
695 695
696 TEST_ASSERT_VAL("No memory", evlist); 696 TEST_ASSERT_VAL("No memory", evlist);
697 697
698 err = parse_events(evlist, "cpu-clock"); 698 err = parse_events(evlist, "cpu-clock", NULL);
699 if (err) 699 if (err)
700 goto out; 700 goto out;
701 701
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 59e53db7914c..108488cd71fa 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -108,10 +108,10 @@ int test__hists_filter(void)
108 108
109 TEST_ASSERT_VAL("No memory", evlist); 109 TEST_ASSERT_VAL("No memory", evlist);
110 110
111 err = parse_events(evlist, "cpu-clock"); 111 err = parse_events(evlist, "cpu-clock", NULL);
112 if (err) 112 if (err)
113 goto out; 113 goto out;
114 err = parse_events(evlist, "task-clock"); 114 err = parse_events(evlist, "task-clock", NULL);
115 if (err) 115 if (err)
116 goto out; 116 goto out;
117 117
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 278ba8344c23..34c61e4d3352 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -282,10 +282,10 @@ int test__hists_link(void)
282 if (evlist == NULL) 282 if (evlist == NULL)
283 return -ENOMEM; 283 return -ENOMEM;
284 284
285 err = parse_events(evlist, "cpu-clock"); 285 err = parse_events(evlist, "cpu-clock", NULL);
286 if (err) 286 if (err)
287 goto out; 287 goto out;
288 err = parse_events(evlist, "task-clock"); 288 err = parse_events(evlist, "task-clock", NULL);
289 if (err) 289 if (err)
290 goto out; 290 goto out;
291 291
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index b52c9faea224..d8a23db80094 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -590,7 +590,7 @@ int test__hists_output(void)
590 590
591 TEST_ASSERT_VAL("No memory", evlist); 591 TEST_ASSERT_VAL("No memory", evlist);
592 592
593 err = parse_events(evlist, "cpu-clock"); 593 err = parse_events(evlist, "cpu-clock", NULL);
594 if (err) 594 if (err)
595 goto out; 595 goto out;
596 596
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 7a5ab7b0b8f6..5b171d1e338b 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -78,8 +78,8 @@ int test__keep_tracking(void)
78 78
79 perf_evlist__set_maps(evlist, cpus, threads); 79 perf_evlist__set_maps(evlist, cpus, threads);
80 80
81 CHECK__(parse_events(evlist, "dummy:u")); 81 CHECK__(parse_events(evlist, "dummy:u", NULL));
82 CHECK__(parse_events(evlist, "cycles:u")); 82 CHECK__(parse_events(evlist, "cycles:u", NULL));
83 83
84 perf_evlist__config(evlist, &opts); 84 perf_evlist__config(evlist, &opts);
85 85
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 3de744961739..82d2a1636f7f 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1571,7 +1571,7 @@ static int test_event(struct evlist_test *e)
1571 if (evlist == NULL) 1571 if (evlist == NULL)
1572 return -ENOMEM; 1572 return -ENOMEM;
1573 1573
1574 ret = parse_events(evlist, e->name); 1574 ret = parse_events(evlist, e->name, NULL);
1575 if (ret) { 1575 if (ret) {
1576 pr_debug("failed to parse event '%s', err %d\n", 1576 pr_debug("failed to parse event '%s', err %d\n",
1577 e->name, ret); 1577 e->name, ret);
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index f238442b238a..5f49484f1abc 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -68,7 +68,7 @@ int test__perf_time_to_tsc(void)
68 68
69 perf_evlist__set_maps(evlist, cpus, threads); 69 perf_evlist__set_maps(evlist, cpus, threads);
70 70
71 CHECK__(parse_events(evlist, "cycles:u")); 71 CHECK__(parse_events(evlist, "cycles:u", NULL));
72 72
73 perf_evlist__config(evlist, &opts); 73 perf_evlist__config(evlist, &opts);
74 74
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index cc68648c7c55..0d31403ea593 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -347,7 +347,7 @@ int test__switch_tracking(void)
347 perf_evlist__set_maps(evlist, cpus, threads); 347 perf_evlist__set_maps(evlist, cpus, threads);
348 348
349 /* First event */ 349 /* First event */
350 err = parse_events(evlist, "cpu-clock:u"); 350 err = parse_events(evlist, "cpu-clock:u", NULL);
351 if (err) { 351 if (err) {
352 pr_debug("Failed to parse event dummy:u\n"); 352 pr_debug("Failed to parse event dummy:u\n");
353 goto out_err; 353 goto out_err;
@@ -356,7 +356,7 @@ int test__switch_tracking(void)
356 cpu_clocks_evsel = perf_evlist__last(evlist); 356 cpu_clocks_evsel = perf_evlist__last(evlist);
357 357
358 /* Second event */ 358 /* Second event */
359 err = parse_events(evlist, "cycles:u"); 359 err = parse_events(evlist, "cycles:u", NULL);
360 if (err) { 360 if (err) {
361 pr_debug("Failed to parse event cycles:u\n"); 361 pr_debug("Failed to parse event cycles:u\n");
362 goto out_err; 362 goto out_err;
@@ -371,7 +371,7 @@ int test__switch_tracking(void)
371 goto out; 371 goto out;
372 } 372 }
373 373
374 err = parse_events(evlist, sched_switch); 374 err = parse_events(evlist, sched_switch, NULL);
375 if (err) { 375 if (err) {
376 pr_debug("Failed to parse event %s\n", sched_switch); 376 pr_debug("Failed to parse event %s\n", sched_switch);
377 goto out_err; 377 goto out_err;
@@ -401,7 +401,7 @@ int test__switch_tracking(void)
401 perf_evsel__set_sample_bit(cycles_evsel, TIME); 401 perf_evsel__set_sample_bit(cycles_evsel, TIME);
402 402
403 /* Fourth event */ 403 /* Fourth event */
404 err = parse_events(evlist, "dummy:u"); 404 err = parse_events(evlist, "dummy:u", NULL);
405 if (err) { 405 if (err) {
406 pr_debug("Failed to parse event dummy:u\n"); 406 pr_debug("Failed to parse event dummy:u\n");
407 goto out_err; 407 goto out_err;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index be0655388b38..6978cc377957 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -17,6 +17,7 @@
17#include "parse-events-flex.h" 17#include "parse-events-flex.h"
18#include "pmu.h" 18#include "pmu.h"
19#include "thread_map.h" 19#include "thread_map.h"
20#include "asm/bug.h"
20 21
21#define MAX_NAME_LEN 100 22#define MAX_NAME_LEN 100
22 23
@@ -1019,11 +1020,13 @@ int parse_events_terms(struct list_head *terms, const char *str)
1019 return ret; 1020 return ret;
1020} 1021}
1021 1022
1022int parse_events(struct perf_evlist *evlist, const char *str) 1023int parse_events(struct perf_evlist *evlist, const char *str,
1024 struct parse_events_error *err)
1023{ 1025{
1024 struct parse_events_evlist data = { 1026 struct parse_events_evlist data = {
1025 .list = LIST_HEAD_INIT(data.list), 1027 .list = LIST_HEAD_INIT(data.list),
1026 .idx = evlist->nr_entries, 1028 .idx = evlist->nr_entries,
1029 .error = err,
1027 }; 1030 };
1028 int ret; 1031 int ret;
1029 1032
@@ -1044,16 +1047,87 @@ int parse_events(struct perf_evlist *evlist, const char *str)
1044 return ret; 1047 return ret;
1045} 1048}
1046 1049
1050#define MAX_WIDTH 1000
1051static int get_term_width(void)
1052{
1053 struct winsize ws;
1054
1055 get_term_dimensions(&ws);
1056 return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col;
1057}
1058
1059static void parse_events_print_error(struct parse_events_error *err,
1060 const char *event)
1061{
1062 const char *str = "invalid or unsupported event: ";
1063 char _buf[MAX_WIDTH];
1064 char *buf = (char *) event;
1065 int idx = 0;
1066
1067 if (err->str) {
1068 /* -2 for extra '' in the final fprintf */
1069 int width = get_term_width() - 2;
1070 int len_event = strlen(event);
1071 int len_str, max_len, cut = 0;
1072
1073 /*
1074 * Maximum error index indent, we will cut
1075 * the event string if it's bigger.
1076 */
1077 int max_err_idx = 10;
1078
1079 /*
1080 * Let's be specific with the message when
1081 * we have the precise error.
1082 */
1083 str = "event syntax error: ";
1084 len_str = strlen(str);
1085 max_len = width - len_str;
1086
1087 buf = _buf;
1088
1089 /* We're cutting from the beggining. */
1090 if (err->idx > max_err_idx)
1091 cut = err->idx - max_err_idx;
1092
1093 strncpy(buf, event + cut, max_len);
1094
1095 /* Mark cut parts with '..' on both sides. */
1096 if (cut)
1097 buf[0] = buf[1] = '.';
1098
1099 if ((len_event - cut) > max_len) {
1100 buf[max_len - 1] = buf[max_len - 2] = '.';
1101 buf[max_len] = 0;
1102 }
1103
1104 idx = len_str + err->idx - cut;
1105 }
1106
1107 fprintf(stderr, "%s'%s'\n", str, buf);
1108 if (idx) {
1109 fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str);
1110 if (err->help)
1111 fprintf(stderr, "\n%s\n", err->help);
1112 free(err->str);
1113 free(err->help);
1114 }
1115
1116 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
1117}
1118
1119#undef MAX_WIDTH
1120
1047int parse_events_option(const struct option *opt, const char *str, 1121int parse_events_option(const struct option *opt, const char *str,
1048 int unset __maybe_unused) 1122 int unset __maybe_unused)
1049{ 1123{
1050 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 1124 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
1051 int ret = parse_events(evlist, str); 1125 struct parse_events_error err = { .idx = 0, };
1126 int ret = parse_events(evlist, str, &err);
1127
1128 if (ret)
1129 parse_events_print_error(&err, str);
1052 1130
1053 if (ret) {
1054 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
1055 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
1056 }
1057 return ret; 1131 return ret;
1058} 1132}
1059 1133
@@ -1535,3 +1609,13 @@ void parse_events__free_terms(struct list_head *terms)
1535 list_for_each_entry_safe(term, h, terms, list) 1609 list_for_each_entry_safe(term, h, terms, list)
1536 free(term); 1610 free(term);
1537} 1611}
1612
1613void parse_events_evlist_error(struct parse_events_evlist *data,
1614 int idx, const char *str)
1615{
1616 struct parse_events_error *err = data->error;
1617
1618 err->idx = idx;
1619 err->str = strdup(str);
1620 WARN_ONCE(!err->str, "WARNING: failed to allocate error string");
1621}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 52a2dda4f954..5ac2ffa0a145 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -12,6 +12,7 @@
12struct list_head; 12struct list_head;
13struct perf_evsel; 13struct perf_evsel;
14struct perf_evlist; 14struct perf_evlist;
15struct parse_events_error;
15 16
16struct option; 17struct option;
17 18
@@ -29,7 +30,8 @@ const char *event_type(int type);
29 30
30extern int parse_events_option(const struct option *opt, const char *str, 31extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 32 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str); 33extern int parse_events(struct perf_evlist *evlist, const char *str,
34 struct parse_events_error *error);
33extern int parse_events_terms(struct list_head *terms, const char *str); 35extern int parse_events_terms(struct list_head *terms, const char *str);
34extern int parse_filter(const struct option *opt, const char *str, int unset); 36extern int parse_filter(const struct option *opt, const char *str, int unset);
35 37
@@ -74,10 +76,17 @@ struct parse_events_term {
74 bool used; 76 bool used;
75}; 77};
76 78
79struct parse_events_error {
80 int idx; /* index in the parsed string */
81 char *str; /* string to display at the index */
82 char *help; /* optional help string */
83};
84
77struct parse_events_evlist { 85struct parse_events_evlist {
78 struct list_head list; 86 struct list_head list;
79 int idx; 87 int idx;
80 int nr_groups; 88 int nr_groups;
89 struct parse_events_error *error;
81}; 90};
82 91
83struct parse_events_terms { 92struct parse_events_terms {
@@ -114,6 +123,8 @@ void parse_events__set_leader(char *name, struct list_head *list);
114void parse_events_update_lists(struct list_head *list_event, 123void parse_events_update_lists(struct list_head *list_event,
115 struct list_head *list_all); 124 struct list_head *list_all);
116void parse_events_error(void *data, void *scanner, char const *msg); 125void parse_events_error(void *data, void *scanner, char const *msg);
126void parse_events_evlist_error(struct parse_events_evlist *data,
127 int idx, const char *str);
117 128
118void print_events(const char *event_glob, bool name_only); 129void print_events(const char *event_glob, bool name_only);
119 130
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 0ccfa498f7b8..d457c523a33d 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -20,7 +20,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
20 if (!evlist) 20 if (!evlist)
21 return -ENOMEM; 21 return -ENOMEM;
22 22
23 if (parse_events(evlist, str)) 23 if (parse_events(evlist, str, NULL))
24 goto out_delete; 24 goto out_delete;
25 25
26 evsel = perf_evlist__first(evlist); 26 evsel = perf_evlist__first(evlist);
@@ -216,7 +216,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
216 if (!temp_evlist) 216 if (!temp_evlist)
217 return false; 217 return false;
218 218
219 err = parse_events(temp_evlist, str); 219 err = parse_events(temp_evlist, str, NULL);
220 if (err) 220 if (err)
221 goto out_delete; 221 goto out_delete;
222 222