-
Notifications
You must be signed in to change notification settings - Fork 354
/
line-prof-by-func
executable file
·110 lines (88 loc) · 2.44 KB
/
line-prof-by-func
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env perl
use strict;
#use warnings;
use Getopt::Std qw( getopts );
my %opts;
getopts("l:f:p:h", \%opts) or usage();
if ($opts{h}) {
usage();
}
my %addr2line;
my %hits;
my $addr;
my $func = $opts{f} or die "No -f <func> specified.\n";
if ($func !~ /^[_a-zA-Z]\w+$/) {
die "Bad function name: $func\n";
}
my $lib = $opts{l} or die "No -l <lib> specified.\n";
my $pid = $opts{p} or die "No -p <pid> specified.\n";
my $mapsfile = "/proc/$pid/maps";
open my $maps, "<$mapsfile"
or die "Cannot open $mapsfile for reading: $!\n";
my $libfile;
my @maps;
while (<$maps>) {
if (/^([a-f0-9]+)-([a-f0-9]+) [-r][-w]xp .*? (\/\S*?\Q$lib\E\S*)$/) {
push @maps, [hex($1), hex($2)];
if (!defined $libfile) {
$libfile = $3;
print "Found library $libfile for $lib.\n";
}
}
}
close $maps;
if (!@maps) {
die "No $lib maps found in process $pid.\n";
}
my $infile = shift or die "No input file specified.\n";
open my $in, "<$infile"
or die "Cannot open $infile for reading: $!\n";
while (<$in>) {
if (/^ (0x[a-f0-9]+) : $func\b/) {
$addr = $1;
} elsif (/^\t(\d+)$/) {
my $cnt = $1;
if ($addr) {
$addr = hex($addr);
my $line = $addr2line{$addr};
if (!$line) {
my $startaddr;
for my $map (@maps) {
if ($addr >= $map->[0] && $addr <= $map->[1]) {
$startaddr = $map->[0];
}
}
if (!$startaddr) {
warn "Addr $addr not found in memory maps.\n";
undef $addr;
next;
}
my $a = sprintf("%#x", $addr - $startaddr);
#warn "addr: $a\n";
$line = `addr2line -s -i -e $libfile $a`;
chomp $line;
$line =~ s/\n+/ < /g;
#warn "line: $line\n";
$addr2line{$addr} = $line;
}
$hits{$line} += $cnt;
undef $addr;
}
}
}
close $in;
my (@entries, $total);
$total = 0;
while (my ($k, $v) = each %hits) {
push @entries, [$k, $v];
$total += $v;
}
@entries = sort { $b->[1] <=> $a->[1] } @entries;
for (@entries) {
my $cnt = $_->[1];
my $ratio = $cnt * 100 / $total;
printf "%.02f%% (%d) %s\n", $ratio, $cnt, $_->[0];
}
sub usage {
die "Usage: $0 -f <func> -l <lib> -p <pid> <bt-file>\n";
}