diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-perl.c | 114 |
1 files changed, 106 insertions, 8 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index b3aabc0d4eb0..1d160855cda9 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <perl.h> | 31 | #include <perl.h> |
32 | 32 | ||
33 | #include "../../perf.h" | 33 | #include "../../perf.h" |
34 | #include "../callchain.h" | ||
35 | #include "../machine.h" | ||
34 | #include "../thread.h" | 36 | #include "../thread.h" |
35 | #include "../event.h" | 37 | #include "../event.h" |
36 | #include "../trace-event.h" | 38 | #include "../trace-event.h" |
@@ -248,10 +250,78 @@ static void define_event_symbols(struct event_format *event, | |||
248 | define_event_symbols(event, ev_name, args->next); | 250 | define_event_symbols(event, ev_name, args->next); |
249 | } | 251 | } |
250 | 252 | ||
253 | static SV *perl_process_callchain(struct perf_sample *sample, | ||
254 | struct perf_evsel *evsel, | ||
255 | struct addr_location *al) | ||
256 | { | ||
257 | AV *list; | ||
258 | |||
259 | list = newAV(); | ||
260 | if (!list) | ||
261 | goto exit; | ||
262 | |||
263 | if (!symbol_conf.use_callchain || !sample->callchain) | ||
264 | goto exit; | ||
265 | |||
266 | if (thread__resolve_callchain(al->thread, evsel, | ||
267 | sample, NULL, NULL, | ||
268 | PERF_MAX_STACK_DEPTH) != 0) { | ||
269 | pr_err("Failed to resolve callchain. Skipping\n"); | ||
270 | goto exit; | ||
271 | } | ||
272 | callchain_cursor_commit(&callchain_cursor); | ||
273 | |||
274 | |||
275 | while (1) { | ||
276 | HV *elem; | ||
277 | struct callchain_cursor_node *node; | ||
278 | node = callchain_cursor_current(&callchain_cursor); | ||
279 | if (!node) | ||
280 | break; | ||
281 | |||
282 | elem = newHV(); | ||
283 | if (!elem) | ||
284 | goto exit; | ||
285 | |||
286 | hv_stores(elem, "ip", newSVuv(node->ip)); | ||
287 | |||
288 | if (node->sym) { | ||
289 | HV *sym = newHV(); | ||
290 | if (!sym) | ||
291 | goto exit; | ||
292 | hv_stores(sym, "start", newSVuv(node->sym->start)); | ||
293 | hv_stores(sym, "end", newSVuv(node->sym->end)); | ||
294 | hv_stores(sym, "binding", newSVuv(node->sym->binding)); | ||
295 | hv_stores(sym, "name", newSVpvn(node->sym->name, | ||
296 | node->sym->namelen)); | ||
297 | hv_stores(elem, "sym", newRV_noinc((SV*)sym)); | ||
298 | } | ||
299 | |||
300 | if (node->map) { | ||
301 | struct map *map = node->map; | ||
302 | const char *dsoname = "[unknown]"; | ||
303 | if (map && map->dso && (map->dso->name || map->dso->long_name)) { | ||
304 | if (symbol_conf.show_kernel_path && map->dso->long_name) | ||
305 | dsoname = map->dso->long_name; | ||
306 | else if (map->dso->name) | ||
307 | dsoname = map->dso->name; | ||
308 | } | ||
309 | hv_stores(elem, "dso", newSVpv(dsoname,0)); | ||
310 | } | ||
311 | |||
312 | callchain_cursor_advance(&callchain_cursor); | ||
313 | av_push(list, newRV_noinc((SV*)elem)); | ||
314 | } | ||
315 | |||
316 | exit: | ||
317 | return newRV_noinc((SV*)list); | ||
318 | } | ||
319 | |||
251 | static void perl_process_tracepoint(struct perf_sample *sample, | 320 | static void perl_process_tracepoint(struct perf_sample *sample, |
252 | struct perf_evsel *evsel, | 321 | struct perf_evsel *evsel, |
253 | struct thread *thread) | 322 | struct addr_location *al) |
254 | { | 323 | { |
324 | struct thread *thread = al->thread; | ||
255 | struct event_format *event = evsel->tp_format; | 325 | struct event_format *event = evsel->tp_format; |
256 | struct format_field *field; | 326 | struct format_field *field; |
257 | static char handler[256]; | 327 | static char handler[256]; |
@@ -295,6 +365,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, | |||
295 | XPUSHs(sv_2mortal(newSVuv(ns))); | 365 | XPUSHs(sv_2mortal(newSVuv(ns))); |
296 | XPUSHs(sv_2mortal(newSViv(pid))); | 366 | XPUSHs(sv_2mortal(newSViv(pid))); |
297 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); | 367 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); |
368 | XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); | ||
298 | 369 | ||
299 | /* common fields other than pid can be accessed via xsub fns */ | 370 | /* common fields other than pid can be accessed via xsub fns */ |
300 | 371 | ||
@@ -329,6 +400,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, | |||
329 | XPUSHs(sv_2mortal(newSVuv(nsecs))); | 400 | XPUSHs(sv_2mortal(newSVuv(nsecs))); |
330 | XPUSHs(sv_2mortal(newSViv(pid))); | 401 | XPUSHs(sv_2mortal(newSViv(pid))); |
331 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); | 402 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); |
403 | XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); | ||
332 | call_pv("main::trace_unhandled", G_SCALAR); | 404 | call_pv("main::trace_unhandled", G_SCALAR); |
333 | } | 405 | } |
334 | SPAGAIN; | 406 | SPAGAIN; |
@@ -366,7 +438,7 @@ static void perl_process_event(union perf_event *event, | |||
366 | struct perf_evsel *evsel, | 438 | struct perf_evsel *evsel, |
367 | struct addr_location *al) | 439 | struct addr_location *al) |
368 | { | 440 | { |
369 | perl_process_tracepoint(sample, evsel, al->thread); | 441 | perl_process_tracepoint(sample, evsel, al); |
370 | perl_process_event_generic(event, sample, evsel); | 442 | perl_process_event_generic(event, sample, evsel); |
371 | } | 443 | } |
372 | 444 | ||
@@ -490,7 +562,27 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
490 | fprintf(ofp, "use Perf::Trace::Util;\n\n"); | 562 | fprintf(ofp, "use Perf::Trace::Util;\n\n"); |
491 | 563 | ||
492 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); | 564 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); |
493 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); | 565 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n"); |
566 | |||
567 | |||
568 | fprintf(ofp, "\n\ | ||
569 | sub print_backtrace\n\ | ||
570 | {\n\ | ||
571 | my $callchain = shift;\n\ | ||
572 | for my $node (@$callchain)\n\ | ||
573 | {\n\ | ||
574 | if(exists $node->{sym})\n\ | ||
575 | {\n\ | ||
576 | printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\ | ||
577 | }\n\ | ||
578 | else\n\ | ||
579 | {\n\ | ||
580 | printf( \"\\t[\\%%x]\\n\", $node{ip});\n\ | ||
581 | }\n\ | ||
582 | }\n\ | ||
583 | }\n\n\ | ||
584 | "); | ||
585 | |||
494 | 586 | ||
495 | while ((event = trace_find_next_event(pevent, event))) { | 587 | while ((event = trace_find_next_event(pevent, event))) { |
496 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); | 588 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); |
@@ -502,7 +594,8 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
502 | fprintf(ofp, "$common_secs, "); | 594 | fprintf(ofp, "$common_secs, "); |
503 | fprintf(ofp, "$common_nsecs,\n"); | 595 | fprintf(ofp, "$common_nsecs,\n"); |
504 | fprintf(ofp, "\t $common_pid, "); | 596 | fprintf(ofp, "\t $common_pid, "); |
505 | fprintf(ofp, "$common_comm,\n\t "); | 597 | fprintf(ofp, "$common_comm, "); |
598 | fprintf(ofp, "$common_callchain,\n\t "); | ||
506 | 599 | ||
507 | not_first = 0; | 600 | not_first = 0; |
508 | count = 0; | 601 | count = 0; |
@@ -519,7 +612,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
519 | 612 | ||
520 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " | 613 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " |
521 | "$common_secs, $common_nsecs,\n\t " | 614 | "$common_secs, $common_nsecs,\n\t " |
522 | "$common_pid, $common_comm);\n\n"); | 615 | "$common_pid, $common_comm, $common_callchain);\n\n"); |
523 | 616 | ||
524 | fprintf(ofp, "\tprintf(\""); | 617 | fprintf(ofp, "\tprintf(\""); |
525 | 618 | ||
@@ -581,17 +674,22 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
581 | fprintf(ofp, "$%s", f->name); | 674 | fprintf(ofp, "$%s", f->name); |
582 | } | 675 | } |
583 | 676 | ||
584 | fprintf(ofp, ");\n"); | 677 | fprintf(ofp, ");\n\n"); |
678 | |||
679 | fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); | ||
680 | |||
585 | fprintf(ofp, "}\n\n"); | 681 | fprintf(ofp, "}\n\n"); |
586 | } | 682 | } |
587 | 683 | ||
588 | fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " | 684 | fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " |
589 | "$common_cpu, $common_secs, $common_nsecs,\n\t " | 685 | "$common_cpu, $common_secs, $common_nsecs,\n\t " |
590 | "$common_pid, $common_comm) = @_;\n\n"); | 686 | "$common_pid, $common_comm, $common_callchain) = @_;\n\n"); |
591 | 687 | ||
592 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " | 688 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " |
593 | "$common_secs, $common_nsecs,\n\t $common_pid, " | 689 | "$common_secs, $common_nsecs,\n\t $common_pid, " |
594 | "$common_comm);\n}\n\n"); | 690 | "$common_comm, $common_callchain);\n"); |
691 | fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); | ||
692 | fprintf(ofp, "}\n\n"); | ||
595 | 693 | ||
596 | fprintf(ofp, "sub print_header\n{\n" | 694 | fprintf(ofp, "sub print_header\n{\n" |
597 | "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" | 695 | "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" |