1 #!/usr/bin/perl 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 # 6 # Read a memtrace logfile from stdin and group memory allocations by logical 7 # code component. The code component is guessed from the callstack, and 8 # is something like {v8, sqlite, disk cache, skia, etc..} 9 # 10 # Usage: 11 # 12 # summary.pl 13 # 14 # [STDIN] -- The memwatcher.logXXXX file to summarize. 15 # 16 17 sub process_stdin() { 18 my %leaks = (); 19 my $total_bytes = 0; 20 21 while(<STDIN>) { 22 my $line = $_; 23 chomp($line); 24 my $bytes, $loc; 25 ($bytes, $loc) = ($line =~ m/[ \t]*([0-9]*)[ \t]*[0-9\.%]*[ \t]*(.*)/); 26 chomp($loc); 27 while(<STDIN>) { 28 my $cont = $_; 29 chomp($cont); 30 last if $cont =~ m/=====/; 31 $loc .= "\n" . $cont; 32 } 33 my $location_blame = ""; 34 35 # print "Found: $bytes, $loc\n"; 36 37 if ($loc =~ m/v8::internal::Snapshot::Deserialize/) { 38 $location_blame = "v8 Snapshot Deserialize"; 39 } elsif ($loc =~ m/RenderStyle::create/) { 40 $location_blame = "RenderStyle::create"; 41 } elsif ($loc =~ m/v8::internal::OldSpace::SlowAllocateRaw/) { 42 $location_blame = "v8 OldSpace"; 43 } elsif ($loc =~ m/sqlite/) { 44 $location_blame = "sqlite"; 45 } elsif ($loc =~ m/ TransportDIB::Map/) { 46 $location_blame = "Shared Memory Backing Store"; 47 } elsif ($loc =~ m/imagedecoder/) { 48 $location_blame = "img decoder"; 49 } elsif ($loc =~ m/SkBitmap/) { 50 $location_blame = "skia"; 51 } elsif ($loc =~ m/disk_cache/) { 52 $location_blame = "disk cache"; 53 } elsif ($loc =~ m/skia/) { 54 $location_blame = "skia"; 55 } elsif ($loc =~ m/:WSA/) { 56 $location_blame = "net"; 57 } elsif ($loc =~ m/dns/) { 58 $location_blame = "net"; 59 } elsif ($loc =~ m/trunk\\net/) { 60 $location_blame = "net"; 61 } elsif ($loc =~ m/WinHttp/) { 62 $location_blame = "WinHttp"; 63 } elsif ($loc =~ m/:I_Crypt/) { 64 $location_blame = "WinHttpSSL"; 65 } elsif ($loc =~ m/CryptGetTls/) { 66 $location_blame = "WinHttpSSL"; 67 } elsif ($loc =~ m/WinVerifyTrust/) { 68 $location_blame = "WinHttpSSL"; 69 } elsif ($loc =~ m/Cert/) { 70 $location_blame = "WinHttpSSL"; 71 } elsif ($loc =~ m/plugin/) { 72 $location_blame = "plugin"; 73 } elsif ($loc =~ m/NP_/) { 74 $location_blame = "plugin"; 75 } elsif ($loc =~ m/hunspell/) { 76 $location_blame = "hunspell"; 77 } elsif ($loc =~ m/TextCodec/) { 78 $location_blame = "fonts"; 79 } elsif ($loc =~ m/glyph/) { 80 $location_blame = "fonts"; 81 } elsif ($loc =~ m/cssparser/) { 82 $location_blame = "webkit css"; 83 } elsif ($loc =~ m/::CSS/) { 84 $location_blame = "webkit css"; 85 } elsif ($loc =~ m/Arena/) { 86 $location_blame = "webkit arenas"; 87 } elsif ($loc =~ m/WebCore::.*ResourceLoader::addData/) { 88 $location_blame = "WebCore *ResourceLoader addData"; 89 } elsif ($loc =~ m/OnUpdateVisitedLinks/) { 90 $location_blame = "OnUpdateVisitedLinks"; 91 } elsif ($loc =~ m/IPC/) { 92 $location_blame = "ipc"; 93 } elsif ($loc =~ m/trunk\\chrome\\browser/) { 94 $location_blame = "browser"; 95 } elsif ($loc =~ m/trunk\\chrome\\renderer/) { 96 $location_blame = "renderer"; 97 } elsif ($loc =~ m/webcore\\html/) { 98 $location_blame = "webkit webcore html"; 99 } elsif ($loc =~ m/webkit.*string/) { 100 $location_blame = "webkit strings"; 101 } elsif ($loc =~ m/htmltokenizer/) { 102 $location_blame = "webkit HTMLTokenizer"; 103 } elsif ($loc =~ m/javascriptcore/) { 104 $location_blame = "webkit javascriptcore"; 105 } elsif ($loc =~ m/webkit/) { 106 $location_blame = "webkit other"; 107 } elsif ($loc =~ m/safe_browsing/) { 108 $location_blame = "safe_browsing"; 109 } elsif ($loc =~ m/VisitedLinkMaster/) { 110 $location_blame = "VisitedLinkMaster"; 111 } elsif ($loc =~ m/NewDOMUI/) { 112 $location_blame = "NewDOMUI"; 113 } elsif ($loc =~ m/RegistryControlledDomainService/) { 114 $location_blame = "RegistryControlledDomainService"; 115 } elsif ($loc =~ m/URLRequestChromeJob::DataAvailable/) { 116 $location_blame = "URLRequestChromeJob DataAvailable"; 117 } elsif ($loc =~ m/history_publisher/) { 118 $location_blame = "history publisher"; 119 } else { 120 $location_blame = "unknown"; 121 } 122 123 # Surface large outliers in an "interesting" group. 124 my $interesting_group = "unknown"; 125 my $interesting_size = 10000000; # Make this smaller as needed. 126 # TODO(jar): Add this as a pair of shell arguments. 127 if ($bytes > $interesting_size && $location_blame eq $interesting_group) { 128 # Create a special group for the exact stack that contributed so much. 129 $location_blame = $loc; 130 } 131 132 $total_bytes += $bytes; 133 $leaks{$location_blame} += $bytes; 134 } 135 136 # now dump our hash table 137 my $sum = 0; 138 my @keys = sort { $leaks{$b} <=> $leaks{$a} }keys %leaks; 139 for ($i=0; $i<@keys; $i++) { 140 my $key = @keys[$i]; 141 printf "%11s\t(%3.2f%%)\t%s\n", comma_print($leaks{$key}), (100* $leaks{$key} / $total_bytes), $key; 142 $sum += $leaks{$key}; 143 } 144 printf("TOTAL: %s\n", comma_print($sum)); 145 } 146 147 # Insert commas into an integer after each three digits for printing. 148 sub comma_print { 149 my $num = "$_[0]"; 150 $num =~ s/(\d{1,3}?)(?=(\d{3})+$)/$1,/g; 151 return $num; 152 } 153 154 # ----- Main ------------------------------------------------ 155 156 process_stdin(); 157