pkgsplit-perf.pl 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/perl -w
  2. #
  3. # pkgsplit-perf.pl Split IP samples on package names "/", eg, Java.
  4. #
  5. # This is for the creation of Java package flame graphs. Example steps:
  6. #
  7. # perf record -F 199 -a -- sleep 30; ./jmaps
  8. # perf script | ./pkgsplit-perf.pl | ./flamegraph.pl > out.svg
  9. #
  10. # Note that stack traces are not sampled (no -g), as we split Java package
  11. # names into frames rather than stack frames.
  12. #
  13. # (jmaps is a helper script for automating perf-map-agent: Java symbol dumps.)
  14. #
  15. # The default output of "perf script" varies between kernel versions, so we'll
  16. # need to deal with that here. I could make people use the perf script option
  17. # to pick fields, so our input is static, but A) I prefer the simplicity of
  18. # just saying: run "perf script", and B) the option to choose fields itself
  19. # changed between kernel versions! -f became -F.
  20. #
  21. # Copyright 2017 Netflix, Inc.
  22. # Licensed under the Apache License, Version 2.0 (the "License")
  23. #
  24. # 20-Sep-2016 Brendan Gregg Created this.
  25. use strict;
  26. my $include_pname = 1; # include process names in stacks
  27. my $include_pid = 0; # include process ID with process name
  28. my $include_tid = 0; # include process & thread ID with process name
  29. while (<>) {
  30. # filter comments
  31. next if /^#/;
  32. # filter idle events
  33. next if /xen_hypercall_sched_op|cpu_idle|native_safe_halt/;
  34. my ($pid, $tid, $pname);
  35. # Linux 3.13:
  36. # java 13905 [000] 8048.096572: cpu-clock: 7fd781ac3053 Ljava/util/Arrays$ArrayList;::toArray (/tmp/perf-12149.map)
  37. # java 8301 [050] 13527.392454: cycles: 7fa8a80d9bff Dictionary::find(int, unsigned int, Symbol*, ClassLoaderData*, Handle, Thread*) (/usr/lib/jvm/java-8-oracle-1.8.0.121/jre/lib/amd64/server/libjvm.so)
  38. # java 4567/8603 [023] 13527.389886: cycles: 7fa863349895 Lcom/google/gson/JsonObject;::add (/tmp/perf-4567.map)
  39. #
  40. # Linux 4.8:
  41. # java 30894 [007] 452884.077440: 10101010 cpu-clock: 7f0acc8eff67 Lsun/nio/ch/SocketChannelImpl;::read+0x27 (/tmp/perf-30849.map)
  42. # bash 26858/26858 [006] 5440237.995639: cpu-clock: 433573 [unknown] (/bin/bash)
  43. #
  44. if (/^\s+(\S.+?)\s+(\d+)\/*(\d+)*\s.*?:.*:/) {
  45. # parse process name and pid/tid
  46. if ($3) {
  47. ($pid, $tid) = ($2, $3);
  48. } else {
  49. ($pid, $tid) = ("?", $2);
  50. }
  51. if ($include_tid) {
  52. $pname = "$1-$pid/$tid";
  53. } elsif ($include_pid) {
  54. $pname = "$1-$pid";
  55. } else {
  56. $pname = $1;
  57. }
  58. $pname =~ tr/ /_/;
  59. } else {
  60. # not a match
  61. next;
  62. }
  63. # parse rest of line
  64. s/^.*?:.*?:\s+//;
  65. s/ \(.*?\)$//;
  66. chomp;
  67. my ($addr, $func) = split(' ', $_, 2);
  68. # strip Java's leading "L"
  69. $func =~ s/^L//;
  70. # replace numbers with X
  71. $func =~ s/[0-9]/X/g;
  72. # colon delimitered
  73. $func =~ s:/:;:g;
  74. print "$pname;$func 1\n";
  75. }