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.c310
1 files changed, 279 insertions, 31 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b766c2a9ac97..ac574ea23917 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;
@@ -19,6 +21,175 @@ static bool debug_mode;
19static u64 last_timestamp; 21static u64 last_timestamp;
20static u64 nr_unordered; 22static u64 nr_unordered;
21extern const struct option record_options[]; 23extern const struct option record_options[];
24static bool no_callchain;
25
26enum perf_output_field {
27 PERF_OUTPUT_COMM = 1U << 0,
28 PERF_OUTPUT_TID = 1U << 1,
29 PERF_OUTPUT_PID = 1U << 2,
30 PERF_OUTPUT_TIME = 1U << 3,
31 PERF_OUTPUT_CPU = 1U << 4,
32 PERF_OUTPUT_EVNAME = 1U << 5,
33 PERF_OUTPUT_TRACE = 1U << 6,
34 PERF_OUTPUT_SYM = 1U << 7,
35};
36
37struct output_option {
38 const char *str;
39 enum perf_output_field field;
40} all_output_options[] = {
41 {.str = "comm", .field = PERF_OUTPUT_COMM},
42 {.str = "tid", .field = PERF_OUTPUT_TID},
43 {.str = "pid", .field = PERF_OUTPUT_PID},
44 {.str = "time", .field = PERF_OUTPUT_TIME},
45 {.str = "cpu", .field = PERF_OUTPUT_CPU},
46 {.str = "event", .field = PERF_OUTPUT_EVNAME},
47 {.str = "trace", .field = PERF_OUTPUT_TRACE},
48 {.str = "sym", .field = PERF_OUTPUT_SYM},
49};
50
51/* default set to maintain compatibility with current format */
52static u64 output_fields[PERF_TYPE_MAX] = {
53 [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
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};
65
66static bool output_set_by_user;
67
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}
107
108static void print_sample_start(struct perf_sample *sample,
109 struct thread *thread,
110 struct perf_event_attr *attr)
111{
112 int type;
113 struct event *event;
114 const char *evname = NULL;
115 unsigned long secs;
116 unsigned long usecs;
117 unsigned long long nsecs;
118
119 if (PRINT_FIELD(COMM)) {
120 if (latency_format)
121 printf("%8.8s ", thread->comm);
122 else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
123 printf("%s ", thread->comm);
124 else
125 printf("%16s ", thread->comm);
126 }
127
128 if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
129 printf("%5d/%-5d ", sample->pid, sample->tid);
130 else if (PRINT_FIELD(PID))
131 printf("%5d ", sample->pid);
132 else if (PRINT_FIELD(TID))
133 printf("%5d ", sample->tid);
134
135 if (PRINT_FIELD(CPU)) {
136 if (latency_format)
137 printf("%3d ", sample->cpu);
138 else
139 printf("[%03d] ", sample->cpu);
140 }
141
142 if (PRINT_FIELD(TIME)) {
143 nsecs = sample->time;
144 secs = nsecs / NSECS_PER_SEC;
145 nsecs -= secs * NSECS_PER_SEC;
146 usecs = nsecs / NSECS_PER_USEC;
147 printf("%5lu.%06lu: ", secs, usecs);
148 }
149
150 if (PRINT_FIELD(EVNAME)) {
151 if (attr->type == PERF_TYPE_TRACEPOINT) {
152 type = trace_parse_common_type(sample->raw_data);
153 event = trace_find_event(type);
154 if (event)
155 evname = event->name;
156 } else
157 evname = __event_name(attr->type, attr->config);
158
159 printf("%s: ", evname ? evname : "(unknown)");
160 }
161}
162
163static void process_event(union perf_event *event __unused,
164 struct perf_sample *sample,
165 struct perf_evsel *evsel,
166 struct perf_session *session,
167 struct thread *thread)
168{
169 struct perf_event_attr *attr = &evsel->attr;
170
171 if (output_fields[attr->type] == 0)
172 return;
173
174 if (perf_session__check_attr(session, attr) < 0)
175 return;
176
177 print_sample_start(sample, thread, attr);
178
179 if (PRINT_FIELD(TRACE))
180 print_trace_event(sample->cpu, sample->raw_data,
181 sample->raw_size);
182
183 if (PRINT_FIELD(SYM)) {
184 if (!symbol_conf.use_callchain)
185 printf(" ");
186 else
187 printf("\n");
188 perf_session__print_symbols(event, sample, session);
189 }
190
191 printf("\n");
192}
22 193
23static int default_start_script(const char *script __unused, 194static int default_start_script(const char *script __unused,
24 int argc __unused, 195 int argc __unused,
@@ -40,7 +211,7 @@ static int default_generate_script(const char *outfile __unused)
40static struct scripting_ops default_scripting_ops = { 211static struct scripting_ops default_scripting_ops = {
41 .start_script = default_start_script, 212 .start_script = default_start_script,
42 .stop_script = default_stop_script, 213 .stop_script = default_stop_script,
43 .process_event = print_event, 214 .process_event = process_event,
44 .generate_script = default_generate_script, 215 .generate_script = default_generate_script,
45}; 216};
46 217
@@ -63,7 +234,9 @@ static int cleanup_scripting(void)
63 234
64static char const *input_name = "perf.data"; 235static char const *input_name = "perf.data";
65 236
66static int process_sample_event(event_t *event, struct sample_data *sample, 237static int process_sample_event(union perf_event *event,
238 struct perf_sample *sample,
239 struct perf_evsel *evsel,
67 struct perf_session *session) 240 struct perf_session *session)
68{ 241{
69 struct thread *thread = perf_session__findnew(session, event->ip.pid); 242 struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -74,40 +247,34 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
74 return -1; 247 return -1;
75 } 248 }
76 249
77 if (session->sample_type & PERF_SAMPLE_RAW) { 250 if (debug_mode) {
78 if (debug_mode) { 251 if (sample->time < last_timestamp) {
79 if (sample->time < last_timestamp) { 252 pr_err("Samples misordered, previous: %" PRIu64
80 pr_err("Samples misordered, previous: %" PRIu64 253 " this: %" PRIu64 "\n", last_timestamp,
81 " this: %" PRIu64 "\n", last_timestamp, 254 sample->time);
82 sample->time); 255 nr_unordered++;
83 nr_unordered++;
84 }
85 last_timestamp = sample->time;
86 return 0;
87 } 256 }
88 /* 257 last_timestamp = sample->time;
89 * FIXME: better resolve from pid from the struct trace_entry 258 return 0;
90 * field, although it should be the same than this perf
91 * event pid
92 */
93 scripting_ops->process_event(sample->cpu, sample->raw_data,
94 sample->raw_size,
95 sample->time, thread->comm);
96 } 259 }
260 scripting_ops->process_event(event, sample, evsel, session, thread);
97 261
98 session->hists.stats.total_period += sample->period; 262 session->hists.stats.total_period += sample->period;
99 return 0; 263 return 0;
100} 264}
101 265
102static struct perf_event_ops event_ops = { 266static struct perf_event_ops event_ops = {
103 .sample = process_sample_event, 267 .sample = process_sample_event,
104 .comm = event__process_comm, 268 .mmap = perf_event__process_mmap,
105 .attr = event__process_attr, 269 .comm = perf_event__process_comm,
106 .event_type = event__process_event_type, 270 .exit = perf_event__process_task,
107 .tracing_data = event__process_tracing_data, 271 .fork = perf_event__process_task,
108 .build_id = event__process_build_id, 272 .attr = perf_event__process_attr,
109 .ordering_requires_timestamps = true, 273 .event_type = perf_event__process_event_type,
274 .tracing_data = perf_event__process_tracing_data,
275 .build_id = perf_event__process_build_id,
110 .ordered_samples = true, 276 .ordered_samples = true,
277 .ordering_requires_timestamps = true,
111}; 278};
112 279
113extern volatile int session_done; 280extern volatile int session_done;
@@ -279,6 +446,68 @@ static int parse_scriptname(const struct option *opt __used,
279 return 0; 446 return 0;
280} 447}
281 448
449static int parse_output_fields(const struct option *opt __used,
450 const char *arg, int unset __used)
451{
452 char *tok;
453 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
454 int rc = 0;
455 char *str = strdup(arg);
456 int type = -1;
457
458 if (!str)
459 return -ENOMEM;
460
461 tok = strtok(str, ":");
462 if (!tok) {
463 fprintf(stderr,
464 "Invalid field string - not prepended with type.");
465 return -EINVAL;
466 }
467
468 /* first word should state which event type user
469 * is specifying the fields
470 */
471 if (!strcmp(tok, "hw"))
472 type = PERF_TYPE_HARDWARE;
473 else if (!strcmp(tok, "sw"))
474 type = PERF_TYPE_SOFTWARE;
475 else if (!strcmp(tok, "trace"))
476 type = PERF_TYPE_TRACEPOINT;
477 else {
478 fprintf(stderr, "Invalid event type in field string.");
479 return -EINVAL;
480 }
481
482 output_fields[type] = 0;
483 while (1) {
484 tok = strtok(NULL, ",");
485 if (!tok)
486 break;
487 for (i = 0; i < imax; ++i) {
488 if (strcmp(tok, all_output_options[i].str) == 0) {
489 output_fields[type] |= all_output_options[i].field;
490 break;
491 }
492 }
493 if (i == imax) {
494 fprintf(stderr, "Invalid field requested.");
495 rc = -EINVAL;
496 break;
497 }
498 }
499
500 if (output_fields[type] == 0) {
501 pr_debug("No fields requested for %s type. "
502 "Events will not be displayed\n", event_type(type));
503 }
504
505 output_set_by_user = true;
506
507 free(str);
508 return rc;
509}
510
282/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ 511/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
283static int is_directory(const char *base_path, const struct dirent *dent) 512static int is_directory(const char *base_path, const struct dirent *dent)
284{ 513{
@@ -591,6 +820,17 @@ static const struct option options[] = {
591 "input file name"), 820 "input file name"),
592 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 821 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
593 "do various checks like samples ordering and lost events"), 822 "do various checks like samples ordering and lost events"),
823 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
824 "file", "vmlinux pathname"),
825 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
826 "file", "kallsyms pathname"),
827 OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
828 "When printing symbols do not display call chain"),
829 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
830 "Look for files with symbols relative to this directory"),
831 OPT_CALLBACK('f', "fields", NULL, "str",
832 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym",
833 parse_output_fields),
594 834
595 OPT_END() 835 OPT_END()
596}; 836};
@@ -771,14 +1011,22 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
771 if (session == NULL) 1011 if (session == NULL)
772 return -ENOMEM; 1012 return -ENOMEM;
773 1013
774 if (strcmp(input_name, "-") && 1014 if (!no_callchain)
775 !perf_session__has_traces(session, "record -R")) 1015 symbol_conf.use_callchain = true;
776 return -EINVAL; 1016 else
1017 symbol_conf.use_callchain = false;
777 1018
778 if (generate_script_lang) { 1019 if (generate_script_lang) {
779 struct stat perf_stat; 1020 struct stat perf_stat;
1021 int input;
1022
1023 if (output_set_by_user) {
1024 fprintf(stderr,
1025 "custom fields not supported for generated scripts");
1026 return -1;
1027 }
780 1028
781 int input = open(input_name, O_RDONLY); 1029 input = open(input_name, O_RDONLY);
782 if (input < 0) { 1030 if (input < 0) {
783 perror("failed to open file"); 1031 perror("failed to open file");
784 exit(-1); 1032 exit(-1);