tools/trace-malloc/blame.pl

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rwxr-xr-x

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 #!/usr/bin/perl -w
michael@0 2 #
michael@0 3 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 6
michael@0 7 #
michael@0 8 # Process output of TraceMallocDumpAllocations() to produce a table
michael@0 9 # that attributes memory to the allocators using call stack.
michael@0 10 #
michael@0 11
michael@0 12 use 5.004;
michael@0 13 use strict;
michael@0 14
michael@0 15 # A table of all ancestors. Key is function name, value is an
michael@0 16 # array of ancestors, each attributed with a number of calls and
michael@0 17 # the amount of memory allocated.
michael@0 18 my %Ancestors;
michael@0 19
michael@0 20 # Ibid, for descendants.
michael@0 21 my %Descendants;
michael@0 22
michael@0 23 # A table that keeps the total amount of memory allocated by each
michael@0 24 # function
michael@0 25 my %Totals;
michael@0 26 $Totals{".root"} = { "#memory#" => 0, "#calls#" => 0 };
michael@0 27
michael@0 28 # A table that maps the long ugly function name to a unique number so
michael@0 29 # that the HTML we generate isn't too fat
michael@0 30 my %Ids;
michael@0 31 my $NextId = 0;
michael@0 32
michael@0 33 $Ids{".root"} = ++$NextId;
michael@0 34
michael@0 35
michael@0 36 LINE: while (<>) {
michael@0 37 # The line'll look like:
michael@0 38 #
michael@0 39 # 0x4000a008 16 PR_Malloc+16; nsMemoryImpl::Alloc(unsigned int)+12; ...
michael@0 40
michael@0 41 # Ignore any lines that don't start with an address
michael@0 42 next LINE unless /^0x/;
michael@0 43
michael@0 44 # Parse it
michael@0 45 my ($address, $size, $rest) = /^(0x\S*)\s*(\d+)\s*(.*)$/;
michael@0 46 my @stack = reverse(split /; /, $rest);
michael@0 47
michael@0 48 # Accumulate at the root
michael@0 49 $Totals{".root"}->{"#memory#"} += $size;
michael@0 50 ++$Totals{".root"}->{"#calls#"};
michael@0 51
michael@0 52 my $caller = ".root";
michael@0 53 foreach my $callee (@stack) {
michael@0 54 # Strip the offset from the callsite information. I don't
michael@0 55 # think we care.
michael@0 56 $callee =~ s/\+\d+$//g;
michael@0 57
michael@0 58 # Accumulate the total for the callee
michael@0 59 if (! $Totals{$callee}) {
michael@0 60 $Totals{$callee} = { "#memory#" => 0, "#calls#" => 0 };
michael@0 61 }
michael@0 62
michael@0 63 $Totals{$callee}->{"#memory#"} += $size;
michael@0 64 ++$Totals{$callee}->{"#calls#"};
michael@0 65
michael@0 66 # Descendants
michael@0 67 my $descendants = $Descendants{$caller};
michael@0 68 if (! $descendants) {
michael@0 69 $descendants = $Descendants{$caller} = [ ];
michael@0 70 }
michael@0 71
michael@0 72 # Manage the list of descendants
michael@0 73 {
michael@0 74 my $wasInserted = 0;
michael@0 75 DESCENDANT: foreach my $item (@$descendants) {
michael@0 76 if ($item->{"#name#"} eq $callee) {
michael@0 77 $item->{"#memory#"} += $size;
michael@0 78 ++$item->{"#calls#"};
michael@0 79 $wasInserted = 1;
michael@0 80 last DESCENDANT;
michael@0 81 }
michael@0 82 }
michael@0 83
michael@0 84 if (! $wasInserted) {
michael@0 85 $descendants->[@$descendants] = {
michael@0 86 "#name#" => $callee,
michael@0 87 "#memory#" => $size,
michael@0 88 "#calls#" => 1
michael@0 89 };
michael@0 90 }
michael@0 91 }
michael@0 92
michael@0 93 # Ancestors
michael@0 94 my $ancestors = $Ancestors{$callee};
michael@0 95 if (! $ancestors) {
michael@0 96 $ancestors = $Ancestors{$callee} = [ ];
michael@0 97 }
michael@0 98
michael@0 99 # Manage the list of ancestors
michael@0 100 {
michael@0 101 my $wasInserted = 0;
michael@0 102 ANCESTOR: foreach my $item (@$ancestors) {
michael@0 103 if ($item->{"#name#"} eq $caller) {
michael@0 104 $item->{"#memory#"} += $size;
michael@0 105 ++$item->{"#calls#"};
michael@0 106 $wasInserted = 1;
michael@0 107 last ANCESTOR;
michael@0 108 }
michael@0 109 }
michael@0 110
michael@0 111 if (! $wasInserted) {
michael@0 112 $ancestors->[@$ancestors] = {
michael@0 113 "#name#" => $caller,
michael@0 114 "#memory#" => $size,
michael@0 115 "#calls#" => 1
michael@0 116 };
michael@0 117 }
michael@0 118 }
michael@0 119
michael@0 120 # Make a new "id", if necessary
michael@0 121 if (! $Ids{$callee}) {
michael@0 122 $Ids{$callee} = ++$NextId;
michael@0 123 }
michael@0 124
michael@0 125 # On to the next one...
michael@0 126 $caller = $callee;
michael@0 127 }
michael@0 128 }
michael@0 129
michael@0 130
michael@0 131 # Change the manky looking callsite into a pretty function; strip argument
michael@0 132 # types and offset information.
michael@0 133 sub pretty($) {
michael@0 134 $_ = $_[0];
michael@0 135 s/&/&amp;/g;
michael@0 136 s/</&lt;/g;
michael@0 137 s/>/&gt;/g;
michael@0 138
michael@0 139 if (/([^\(]*)(\(.*\))/) {
michael@0 140 return $1 . "()";
michael@0 141 }
michael@0 142 else {
michael@0 143 return $_[0];
michael@0 144 }
michael@0 145 }
michael@0 146
michael@0 147 # Dump a web page!
michael@0 148 print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n";
michael@0 149 print "<html><head>\n";
michael@0 150 print "<title>Live Bloat Blame</title>\n";
michael@0 151 print "<link rel=\"stylesheet\" type=\"text/css\" href=\"blame.css\">\n";
michael@0 152 print "</head>\n";
michael@0 153 print "<body>\n";
michael@0 154
michael@0 155 # At most 100 rows per table so as not to kill the browser.
michael@0 156 my $maxrows = 100;
michael@0 157
michael@0 158 print "<table>\n";
michael@0 159 print "<thead><tr><td>Function</td><td>Ancestors</td><td>Descendants</td></tr></thead>\n";
michael@0 160
michael@0 161 foreach my $node (sort(keys(%Ids))) {
michael@0 162 print "<tr>\n";
michael@0 163
michael@0 164 # Print the current node
michael@0 165 {
michael@0 166 my ($memory, $calls) =
michael@0 167 ($Totals{$node}->{"#memory#"},
michael@0 168 $Totals{$node}->{"#calls#"});
michael@0 169
michael@0 170 my $pretty = pretty($node);
michael@0 171 print " <td><a name=\"$Ids{$node}\">$pretty&nbsp;$memory&nbsp;($calls)</a></td>\n";
michael@0 172 }
michael@0 173
michael@0 174 # Ancestors, sorted descending by amount of memory allocated
michael@0 175 print " <td>\n";
michael@0 176 my $ancestors = $Ancestors{$node};
michael@0 177 if ($ancestors) {
michael@0 178 foreach my $ancestor (sort { $b->{"#memory#"} <=> $a->{"#memory#"} } @$ancestors) {
michael@0 179 my ($name, $memory, $calls) =
michael@0 180 ($ancestor->{"#name#"},
michael@0 181 $ancestor->{"#memory#"},
michael@0 182 $ancestor->{"#calls#"});
michael@0 183
michael@0 184 my $pretty = pretty($name);
michael@0 185
michael@0 186 print " <a href=\"#$Ids{$name}\">$pretty</a>&nbsp;$memory&nbsp;($calls)<br>\n";
michael@0 187 }
michael@0 188 }
michael@0 189
michael@0 190 print " </td>\n";
michael@0 191
michael@0 192 # Descendants, sorted descending by amount of memory allocated
michael@0 193 print " <td>\n";
michael@0 194 my $descendants = $Descendants{$node};
michael@0 195 if ($descendants) {
michael@0 196 foreach my $descendant (sort { $b->{"#memory#"} <=> $a->{"#memory#"} } @$descendants) {
michael@0 197 my ($name, $memory, $calls) =
michael@0 198 ($descendant->{"#name#"},
michael@0 199 $descendant->{"#memory#"},
michael@0 200 $descendant->{"#calls#"});
michael@0 201
michael@0 202 my $pretty = pretty($name);
michael@0 203
michael@0 204 print " <a href=\"#$Ids{$name}\">$pretty</a>&nbsp;$memory&nbsp;($calls)<br>\n";
michael@0 205 }
michael@0 206 }
michael@0 207 print " </td></tr>\n";
michael@0 208
michael@0 209 if (--$maxrows == 0) {
michael@0 210 print "</table>\n";
michael@0 211 print "<table>\n";
michael@0 212 print "<thead><tr><td>Function</td><td>Ancestors</td><td>Descendants</td></tr></thead>\n";
michael@0 213 $maxrows = 100;
michael@0 214 }
michael@0 215 }
michael@0 216
michael@0 217 # Footer
michael@0 218 print "</table>\n";
michael@0 219 print "</body></html>\n";

mercurial