diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 106 |
1 files changed, 65 insertions, 41 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8e395a538eb9..1e60ab70b2b1 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -28,6 +28,11 @@ static bool system_wide; | |||
28 | static const char *cpu_list; | 28 | static const char *cpu_list; |
29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
30 | 30 | ||
31 | struct perf_script { | ||
32 | struct perf_tool tool; | ||
33 | struct perf_session *session; | ||
34 | }; | ||
35 | |||
31 | enum perf_output_field { | 36 | enum perf_output_field { |
32 | PERF_OUTPUT_COMM = 1U << 0, | 37 | PERF_OUTPUT_COMM = 1U << 0, |
33 | PERF_OUTPUT_TID = 1U << 1, | 38 | PERF_OUTPUT_TID = 1U << 1, |
@@ -137,10 +142,11 @@ static const char *output_field2str(enum perf_output_field field) | |||
137 | 142 | ||
138 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) | 143 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) |
139 | 144 | ||
140 | static int perf_event_attr__check_stype(struct perf_event_attr *attr, | 145 | static int perf_evsel__check_stype(struct perf_evsel *evsel, |
141 | u64 sample_type, const char *sample_msg, | 146 | u64 sample_type, const char *sample_msg, |
142 | enum perf_output_field field) | 147 | enum perf_output_field field) |
143 | { | 148 | { |
149 | struct perf_event_attr *attr = &evsel->attr; | ||
144 | int type = attr->type; | 150 | int type = attr->type; |
145 | const char *evname; | 151 | const char *evname; |
146 | 152 | ||
@@ -148,7 +154,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr, | |||
148 | return 0; | 154 | return 0; |
149 | 155 | ||
150 | if (output[type].user_set) { | 156 | if (output[type].user_set) { |
151 | evname = __event_name(attr->type, attr->config); | 157 | evname = perf_evsel__name(evsel); |
152 | pr_err("Samples for '%s' event do not have %s attribute set. " | 158 | pr_err("Samples for '%s' event do not have %s attribute set. " |
153 | "Cannot print '%s' field.\n", | 159 | "Cannot print '%s' field.\n", |
154 | evname, sample_msg, output_field2str(field)); | 160 | evname, sample_msg, output_field2str(field)); |
@@ -157,7 +163,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr, | |||
157 | 163 | ||
158 | /* user did not ask for it explicitly so remove from the default list */ | 164 | /* user did not ask for it explicitly so remove from the default list */ |
159 | output[type].fields &= ~field; | 165 | output[type].fields &= ~field; |
160 | evname = __event_name(attr->type, attr->config); | 166 | evname = perf_evsel__name(evsel); |
161 | pr_debug("Samples for '%s' event do not have %s attribute set. " | 167 | pr_debug("Samples for '%s' event do not have %s attribute set. " |
162 | "Skipping '%s' field.\n", | 168 | "Skipping '%s' field.\n", |
163 | evname, sample_msg, output_field2str(field)); | 169 | evname, sample_msg, output_field2str(field)); |
@@ -175,8 +181,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
175 | return -EINVAL; | 181 | return -EINVAL; |
176 | 182 | ||
177 | if (PRINT_FIELD(IP)) { | 183 | if (PRINT_FIELD(IP)) { |
178 | if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", | 184 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", |
179 | PERF_OUTPUT_IP)) | 185 | PERF_OUTPUT_IP)) |
180 | return -EINVAL; | 186 | return -EINVAL; |
181 | 187 | ||
182 | if (!no_callchain && | 188 | if (!no_callchain && |
@@ -185,8 +191,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
185 | } | 191 | } |
186 | 192 | ||
187 | if (PRINT_FIELD(ADDR) && | 193 | if (PRINT_FIELD(ADDR) && |
188 | perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR", | 194 | perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", |
189 | PERF_OUTPUT_ADDR)) | 195 | PERF_OUTPUT_ADDR)) |
190 | return -EINVAL; | 196 | return -EINVAL; |
191 | 197 | ||
192 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | 198 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { |
@@ -208,18 +214,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
208 | } | 214 | } |
209 | 215 | ||
210 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && | 216 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && |
211 | perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID", | 217 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", |
212 | PERF_OUTPUT_TID|PERF_OUTPUT_PID)) | 218 | PERF_OUTPUT_TID|PERF_OUTPUT_PID)) |
213 | return -EINVAL; | 219 | return -EINVAL; |
214 | 220 | ||
215 | if (PRINT_FIELD(TIME) && | 221 | if (PRINT_FIELD(TIME) && |
216 | perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME", | 222 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", |
217 | PERF_OUTPUT_TIME)) | 223 | PERF_OUTPUT_TIME)) |
218 | return -EINVAL; | 224 | return -EINVAL; |
219 | 225 | ||
220 | if (PRINT_FIELD(CPU) && | 226 | if (PRINT_FIELD(CPU) && |
221 | perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU", | 227 | perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU", |
222 | PERF_OUTPUT_CPU)) | 228 | PERF_OUTPUT_CPU)) |
223 | return -EINVAL; | 229 | return -EINVAL; |
224 | 230 | ||
225 | return 0; | 231 | return 0; |
@@ -256,11 +262,13 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
256 | return 0; | 262 | return 0; |
257 | } | 263 | } |
258 | 264 | ||
259 | static void print_sample_start(struct perf_sample *sample, | 265 | static void print_sample_start(struct pevent *pevent, |
266 | struct perf_sample *sample, | ||
260 | struct thread *thread, | 267 | struct thread *thread, |
261 | struct perf_event_attr *attr) | 268 | struct perf_evsel *evsel) |
262 | { | 269 | { |
263 | int type; | 270 | int type; |
271 | struct perf_event_attr *attr = &evsel->attr; | ||
264 | struct event_format *event; | 272 | struct event_format *event; |
265 | const char *evname = NULL; | 273 | const char *evname = NULL; |
266 | unsigned long secs; | 274 | unsigned long secs; |
@@ -300,12 +308,18 @@ static void print_sample_start(struct perf_sample *sample, | |||
300 | 308 | ||
301 | if (PRINT_FIELD(EVNAME)) { | 309 | if (PRINT_FIELD(EVNAME)) { |
302 | if (attr->type == PERF_TYPE_TRACEPOINT) { | 310 | if (attr->type == PERF_TYPE_TRACEPOINT) { |
303 | type = trace_parse_common_type(sample->raw_data); | 311 | /* |
304 | event = trace_find_event(type); | 312 | * XXX Do we really need this here? |
313 | * perf_evlist__set_tracepoint_names should have done | ||
314 | * this already | ||
315 | */ | ||
316 | type = trace_parse_common_type(pevent, | ||
317 | sample->raw_data); | ||
318 | event = pevent_find_event(pevent, type); | ||
305 | if (event) | 319 | if (event) |
306 | evname = event->name; | 320 | evname = event->name; |
307 | } else | 321 | } else |
308 | evname = __event_name(attr->type, attr->config); | 322 | evname = perf_evsel__name(evsel); |
309 | 323 | ||
310 | printf("%s: ", evname ? evname : "[unknown]"); | 324 | printf("%s: ", evname ? evname : "[unknown]"); |
311 | } | 325 | } |
@@ -387,7 +401,7 @@ static void print_sample_bts(union perf_event *event, | |||
387 | printf(" "); | 401 | printf(" "); |
388 | else | 402 | else |
389 | printf("\n"); | 403 | printf("\n"); |
390 | perf_event__print_ip(event, sample, machine, evsel, | 404 | perf_event__print_ip(event, sample, machine, |
391 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), | 405 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), |
392 | PRINT_FIELD(SYMOFFSET)); | 406 | PRINT_FIELD(SYMOFFSET)); |
393 | } | 407 | } |
@@ -402,6 +416,7 @@ static void print_sample_bts(union perf_event *event, | |||
402 | } | 416 | } |
403 | 417 | ||
404 | static void process_event(union perf_event *event __unused, | 418 | static void process_event(union perf_event *event __unused, |
419 | struct pevent *pevent, | ||
405 | struct perf_sample *sample, | 420 | struct perf_sample *sample, |
406 | struct perf_evsel *evsel, | 421 | struct perf_evsel *evsel, |
407 | struct machine *machine, | 422 | struct machine *machine, |
@@ -412,7 +427,7 @@ static void process_event(union perf_event *event __unused, | |||
412 | if (output[attr->type].fields == 0) | 427 | if (output[attr->type].fields == 0) |
413 | return; | 428 | return; |
414 | 429 | ||
415 | print_sample_start(sample, thread, attr); | 430 | print_sample_start(pevent, sample, thread, evsel); |
416 | 431 | ||
417 | if (is_bts_event(attr)) { | 432 | if (is_bts_event(attr)) { |
418 | print_sample_bts(event, sample, evsel, machine, thread); | 433 | print_sample_bts(event, sample, evsel, machine, thread); |
@@ -420,7 +435,7 @@ static void process_event(union perf_event *event __unused, | |||
420 | } | 435 | } |
421 | 436 | ||
422 | if (PRINT_FIELD(TRACE)) | 437 | if (PRINT_FIELD(TRACE)) |
423 | print_trace_event(sample->cpu, sample->raw_data, | 438 | print_trace_event(pevent, sample->cpu, sample->raw_data, |
424 | sample->raw_size); | 439 | sample->raw_size); |
425 | 440 | ||
426 | if (PRINT_FIELD(ADDR)) | 441 | if (PRINT_FIELD(ADDR)) |
@@ -431,7 +446,7 @@ static void process_event(union perf_event *event __unused, | |||
431 | printf(" "); | 446 | printf(" "); |
432 | else | 447 | else |
433 | printf("\n"); | 448 | printf("\n"); |
434 | perf_event__print_ip(event, sample, machine, evsel, | 449 | perf_event__print_ip(event, sample, machine, |
435 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), | 450 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), |
436 | PRINT_FIELD(SYMOFFSET)); | 451 | PRINT_FIELD(SYMOFFSET)); |
437 | } | 452 | } |
@@ -451,7 +466,8 @@ static int default_stop_script(void) | |||
451 | return 0; | 466 | return 0; |
452 | } | 467 | } |
453 | 468 | ||
454 | static int default_generate_script(const char *outfile __unused) | 469 | static int default_generate_script(struct pevent *pevent __unused, |
470 | const char *outfile __unused) | ||
455 | { | 471 | { |
456 | return 0; | 472 | return 0; |
457 | } | 473 | } |
@@ -489,6 +505,7 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
489 | struct machine *machine) | 505 | struct machine *machine) |
490 | { | 506 | { |
491 | struct addr_location al; | 507 | struct addr_location al; |
508 | struct perf_script *scr = container_of(tool, struct perf_script, tool); | ||
492 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); | 509 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); |
493 | 510 | ||
494 | if (thread == NULL) { | 511 | if (thread == NULL) { |
@@ -520,24 +537,27 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
520 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) | 537 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
521 | return 0; | 538 | return 0; |
522 | 539 | ||
523 | scripting_ops->process_event(event, sample, evsel, machine, thread); | 540 | scripting_ops->process_event(event, scr->session->pevent, |
541 | sample, evsel, machine, thread); | ||
524 | 542 | ||
525 | evsel->hists.stats.total_period += sample->period; | 543 | evsel->hists.stats.total_period += sample->period; |
526 | return 0; | 544 | return 0; |
527 | } | 545 | } |
528 | 546 | ||
529 | static struct perf_tool perf_script = { | 547 | static struct perf_script perf_script = { |
530 | .sample = process_sample_event, | 548 | .tool = { |
531 | .mmap = perf_event__process_mmap, | 549 | .sample = process_sample_event, |
532 | .comm = perf_event__process_comm, | 550 | .mmap = perf_event__process_mmap, |
533 | .exit = perf_event__process_task, | 551 | .comm = perf_event__process_comm, |
534 | .fork = perf_event__process_task, | 552 | .exit = perf_event__process_task, |
535 | .attr = perf_event__process_attr, | 553 | .fork = perf_event__process_task, |
536 | .event_type = perf_event__process_event_type, | 554 | .attr = perf_event__process_attr, |
537 | .tracing_data = perf_event__process_tracing_data, | 555 | .event_type = perf_event__process_event_type, |
538 | .build_id = perf_event__process_build_id, | 556 | .tracing_data = perf_event__process_tracing_data, |
539 | .ordered_samples = true, | 557 | .build_id = perf_event__process_build_id, |
540 | .ordering_requires_timestamps = true, | 558 | .ordered_samples = true, |
559 | .ordering_requires_timestamps = true, | ||
560 | }, | ||
541 | }; | 561 | }; |
542 | 562 | ||
543 | extern volatile int session_done; | 563 | extern volatile int session_done; |
@@ -553,7 +573,7 @@ static int __cmd_script(struct perf_session *session) | |||
553 | 573 | ||
554 | signal(SIGINT, sig_handler); | 574 | signal(SIGINT, sig_handler); |
555 | 575 | ||
556 | ret = perf_session__process_events(session, &perf_script); | 576 | ret = perf_session__process_events(session, &perf_script.tool); |
557 | 577 | ||
558 | if (debug_mode) | 578 | if (debug_mode) |
559 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); | 579 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); |
@@ -1335,10 +1355,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1335 | if (!script_name) | 1355 | if (!script_name) |
1336 | setup_pager(); | 1356 | setup_pager(); |
1337 | 1357 | ||
1338 | session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); | 1358 | session = perf_session__new(input_name, O_RDONLY, 0, false, |
1359 | &perf_script.tool); | ||
1339 | if (session == NULL) | 1360 | if (session == NULL) |
1340 | return -ENOMEM; | 1361 | return -ENOMEM; |
1341 | 1362 | ||
1363 | perf_script.session = session; | ||
1364 | |||
1342 | if (cpu_list) { | 1365 | if (cpu_list) { |
1343 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) | 1366 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) |
1344 | return -1; | 1367 | return -1; |
@@ -1384,7 +1407,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1384 | return -1; | 1407 | return -1; |
1385 | } | 1408 | } |
1386 | 1409 | ||
1387 | err = scripting_ops->generate_script("perf-script"); | 1410 | err = scripting_ops->generate_script(session->pevent, |
1411 | "perf-script"); | ||
1388 | goto out; | 1412 | goto out; |
1389 | } | 1413 | } |
1390 | 1414 | ||