Home | History | Annotate | Download | only in scripts
      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 # Given a memwatcher logfile, group memory allocations by callstack.
      7 #
      8 # Usage:
      9 #
     10 #   memprof.pl <logfile>
     11 #
     12 #      logfile -- The memwatcher.logXXXX file to summarize.
     13 #
     14 #
     15 #
     16 # Sample output:
     17 #
     18 # 54,061,617        100.00% AllocationStack::AllocationStack
     19 # 41,975,368        77.64%  malloc
     20 # 11,886,592        21.99%  VirtualAlloc
     21 #  7,168,000        13.26%  v8::internal::OS::Allocate
     22 #  7,168,000        13.26%  v8::internal::MemoryAllocator::AllocateRawMemory
     23 #  5,976,184        11.05%  WebCore::V8Bridge::evaluate
     24 #  5,767,168        10.67%  v8::internal::MemoryAllocator::AllocatePages
     25 #  5,451,776        10.08%  WebCore::V8Proxy::initContextIfNeeded
     26 #  ....
     27 #
     28 #
     29 #
     30 # ********
     31 # Note: The output is currently sorted by decreasing size.
     32 # ********
     33 #
     34 
     35 sub process_raw($$) {
     36   my $file = shift;
     37   my $filter = shift;
     38 
     39   my %leaks = ();
     40   my %stackframes = ();
     41 
     42   my $blamed = 0;
     43   my $bytes = 0;
     44   my $hits = 0;
     45   open (LOGFILE, "$file") or die("could not open $file");
     46   while(<LOGFILE>) {
     47     my $line = $_;
     48 #print "$line";
     49     chomp($line);
     50     if ($line =~ m/([0-9]*) bytes, ([0-9]*) allocs/) {
     51 
     52       # If we didn't find any frames to account this to, log that.
     53       if ($blamed == 0) {
     54         $leaks{"UNACCOUNTED"} += $bytes;
     55       }
     56 
     57 #print "START\n";
     58       #print("stackframe " . $1 . ", " . $2 . "\n");
     59       $hits = $2;
     60       $bytes = $1;
     61       %stackframes = ();   # we have a new frame, clear the list.
     62       $blamed = 0;         # we haven't blamed anyone yet
     63     }
     64     elsif ($line =~ m/Total Bytes:[ ]*([0-9]*)/) {
     65       $total_bytes += $1;
     66     }
     67     elsif ($line =~ m/=============/) {
     68       next;
     69     }
     70     elsif ($line =~ m/[ ]*([\-a-zA-Z_\\0-9\.]*) \(([0-9]*)\):[ ]*([<>_a-zA-Z_0-9:]*)/) {
     71 #      print("junk: " . $line . "\n");
     72 #    print("file: $1\n"); 
     73 #    print("line: $2\n"); 
     74 #    print("function: $3\n"); 
     75 #   
     76       
     77       # blame the function
     78       my $pig = $3;
     79 #      my $pig = $1;
     80 
     81       # only add the memory if this function is not yet on our callstack
     82       if (!exists $stackframes{$pig}) {  
     83         $leaks{$pig} += $bytes;
     84       }
     85 
     86       $stackframes{$pig}++;
     87       $blamed++;
     88     }
     89   }
     90 
     91   # now dump our hash table
     92   my $sum = 0;
     93   my @keys = sort { $leaks{$b} <=> $leaks{$a}  }keys %leaks;
     94   for ($i=0; $i<@keys; $i++) {
     95     my $key = @keys[$i];
     96     printf "%11s\t%3.2f%%\t%s\n", comma_print($leaks{$key}), (100* $leaks{$key} / $total_bytes), $key;
     97     $sum += $leaks{$key};
     98   }
     99   printf("TOTAL: %s\n", comma_print($sum));
    100 }
    101 
    102 # Insert commas into an integer after each three digits for printing.
    103 sub comma_print {
    104     my $num = "$_[0]";
    105     $num =~ s/(\d{1,3}?)(?=(\d{3})+$)/$1,/g;
    106     return $num;
    107 }
    108 
    109 # ----- Main ------------------------------------------------
    110 
    111 # Get the command line argument
    112 my $filename = shift;
    113 my $filter = shift;
    114 
    115 # Process the file.
    116 process_raw($filename, $filter);
    117