aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorDima Kogan <dima@secretsauce.net>2016-03-29 11:47:53 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-03-30 10:14:09 -0400
commitf7380c12ec6cfd69f274ba6181cd01c764f877bb (patch)
treeba89f3cad389a073b0ae88878e9fa6f10d9ce513 /tools/perf/util
parent37194f443a5a7157866ba68b04827e111100167b (diff)
perf script perl: Perl scripts now get a backtrace, like the python ones
We have some infrastructure to use perl or python to analyze logs generated by perf. Prior to this patch, only the python tools had access to backtrace information. This patch makes this information available to perl scripts as well. Example: Let's look at malloc() calls made by the seq utility. First we create a probe point: $ perf probe -x /lib/x86_64-linux-gnu/libc.so.6 malloc Added new events: ... Now we run seq, while monitoring malloc() calls with perf $ perf record --call-graph=dwarf -e probe_libc:malloc seq 5 1 2 3 4 5 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.064 MB perf.data (6 samples) ] We can use perf to look at its log to see the malloc calls and the backtrace $ perf script seq 14195 [000] 1927993.748254: probe_libc:malloc: (7f9ff8edd320) bytes=0x22 7f9ff8edd320 malloc (/lib/x86_64-linux-gnu/libc-2.22.so) 7f9ff8e8eab0 set_binding_values.part.0 (/lib/x86_64-linux-gnu/libc-2.22.so) 7f9ff8e8eda1 __bindtextdomain (/lib/x86_64-linux-gnu/libc-2.22.so) 401b22 main (/usr/bin/seq) 7f9ff8e82610 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.22.so) 402799 _start (/usr/bin/seq) ... We can also use the scripting facilities. We create a skeleton perl script that simply prints out the events $ perf script -g perl generated Perl script: perf-script.pl We can then use this script to see the malloc() calls with a backtrace. Prior to this patch, the backtrace was not available to the perl scripts. $ perf script -s perf-script.pl probe_libc::malloc 0 1927993.748254260 14195 seq __probe_ip=140325052863264, bytes=34 [7f9ff8edd320] malloc [7f9ff8e8eab0] set_binding_values.part.0 [7f9ff8e8eda1] __bindtextdomain [401b22] main [7f9ff8e82610] __libc_start_main [402799] _start ... Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Link: http://lkml.kernel.org/r/87mvphzld0.fsf@secretsauce.net Signed-off-by: Dima Kogan <dima@secretsauce.net>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c114
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
253static 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
316exit:
317 return newRV_noinc((SV*)list);
318}
319
251static void perl_process_tracepoint(struct perf_sample *sample, 320static 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\
569sub 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"