diff -r 000000000000 -r 6474c204b198 tools/trace-malloc/blame.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/trace-malloc/blame.pl Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,219 @@ +#!/usr/bin/perl -w +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# +# Process output of TraceMallocDumpAllocations() to produce a table +# that attributes memory to the allocators using call stack. +# + +use 5.004; +use strict; + +# A table of all ancestors. Key is function name, value is an +# array of ancestors, each attributed with a number of calls and +# the amount of memory allocated. +my %Ancestors; + +# Ibid, for descendants. +my %Descendants; + +# A table that keeps the total amount of memory allocated by each +# function +my %Totals; +$Totals{".root"} = { "#memory#" => 0, "#calls#" => 0 }; + +# A table that maps the long ugly function name to a unique number so +# that the HTML we generate isn't too fat +my %Ids; +my $NextId = 0; + +$Ids{".root"} = ++$NextId; + + +LINE: while (<>) { + # The line'll look like: + # + # 0x4000a008 16 PR_Malloc+16; nsMemoryImpl::Alloc(unsigned int)+12; ... + + # Ignore any lines that don't start with an address + next LINE unless /^0x/; + + # Parse it + my ($address, $size, $rest) = /^(0x\S*)\s*(\d+)\s*(.*)$/; + my @stack = reverse(split /; /, $rest); + + # Accumulate at the root + $Totals{".root"}->{"#memory#"} += $size; + ++$Totals{".root"}->{"#calls#"}; + + my $caller = ".root"; + foreach my $callee (@stack) { + # Strip the offset from the callsite information. I don't + # think we care. + $callee =~ s/\+\d+$//g; + + # Accumulate the total for the callee + if (! $Totals{$callee}) { + $Totals{$callee} = { "#memory#" => 0, "#calls#" => 0 }; + } + + $Totals{$callee}->{"#memory#"} += $size; + ++$Totals{$callee}->{"#calls#"}; + + # Descendants + my $descendants = $Descendants{$caller}; + if (! $descendants) { + $descendants = $Descendants{$caller} = [ ]; + } + + # Manage the list of descendants + { + my $wasInserted = 0; + DESCENDANT: foreach my $item (@$descendants) { + if ($item->{"#name#"} eq $callee) { + $item->{"#memory#"} += $size; + ++$item->{"#calls#"}; + $wasInserted = 1; + last DESCENDANT; + } + } + + if (! $wasInserted) { + $descendants->[@$descendants] = { + "#name#" => $callee, + "#memory#" => $size, + "#calls#" => 1 + }; + } + } + + # Ancestors + my $ancestors = $Ancestors{$callee}; + if (! $ancestors) { + $ancestors = $Ancestors{$callee} = [ ]; + } + + # Manage the list of ancestors + { + my $wasInserted = 0; + ANCESTOR: foreach my $item (@$ancestors) { + if ($item->{"#name#"} eq $caller) { + $item->{"#memory#"} += $size; + ++$item->{"#calls#"}; + $wasInserted = 1; + last ANCESTOR; + } + } + + if (! $wasInserted) { + $ancestors->[@$ancestors] = { + "#name#" => $caller, + "#memory#" => $size, + "#calls#" => 1 + }; + } + } + + # Make a new "id", if necessary + if (! $Ids{$callee}) { + $Ids{$callee} = ++$NextId; + } + + # On to the next one... + $caller = $callee; + } +} + + +# Change the manky looking callsite into a pretty function; strip argument +# types and offset information. +sub pretty($) { + $_ = $_[0]; + s/&/&/g; + s/</g; + s/>/>/g; + + if (/([^\(]*)(\(.*\))/) { + return $1 . "()"; + } + else { + return $_[0]; + } +} + +# Dump a web page! +print "\n"; +print "
\n"; +print "Function | Ancestors | Descendants |
$pretty $memory ($calls) | \n"; + } + + # Ancestors, sorted descending by amount of memory allocated + print "\n";
+ my $ancestors = $Ancestors{$node};
+ if ($ancestors) {
+ foreach my $ancestor (sort { $b->{"#memory#"} <=> $a->{"#memory#"} } @$ancestors) {
+ my ($name, $memory, $calls) =
+ ($ancestor->{"#name#"},
+ $ancestor->{"#memory#"},
+ $ancestor->{"#calls#"});
+
+ my $pretty = pretty($name);
+
+ print " $pretty $memory ($calls) \n"; + } + } + + print " | \n";
+
+ # Descendants, sorted descending by amount of memory allocated
+ print " \n";
+ my $descendants = $Descendants{$node};
+ if ($descendants) {
+ foreach my $descendant (sort { $b->{"#memory#"} <=> $a->{"#memory#"} } @$descendants) {
+ my ($name, $memory, $calls) =
+ ($descendant->{"#name#"},
+ $descendant->{"#memory#"},
+ $descendant->{"#calls#"});
+
+ my $pretty = pretty($name);
+
+ print " $pretty $memory ($calls) \n"; + } + } + print " |
Function | Ancestors | Descendants |