Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
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 | # vim:cindent:ts=8:et:sw=4: |
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 | # This script produces a diff between two files that are the result of |
michael@0 | 8 | # calling NS_TraceMallocDumpAllocations. Such files can be created |
michael@0 | 9 | # through the command-line option --shutdown-leaks=<filename> or through |
michael@0 | 10 | # the DOM function window.TraceMallocDumpAllocations(<filename>). Both |
michael@0 | 11 | # methods will work only if --trace-malloc=<malloc-log> is also given on |
michael@0 | 12 | # the command line. |
michael@0 | 13 | |
michael@0 | 14 | use 5.004; |
michael@0 | 15 | use strict; |
michael@0 | 16 | use Getopt::Long; |
michael@0 | 17 | |
michael@0 | 18 | $::opt_help = 0; |
michael@0 | 19 | $::opt_depth = 6; |
michael@0 | 20 | $::opt_include_zero = 0; |
michael@0 | 21 | $::opt_allocation_count = 0; |
michael@0 | 22 | $::opt_use_address = 0; |
michael@0 | 23 | |
michael@0 | 24 | # XXX Change --use-address to be the default and remove the option |
michael@0 | 25 | # once tinderbox is no longer using it without --use-address. |
michael@0 | 26 | |
michael@0 | 27 | Getopt::Long::Configure("pass_through"); |
michael@0 | 28 | Getopt::Long::GetOptions("help", "allocation-count", "depth=i", |
michael@0 | 29 | "include-zero", "use-address"); |
michael@0 | 30 | |
michael@0 | 31 | if ($::opt_help) { |
michael@0 | 32 | die "usage: diffbloatdump.pl [options] <dump1> <dump2> |
michael@0 | 33 | --help Display this message |
michael@0 | 34 | |
michael@0 | 35 | --allocation-count Use allocation count rather than size (i.e., treat |
michael@0 | 36 | all sizes as 1). |
michael@0 | 37 | --depth=<num> Only display <num> frames at top of allocation stack. |
michael@0 | 38 | --include-zero Display subtrees totalling zero. |
michael@0 | 39 | --use-address Don't ignore the address part of the stack trace |
michael@0 | 40 | (can make comparison more accurate when comparing |
michael@0 | 41 | results from the same build) |
michael@0 | 42 | |
michael@0 | 43 | The input files (<dump1> and <dump2> above) are either trace-malloc |
michael@0 | 44 | memory dumps OR this script's output. (If this script's output, |
michael@0 | 45 | --allocation-count and --use-address are ignored.) If the input files |
michael@0 | 46 | have .gz or .bz2 extension, they are uncompressed. |
michael@0 | 47 | "; |
michael@0 | 48 | } |
michael@0 | 49 | |
michael@0 | 50 | my $calltree = { count => 0 }; # leave children undefined |
michael@0 | 51 | |
michael@0 | 52 | sub get_child($$) { |
michael@0 | 53 | my ($node, $frame) = @_; |
michael@0 | 54 | if (!defined($node->{children})) { |
michael@0 | 55 | $node->{children} = {}; |
michael@0 | 56 | } |
michael@0 | 57 | if (!defined($node->{children}->{$frame})) { |
michael@0 | 58 | $node->{children}->{$frame} = { count => 0 }; |
michael@0 | 59 | } |
michael@0 | 60 | return $node->{children}->{$frame}; |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | sub add_tree_file($$$) { |
michael@0 | 64 | my ($infile, $firstline, $factor) = @_; |
michael@0 | 65 | |
michael@0 | 66 | my @nodestack; |
michael@0 | 67 | $nodestack[1] = $calltree; |
michael@0 | 68 | $firstline =~ /^(-?\d+) malloc$/; |
michael@0 | 69 | $calltree->{count} += $1 * $factor; |
michael@0 | 70 | |
michael@0 | 71 | my $lineno = 1; |
michael@0 | 72 | while (!eof($infile)) { |
michael@0 | 73 | my $line = <$infile>; |
michael@0 | 74 | ++$lineno; |
michael@0 | 75 | $line =~ /^( *)(-?\d+) (.*)$/ || die "malformed input, line $lineno"; |
michael@0 | 76 | my $depth = length($1); |
michael@0 | 77 | my $count = $2; |
michael@0 | 78 | my $frame = $3; |
michael@0 | 79 | die "malformed input, line $lineno" if ($depth % 2 != 0); |
michael@0 | 80 | $depth /= 2; |
michael@0 | 81 | die "malformed input, line $lineno" if ($depth > $#nodestack); |
michael@0 | 82 | $#nodestack = $depth; |
michael@0 | 83 | my $node = get_child($nodestack[$depth], $frame); |
michael@0 | 84 | push @nodestack, $node; |
michael@0 | 85 | $node->{count} += $count * $factor; |
michael@0 | 86 | } |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | sub add_file($$) { |
michael@0 | 90 | # Takes (1) a reference to a file descriptor for input and (2) the |
michael@0 | 91 | # factor to multiply the stacks by (generally +1 or -1). |
michael@0 | 92 | # Returns a reference to an array representing the stack, allocation |
michael@0 | 93 | # site in array[0]. |
michael@0 | 94 | sub read_stack($) { |
michael@0 | 95 | my ($infile) = @_; |
michael@0 | 96 | my $line; |
michael@0 | 97 | my @stack; |
michael@0 | 98 | |
michael@0 | 99 | # read the data at the memory location |
michael@0 | 100 | while ( defined($infile) && ($line = <$infile>) && substr($line,0,1) eq "\t" ) { |
michael@0 | 101 | # do nothing |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | # read the stack |
michael@0 | 105 | do { |
michael@0 | 106 | chomp($line); |
michael@0 | 107 | if ( ! $::opt_use_address && |
michael@0 | 108 | $line =~ /(.*)\[(.*)\]/) { |
michael@0 | 109 | $line = $1; |
michael@0 | 110 | } |
michael@0 | 111 | $stack[$#stack+1] = $line; |
michael@0 | 112 | } while ( defined($infile) && ($line = <$infile>) && $line ne "\n" && $line ne "\r\n" ); |
michael@0 | 113 | |
michael@0 | 114 | return \@stack; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | # adds the stack given as a parameter (reference to array, $stack[0] is |
michael@0 | 118 | # allocator) to $calltree, with the call count multiplied by $factor |
michael@0 | 119 | # (typically +1 or -1). |
michael@0 | 120 | sub add_stack($$) { |
michael@0 | 121 | my @stack = @{$_[0]}; |
michael@0 | 122 | my $factor = $_[1]; |
michael@0 | 123 | |
michael@0 | 124 | my $i = 0; |
michael@0 | 125 | my $node = $calltree; |
michael@0 | 126 | while ($i < $#stack && $i < $::opt_depth) { |
michael@0 | 127 | $node->{count} += $factor; |
michael@0 | 128 | $node = get_child($node, $stack[$i]); |
michael@0 | 129 | ++$i; |
michael@0 | 130 | } |
michael@0 | 131 | $node->{count} += $factor; |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | my ($infile, $factor) = @_; |
michael@0 | 135 | |
michael@0 | 136 | if ($infile =~ /\.bz2$/) { |
michael@0 | 137 | # XXX This doesn't propagate errors from bzip2. |
michael@0 | 138 | open (INFILE, "bzip2 -cd '$infile' |") || die "Can't open input \"$infile\""; |
michael@0 | 139 | } elsif ($infile =~ /\.gz$/) { |
michael@0 | 140 | # XXX This doesn't propagate errors from gzip. |
michael@0 | 141 | open (INFILE, "gzip -cd '$infile' |") || die "Can't open input \"$infile\""; |
michael@0 | 142 | } else { |
michael@0 | 143 | open (INFILE, "<$infile") || die "Can't open input \"$infile\""; |
michael@0 | 144 | } |
michael@0 | 145 | my $first = 1; |
michael@0 | 146 | while ( ! eof(INFILE) ) { |
michael@0 | 147 | # read the type and address |
michael@0 | 148 | my $line = <INFILE>; |
michael@0 | 149 | if ($first) { |
michael@0 | 150 | $first = 0; |
michael@0 | 151 | if ($line =~ /^-?\d+ malloc$/) { |
michael@0 | 152 | # We're capable of reading in our own output as well. |
michael@0 | 153 | add_tree_file(\*INFILE, $line, $factor); |
michael@0 | 154 | close INFILE; |
michael@0 | 155 | return; |
michael@0 | 156 | } |
michael@0 | 157 | } |
michael@0 | 158 | unless ($line =~ /.*\((\d*)\)[\r|\n]/) { |
michael@0 | 159 | die "badly formed allocation header in $infile"; |
michael@0 | 160 | } |
michael@0 | 161 | my $size; |
michael@0 | 162 | if ($::opt_allocation_count) { |
michael@0 | 163 | $size = 1; |
michael@0 | 164 | } else { |
michael@0 | 165 | $size = $1; |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | add_stack(read_stack(\*INFILE), $size * $factor); |
michael@0 | 169 | } |
michael@0 | 170 | close INFILE; |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | sub print_node_indent($$$); |
michael@0 | 174 | |
michael@0 | 175 | sub print_calltree() { |
michael@0 | 176 | sub print_indent($) { |
michael@0 | 177 | my ($i) = @_; |
michael@0 | 178 | while (--$i >= 0) { |
michael@0 | 179 | print " "; |
michael@0 | 180 | } |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | sub print_node_indent($$$) { |
michael@0 | 184 | my ($nodename, $node, $indent) = @_; |
michael@0 | 185 | |
michael@0 | 186 | if (!$::opt_include_zero && $node->{count} == 0) { |
michael@0 | 187 | return; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | print_indent($indent); |
michael@0 | 191 | print "$node->{count} $nodename\n"; |
michael@0 | 192 | if (defined($node->{children})) { |
michael@0 | 193 | my %kids = %{$node->{children}}; |
michael@0 | 194 | ++$indent; |
michael@0 | 195 | foreach my $kid (sort { $kids{$b}->{count} <=> $kids{$a}->{count} } |
michael@0 | 196 | keys (%kids)) { |
michael@0 | 197 | print_node_indent($kid, $kids{$kid}, $indent); |
michael@0 | 198 | } |
michael@0 | 199 | } |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | print_node_indent("malloc", $calltree, 0); |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | add_file($ARGV[0], -1); |
michael@0 | 206 | add_file($ARGV[1], 1); |
michael@0 | 207 | print_calltree(); |