Whamcloud - gitweb
b=15977 analyse only consistent part of the log
[fs/lustre-release.git] / lustre / tests / leak_finder.pl
1 #!/usr/bin/perl -w
2
3 use IO::Handle;
4
5 STDOUT->autoflush(1);
6 STDERR->autoflush(1);
7
8 my ($line, $memory);
9 my $debug_line = 0;
10
11 my $total = 0;
12 my $max = 0;
13
14 my @parsed;
15 my %cpu;
16 my $start_time = 0;
17
18 if (!defined($ARGV[0])) {
19         print "No log file specified\n";
20         exit
21 }
22
23 open(INFILE, $ARGV[0]);
24 while ($line = <INFILE>) {
25     if ($line =~ m/^(.*)\((.*):(\d+):(.*)\(\)\)/) {
26         @parsed = split(":", $1);
27         if (substr ($parsed[2], -1, 1) eq "F") {
28             chop $parsed[2];
29             $cpu{$parsed[2]} = 0;
30         } else {
31             if (!defined($cpu{$parsed[2]})) {
32                 $cpu{$parsed[2]} = $parsed[3];
33             }
34         }
35     }
36 }
37
38 foreach $time (values %cpu) {
39     if ($start_time < $time) {
40         $start_time = $time;
41     }
42 }
43
44 print "Starting analysis since $start_time\n";
45
46 seek(INFILE, 0, 0);
47 while ($line = <INFILE>) {
48     $debug_line++;
49     my ($file, $func, $lno, $name, $size, $addr, $type);
50     if ($line =~ m/^(.*)\((.*):(\d+):(.*)\(\)\) (k|v|slab-)(.*) '(.*)': (\d+) at ([\da-f]+)/){
51         @parsed = split(":", $1);
52         if ($parsed[3] <= $start_time) {
53                 next;
54         }
55         
56         $file = $2;
57         $lno  = $3;
58         $func = $4;
59         $type = $6;
60         $name = $7;
61         $size = $8;
62         $addr = $9;
63
64         # we can't dump the log after portals has exited, so skip "leaks"
65         # from memory freed in the portals module unloading.
66         if ($func eq 'portals_handle_init') {
67             next;
68         }
69         printf("%8s %6d bytes at %s called %s (%s:%s:%d)\n", $type, $size,
70                $addr, $name, $file, $func, $lno);
71     } else {
72         next;
73     }
74
75     if (index($type, 'alloced') >= 0) {
76         if (defined($memory->{$addr})) {
77             print STDERR "*** Two allocs with the same address ($size bytes at $addr, $file:$func:$lno)\n";
78             print STDERR "    first malloc at $memory->{$addr}->{file}:$memory->{$addr}->{func}:$memory->{$addr}->{lno}, second at $file:$func:$lno\n";
79             next;
80         }
81
82         $memory->{$addr}->{name} = $name;
83         $memory->{$addr}->{size} = $size;
84         $memory->{$addr}->{file} = $file;
85         $memory->{$addr}->{func} = $func;
86         $memory->{$addr}->{lno} = $lno;
87         $memory->{$addr}->{debug_line} = $debug_line;
88
89         $total += $size;
90         if ($total > $max) {
91             $max = $total;
92         }
93     } else {
94         if (!defined($memory->{$addr})) {
95             print STDERR "*** Free without malloc ($size bytes at $addr, $file:$func:$lno)\n";
96             next;
97         }
98         my ($oldname, $oldsize, $oldfile, $oldfunc, $oldlno) = $memory->{$addr};
99
100         if ($memory->{$addr}->{size} != $size) {
101             print STDERR "*** Free different size ($memory->{$addr}->{size} alloced, $size freed).\n";
102             print STDERR "    malloc at $memory->{$addr}->{file}:$memory->{$addr}->{func}:$memory->{$addr}->{lno}, free at $file:$func:$lno\n";
103             next;
104         }
105
106         delete $memory->{$addr};
107         $total -= $size;
108     }
109 }
110 close(INFILE);
111
112 # Sort leak output by allocation time
113 my @sorted = sort {
114     return $memory->{$a}->{debug_line} <=> $memory->{$b}->{debug_line};
115 } keys(%{$memory});
116
117 my $key;
118 foreach $key (@sorted) {
119     my ($oldname, $oldsize, $oldfile, $oldfunc, $oldlno) = $memory->{$key};
120     print STDERR "*** Leak: $memory->{$key}->{size} bytes allocated at $key ($memory->{$key}->{file}:$memory->{$key}->{func}:$memory->{$key}->{lno}, debug file line $memory->{$key}->{debug_line})\n";
121 }
122
123 print STDERR "maximum used: $max, amount leaked: $total\n";