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