aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c155
1 files changed, 120 insertions, 35 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b45b09c13f7a..9f5fc5492141 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -12,6 +12,8 @@
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13#include "util/parse-options.h" 13#include "util/parse-options.h"
14#include "util/util.h" 14#include "util/util.h"
15#include "util/evlist.h"
16#include "util/evsel.h"
15 17
16static char const *script_name; 18static char const *script_name;
17static char const *generate_script_lang; 19static char const *generate_script_lang;
@@ -47,16 +49,65 @@ struct output_option {
47}; 49};
48 50
49/* default set to maintain compatibility with current format */ 51/* default set to maintain compatibility with current format */
50static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ 52static u64 output_fields[PERF_TYPE_MAX] = {
51 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ 53 [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
52 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE; 54 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
55 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
56
57 [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
58 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
59 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
60
61 [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
62 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
63 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
64};
53 65
54static bool output_set_by_user; 66static bool output_set_by_user;
55 67
56#define PRINT_FIELD(x) (output_fields & PERF_OUTPUT_##x) 68#define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x)
69
70static int perf_session__check_attr(struct perf_session *session,
71 struct perf_event_attr *attr)
72{
73 if (PRINT_FIELD(TRACE) &&
74 !perf_session__has_traces(session, "record -R"))
75 return -EINVAL;
76
77 if (PRINT_FIELD(SYM)) {
78 if (!(session->sample_type & PERF_SAMPLE_IP)) {
79 pr_err("Samples do not contain IP data.\n");
80 return -EINVAL;
81 }
82 if (!no_callchain &&
83 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
84 symbol_conf.use_callchain = false;
85 }
86
87 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
88 !(session->sample_type & PERF_SAMPLE_TID)) {
89 pr_err("Samples do not contain TID/PID data.\n");
90 return -EINVAL;
91 }
92
93 if (PRINT_FIELD(TIME) &&
94 !(session->sample_type & PERF_SAMPLE_TIME)) {
95 pr_err("Samples do not contain timestamps.\n");
96 return -EINVAL;
97 }
98
99 if (PRINT_FIELD(CPU) &&
100 !(session->sample_type & PERF_SAMPLE_CPU)) {
101 pr_err("Samples do not contain cpu.\n");
102 return -EINVAL;
103 }
104
105 return 0;
106}
57 107
58static void print_sample_start(struct perf_sample *sample, 108static void print_sample_start(struct perf_sample *sample,
59 struct thread *thread) 109 struct thread *thread,
110 struct perf_event_attr *attr)
60{ 111{
61 int type; 112 int type;
62 struct event *event; 113 struct event *event;
@@ -97,10 +148,13 @@ static void print_sample_start(struct perf_sample *sample,
97 } 148 }
98 149
99 if (PRINT_FIELD(EVNAME)) { 150 if (PRINT_FIELD(EVNAME)) {
100 type = trace_parse_common_type(sample->raw_data); 151 if (attr->type == PERF_TYPE_TRACEPOINT) {
101 event = trace_find_event(type); 152 type = trace_parse_common_type(sample->raw_data);
102 if (event) 153 event = trace_find_event(type);
103 evname = event->name; 154 if (event)
155 evname = event->name;
156 } else
157 evname = __event_name(attr->type, attr->config);
104 158
105 printf("%s: ", evname ? evname : "(unknown)"); 159 printf("%s: ", evname ? evname : "(unknown)");
106 } 160 }
@@ -108,10 +162,27 @@ static void print_sample_start(struct perf_sample *sample,
108 162
109static void process_event(union perf_event *event __unused, 163static void process_event(union perf_event *event __unused,
110 struct perf_sample *sample, 164 struct perf_sample *sample,
111 struct perf_session *session __unused, 165 struct perf_session *session,
112 struct thread *thread) 166 struct thread *thread)
113{ 167{
114 print_sample_start(sample, thread); 168 struct perf_event_attr *attr;
169 struct perf_evsel *evsel;
170
171 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
172 if (evsel == NULL) {
173 pr_err("Invalid data. Contains samples with id not in "
174 "its header!\n");
175 return;
176 }
177 attr = &evsel->attr;
178
179 if (output_fields[attr->type] == 0)
180 return;
181
182 if (perf_session__check_attr(session, attr) < 0)
183 return;
184
185 print_sample_start(sample, thread, attr);
115 186
116 if (PRINT_FIELD(TRACE)) 187 if (PRINT_FIELD(TRACE))
117 print_trace_event(sample->cpu, sample->raw_data, 188 print_trace_event(sample->cpu, sample->raw_data,
@@ -183,19 +254,17 @@ static int process_sample_event(union perf_event *event,
183 return -1; 254 return -1;
184 } 255 }
185 256
186 if (session->sample_type & PERF_SAMPLE_RAW) { 257 if (debug_mode) {
187 if (debug_mode) { 258 if (sample->time < last_timestamp) {
188 if (sample->time < last_timestamp) { 259 pr_err("Samples misordered, previous: %" PRIu64
189 pr_err("Samples misordered, previous: %" PRIu64 260 " this: %" PRIu64 "\n", last_timestamp,
190 " this: %" PRIu64 "\n", last_timestamp, 261 sample->time);
191 sample->time); 262 nr_unordered++;
192 nr_unordered++;
193 }
194 last_timestamp = sample->time;
195 return 0;
196 } 263 }
197 scripting_ops->process_event(event, sample, session, thread); 264 last_timestamp = sample->time;
265 return 0;
198 } 266 }
267 scripting_ops->process_event(event, sample, session, thread);
199 268
200 session->hists.stats.total_period += sample->period; 269 session->hists.stats.total_period += sample->period;
201 return 0; 270 return 0;
@@ -391,21 +460,40 @@ static int parse_output_fields(const struct option *opt __used,
391 int i, imax = sizeof(all_output_options) / sizeof(struct output_option); 460 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
392 int rc = 0; 461 int rc = 0;
393 char *str = strdup(arg); 462 char *str = strdup(arg);
463 int type = -1;
394 464
395 if (!str) 465 if (!str)
396 return -ENOMEM; 466 return -ENOMEM;
397 467
398 tok = strtok(str, ","); 468 tok = strtok(str, ":");
399 if (!tok) { 469 if (!tok) {
400 fprintf(stderr, "Invalid field string."); 470 fprintf(stderr,
471 "Invalid field string - not prepended with type.");
472 return -EINVAL;
473 }
474
475 /* first word should state which event type user
476 * is specifying the fields
477 */
478 if (!strcmp(tok, "hw"))
479 type = PERF_TYPE_HARDWARE;
480 else if (!strcmp(tok, "sw"))
481 type = PERF_TYPE_SOFTWARE;
482 else if (!strcmp(tok, "trace"))
483 type = PERF_TYPE_TRACEPOINT;
484 else {
485 fprintf(stderr, "Invalid event type in field string.");
401 return -EINVAL; 486 return -EINVAL;
402 } 487 }
403 488
404 output_fields = 0; 489 output_fields[type] = 0;
405 while (1) { 490 while (1) {
491 tok = strtok(NULL, ",");
492 if (!tok)
493 break;
406 for (i = 0; i < imax; ++i) { 494 for (i = 0; i < imax; ++i) {
407 if (strcmp(tok, all_output_options[i].str) == 0) { 495 if (strcmp(tok, all_output_options[i].str) == 0) {
408 output_fields |= all_output_options[i].field; 496 output_fields[type] |= all_output_options[i].field;
409 break; 497 break;
410 } 498 }
411 } 499 }
@@ -414,10 +502,11 @@ static int parse_output_fields(const struct option *opt __used,
414 rc = -EINVAL; 502 rc = -EINVAL;
415 break; 503 break;
416 } 504 }
505 }
417 506
418 tok = strtok(NULL, ","); 507 if (output_fields[type] == 0) {
419 if (!tok) 508 pr_debug("No fields requested for %s type. "
420 break; 509 "Events will not be displayed\n", event_type(type));
421 } 510 }
422 511
423 output_set_by_user = true; 512 output_set_by_user = true;
@@ -747,7 +836,7 @@ static const struct option options[] = {
747 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 836 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
748 "Look for files with symbols relative to this directory"), 837 "Look for files with symbols relative to this directory"),
749 OPT_CALLBACK('f', "fields", NULL, "str", 838 OPT_CALLBACK('f', "fields", NULL, "str",
750 "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace,sym", 839 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym",
751 parse_output_fields), 840 parse_output_fields),
752 841
753 OPT_END() 842 OPT_END()
@@ -929,15 +1018,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
929 if (session == NULL) 1018 if (session == NULL)
930 return -ENOMEM; 1019 return -ENOMEM;
931 1020
932 if (!no_callchain && (session->sample_type & PERF_SAMPLE_CALLCHAIN)) 1021 if (!no_callchain)
933 symbol_conf.use_callchain = true; 1022 symbol_conf.use_callchain = true;
934 else 1023 else
935 symbol_conf.use_callchain = false; 1024 symbol_conf.use_callchain = false;
936 1025
937 if (strcmp(input_name, "-") &&
938 !perf_session__has_traces(session, "record -R"))
939 return -EINVAL;
940
941 if (generate_script_lang) { 1026 if (generate_script_lang) {
942 struct stat perf_stat; 1027 struct stat perf_stat;
943 int input; 1028 int input;