tools/rb/bloatdiff.pl

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/rb/bloatdiff.pl	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,372 @@
     1.4 +#!/usr/bin/perl -w
     1.5 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.6 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.8 +
     1.9 +
    1.10 +################################################################################
    1.11 +
    1.12 +sub usage() {
    1.13 +    print <<EOUSAGE;
    1.14 +# bloatdiff.pl - munges the output from
    1.15 +#   XPCOM_MEM_BLOAT_LOG=1 
    1.16 +#   firefox-bin -P default resource:///res/bloatcycle.html
    1.17 +# so that it does some summary and stats stuff.
    1.18 +#
    1.19 +# To show leak test results for a set of changes, do something like this:
    1.20 +#
    1.21 +#   XPCOM_MEM_BLOAT_LOG=1
    1.22 +#   firefox-bin -P default resource:///res/bloatcycle.html > a.out
    1.23 +#     **make change**
    1.24 +#   firefox-bin -P default resource:///res/bloatcycle.html > b.out
    1.25 +#   bloatdiff.pl a.out b.out
    1.26 +
    1.27 +EOUSAGE
    1.28 +}
    1.29 +
    1.30 +$OLDFILE = $ARGV[0];
    1.31 +$NEWFILE = $ARGV[1];
    1.32 +#$LABEL   = $ARGV[2];
    1.33 +
    1.34 +if (!$OLDFILE or
    1.35 +    ! -e $OLDFILE or 
    1.36 +    -z $OLDFILE) {
    1.37 +    print "\nError: Previous log file not specified, does not exist, or is empty.\n\n";
    1.38 +    &usage();
    1.39 +    exit 1;
    1.40 +}
    1.41 +
    1.42 +if (!$NEWFILE or
    1.43 +    ! -e $NEWFILE or 
    1.44 +    -z $NEWFILE) {
    1.45 +    print "\nError: Current log file not specified, does not exist, or is empty.\n\n";
    1.46 +    &usage();
    1.47 +    exit 1;
    1.48 +}
    1.49 +
    1.50 +sub processFile {
    1.51 +    my ($filename, $map, $prevMap) = @_;
    1.52 +    open(FH, $filename);
    1.53 +    while (<FH>) {
    1.54 +        if (m{
    1.55 +              ^\s*(\d+)\s          # Line number
    1.56 +              ([\w:]+)\s+          # Name
    1.57 +              (-?\d+)\s+           # Size
    1.58 +              (-?\d+)\s+           # Leaked
    1.59 +              (-?\d+)\s+           # Objects Total
    1.60 +              (-?\d+)\s+           # Objects Rem
    1.61 +              \(\s*(-?[\d.]+)\s+   # Objects Mean
    1.62 +                 \+/-\s+
    1.63 +              ([\w.]+)\)\s+        # Objects StdDev
    1.64 +              (-?\d+)\s+           # Reference Total
    1.65 +              (-?\d+)\s+           # Reference Rem
    1.66 +              \(\s*(-?[\d.]+)\s+   # Reference Mean
    1.67 +                 \+/-\s+
    1.68 +              ([\w\.]+)\)          # Reference StdDev
    1.69 +             }x) {
    1.70 +          $$map{$2} = { name => $2,
    1.71 +                        size => $3,
    1.72 +                        leaked => $4,
    1.73 +                        objTotal => $5,
    1.74 +                        objRem => $6,
    1.75 +                        objMean => $7,
    1.76 +                        objStdDev => $8,
    1.77 +                        refTotal => $9,
    1.78 +                        refRem => $10,
    1.79 +                        refMean => $11,
    1.80 +                        refStdDev => $12,
    1.81 +                        bloat => $3 * $5 # size * objTotal
    1.82 +                      };
    1.83 +        } else {
    1.84 +#            print "failed to parse: $_\n";
    1.85 +        }
    1.86 +    }
    1.87 +    close(FH);
    1.88 +}
    1.89 +
    1.90 +%oldMap = ();
    1.91 +processFile($OLDFILE, \%oldMap);
    1.92 +
    1.93 +%newMap = ();
    1.94 +processFile($NEWFILE, \%newMap);
    1.95 +
    1.96 +################################################################################
    1.97 +
    1.98 +$inf = 9999999.99;
    1.99 +
   1.100 +sub getLeaksDelta {
   1.101 +    my ($key) = @_;
   1.102 +    my $oldLeaks = $oldMap{$key}{leaked} || 0;
   1.103 +    my $newLeaks = $newMap{$key}{leaked};
   1.104 +    my $percentLeaks = 0;
   1.105 +    if ($oldLeaks == 0) {
   1.106 +        if ($newLeaks != 0) {
   1.107 +            # there weren't any leaks before, but now there are!
   1.108 +            $percentLeaks = $inf;
   1.109 +        }
   1.110 +    }
   1.111 +    else {
   1.112 +        $percentLeaks = ($newLeaks - $oldLeaks) / $oldLeaks * 100;
   1.113 +    }
   1.114 +    # else we had no record of this class before
   1.115 +    return ($newLeaks - $oldLeaks, $percentLeaks);
   1.116 +}
   1.117 +    
   1.118 +################################################################################
   1.119 +
   1.120 +sub getBloatDelta {
   1.121 +    my ($key) = @_;
   1.122 +    my $newBloat = $newMap{$key}{bloat};
   1.123 +    my $percentBloat = 0;
   1.124 +    my $oldSize = $oldMap{$key}{size} || 0;
   1.125 +    my $oldTotal = $oldMap{$key}{objTotal} || 0;
   1.126 +    my $oldBloat = $oldTotal * $oldSize;
   1.127 +    if ($oldBloat == 0) {
   1.128 +        if ($newBloat != 0) {
   1.129 +            # this class wasn't used before, but now it is
   1.130 +            $percentBloat = $inf;
   1.131 +        }
   1.132 +    }
   1.133 +    else {
   1.134 +        $percentBloat = ($newBloat - $oldBloat) / $oldBloat * 100;
   1.135 +    }
   1.136 +    # else we had no record of this class before
   1.137 +    return ($newBloat - $oldBloat, $percentBloat);
   1.138 +}
   1.139 +
   1.140 +################################################################################
   1.141 +
   1.142 +foreach $key (keys %newMap) {
   1.143 +    my ($newLeaks, $percentLeaks) = getLeaksDelta($key);
   1.144 +    my ($newBloat, $percentBloat) = getBloatDelta($key);
   1.145 +    $newMap{$key}{leakDelta} = $newLeaks;
   1.146 +    $newMap{$key}{leakPercent} = $percentLeaks;
   1.147 +    $newMap{$key}{bloatDelta} = $newBloat;
   1.148 +    $newMap{$key}{bloatPercent} = $percentBloat;
   1.149 +}
   1.150 +
   1.151 +################################################################################
   1.152 +
   1.153 +# Print a value of bytes out in a reasonable
   1.154 +# KB, MB, or GB form.  Copied from build-seamonkey-util.pl, sorry.  -mcafee
   1.155 +sub PrintSize($) {
   1.156 +
   1.157 +    # print a number with 3 significant figures
   1.158 +    sub PrintNum($) {
   1.159 +        my ($num) = @_;
   1.160 +        my $rv;
   1.161 +        if ($num < 1) {
   1.162 +            $rv = sprintf "%.3f", ($num);
   1.163 +        } elsif ($num < 10) {
   1.164 +            $rv = sprintf "%.2f", ($num);
   1.165 +        } elsif ($num < 100) {
   1.166 +            $rv = sprintf "%.1f", ($num);
   1.167 +        } else {
   1.168 +            $rv = sprintf "%d", ($num);
   1.169 +        }
   1.170 +    }
   1.171 +
   1.172 +    my ($size) = @_;
   1.173 +    my $rv;
   1.174 +    if ($size > 1000000000) {
   1.175 +        $rv = PrintNum($size / 1000000000.0) . "G";
   1.176 +    } elsif ($size > 1000000) {
   1.177 +        $rv = PrintNum($size / 1000000.0) . "M";
   1.178 +    } elsif ($size > 1000) {
   1.179 +        $rv = PrintNum($size / 1000.0) . "K";
   1.180 +    } else {
   1.181 +        $rv = PrintNum($size);
   1.182 +    }
   1.183 +}
   1.184 +
   1.185 +
   1.186 +print "Bloat/Leak Delta Report\n";
   1.187 +print "--------------------------------------------------------------------------------------\n";
   1.188 +print "Current file:  $NEWFILE\n";
   1.189 +print "Previous file: $OLDFILE\n";
   1.190 +print "----------------------------------------------leaks------leaks%------bloat------bloat%\n";
   1.191 +
   1.192 +    if (! $newMap{"TOTAL"} or 
   1.193 +        ! $newMap{"TOTAL"}{bloat}) {
   1.194 +        # It's OK if leaked or leakPercent are 0 (in fact, that would be good).
   1.195 +        # If bloatPercent is zero, it is also OK, because we may have just had
   1.196 +        # two runs exactly the same or with no new bloat.
   1.197 +        print "\nError: unable to calculate bloat/leak data.\n";
   1.198 +        print "There is no data present.\n\n";
   1.199 +        print "HINT - Did your test run complete successfully?\n";
   1.200 +        print "HINT - Are you pointing at the right log files?\n\n";
   1.201 +        &usage();
   1.202 +        exit 1;
   1.203 +    }
   1.204 +
   1.205 +printf "%-40s %10s %10.2f%% %10s %10.2f%%\n",
   1.206 +       ("TOTAL",
   1.207 +        $newMap{"TOTAL"}{leaked}, $newMap{"TOTAL"}{leakPercent},
   1.208 +        $newMap{"TOTAL"}{bloat}, $newMap{"TOTAL"}{bloatPercent});
   1.209 +
   1.210 +################################################################################
   1.211 +
   1.212 +sub percentStr {
   1.213 +    my ($p) = @_;
   1.214 +    if ($p == $inf) {
   1.215 +        return "-";
   1.216 +    }
   1.217 +    else {
   1.218 +        return sprintf "%10.2f%%", $p;
   1.219 +    }
   1.220 +}
   1.221 +
   1.222 +# NEW LEAKS
   1.223 +@keys = sort { $newMap{$b}{leakPercent} <=> $newMap{$a}{leakPercent} } keys %newMap;
   1.224 +my $needsHeading = 1;
   1.225 +my $total = 0;
   1.226 +foreach $key (@keys) {
   1.227 +    my $percentLeaks = $newMap{$key}{leakPercent};
   1.228 +    my $leaks = $newMap{$key}{leaked};
   1.229 +    if ($percentLeaks > 0 && $key !~ /TOTAL/) {
   1.230 +        if ($needsHeading) {
   1.231 +            printf "--NEW-LEAKS-----------------------------------leaks------leaks%%-----------------------\n";
   1.232 +            $needsHeading = 0;
   1.233 +        }
   1.234 +        printf "%-40s %10s %10s\n", ($key, $leaks, percentStr($percentLeaks));
   1.235 +        $total += $leaks;
   1.236 +    }
   1.237 +}
   1.238 +if (!$needsHeading) {
   1.239 +    printf "%-40s %10s\n", ("TOTAL", $total);
   1.240 +}
   1.241 +
   1.242 +# FIXED LEAKS
   1.243 +@keys = sort { $newMap{$b}{leakPercent} <=> $newMap{$a}{leakPercent} } keys %newMap;
   1.244 +$needsHeading = 1;
   1.245 +$total = 0;
   1.246 +foreach $key (@keys) {
   1.247 +    my $percentLeaks = $newMap{$key}{leakPercent};
   1.248 +    my $leaks = $newMap{$key}{leaked};
   1.249 +    if ($percentLeaks < 0 && $key !~ /TOTAL/) {
   1.250 +        if ($needsHeading) {
   1.251 +            printf "--FIXED-LEAKS---------------------------------leaks------leaks%%-----------------------\n";
   1.252 +            $needsHeading = 0;
   1.253 +        }
   1.254 +        printf "%-40s %10s %10s\n", ($key, $leaks, percentStr($percentLeaks));
   1.255 +        $total += $leaks;
   1.256 +    }
   1.257 +}
   1.258 +if (!$needsHeading) {
   1.259 +    printf "%-40s %10s\n", ("TOTAL", $total);
   1.260 +}
   1.261 +
   1.262 +# NEW BLOAT
   1.263 +@keys = sort { $newMap{$b}{bloatPercent} <=> $newMap{$a}{bloatPercent} } keys %newMap;
   1.264 +$needsHeading = 1;
   1.265 +$total = 0;
   1.266 +foreach $key (@keys) {
   1.267 +    my $percentBloat = $newMap{$key}{bloatPercent};
   1.268 +    my $bloat = $newMap{$key}{bloat};
   1.269 +    if ($percentBloat > 0  && $key !~ /TOTAL/) {
   1.270 +        if ($needsHeading) {
   1.271 +            printf "--NEW-BLOAT-----------------------------------bloat------bloat%%-----------------------\n";
   1.272 +            $needsHeading = 0;
   1.273 +        }
   1.274 +        printf "%-40s %10s %10s\n", ($key, $bloat, percentStr($percentBloat));
   1.275 +        $total += $bloat;
   1.276 +    }
   1.277 +}
   1.278 +if (!$needsHeading) {
   1.279 +    printf "%-40s %10s\n", ("TOTAL", $total);
   1.280 +}
   1.281 +
   1.282 +# ALL LEAKS
   1.283 +@keys = sort { $newMap{$b}{leaked} <=> $newMap{$a}{leaked} } keys %newMap;
   1.284 +$needsHeading = 1;
   1.285 +$total = 0;
   1.286 +foreach $key (@keys) {
   1.287 +    my $leaks = $newMap{$key}{leaked};
   1.288 +    my $percentLeaks = $newMap{$key}{leakPercent};
   1.289 +    if ($leaks > 0) {
   1.290 +        if ($needsHeading) {
   1.291 +            printf "--ALL-LEAKS-----------------------------------leaks------leaks%%-----------------------\n";
   1.292 +            $needsHeading = 0;
   1.293 +        }
   1.294 +        printf "%-40s %10s %10s\n", ($key, $leaks, percentStr($percentLeaks));
   1.295 +        if ($key !~ /TOTAL/) {
   1.296 +            $total += $leaks;
   1.297 +        }
   1.298 +    }
   1.299 +}
   1.300 +if (!$needsHeading) {
   1.301 +#    printf "%-40s %10s\n", ("TOTAL", $total);
   1.302 +}
   1.303 +
   1.304 +# ALL BLOAT
   1.305 +@keys = sort { $newMap{$b}{bloat} <=> $newMap{$a}{bloat} } keys %newMap;
   1.306 +$needsHeading = 1;
   1.307 +$total = 0;
   1.308 +foreach $key (@keys) {
   1.309 +    my $bloat = $newMap{$key}{bloat};
   1.310 +    my $percentBloat = $newMap{$key}{bloatPercent};
   1.311 +    if ($bloat > 0) {
   1.312 +        if ($needsHeading) {
   1.313 +            printf "--ALL-BLOAT-----------------------------------bloat------bloat%%-----------------------\n";
   1.314 +            $needsHeading = 0;
   1.315 +        }
   1.316 +        printf "%-40s %10s %10s\n", ($key, $bloat, percentStr($percentBloat));
   1.317 +        if ($key !~ /TOTAL/) {
   1.318 +            $total += $bloat;
   1.319 +        }
   1.320 +    }
   1.321 +}
   1.322 +if (!$needsHeading) {
   1.323 +#    printf "%-40s %10s\n", ("TOTAL", $total);
   1.324 +}
   1.325 +
   1.326 +# NEW CLASSES
   1.327 +@keys = sort { $newMap{$b}{bloatDelta} <=> $newMap{$a}{bloatDelta} } keys %newMap;
   1.328 +$needsHeading = 1;
   1.329 +my $ltotal = 0;
   1.330 +my $btotal = 0;
   1.331 +foreach $key (@keys) {
   1.332 +    my $leaks = $newMap{$key}{leaked};
   1.333 +    my $bloat = $newMap{$key}{bloat};
   1.334 +    my $percentBloat = $newMap{$key}{bloatPercent};
   1.335 +    if ($percentBloat == $inf && $key !~ /TOTAL/) {
   1.336 +        if ($needsHeading) {
   1.337 +            printf "--CLASSES-NOT-REPORTED-LAST-TIME--------------leaks------bloat------------------------\n";
   1.338 +            $needsHeading = 0;
   1.339 +        }
   1.340 +        printf "%-40s %10s %10s\n", ($key, $leaks, $bloat);
   1.341 +        if ($key !~ /TOTAL/) {
   1.342 +            $ltotal += $leaks;
   1.343 +            $btotal += $bloat;
   1.344 +        }
   1.345 +    }
   1.346 +}
   1.347 +if (!$needsHeading) {
   1.348 +    printf "%-40s %10s %10s\n", ("TOTAL", $ltotal, $btotal);
   1.349 +}
   1.350 +
   1.351 +# OLD CLASSES
   1.352 +@keys = sort { ($oldMap{$b}{bloat} || 0) <=> ($oldMap{$a}{bloat} || 0) } keys %oldMap;
   1.353 +$needsHeading = 1;
   1.354 +$ltotal = 0;
   1.355 +$btotal = 0;
   1.356 +foreach $key (@keys) {
   1.357 +    if (!defined($newMap{$key})) {
   1.358 +        my $leaks = $oldMap{$key}{leaked};
   1.359 +        my $bloat = $oldMap{$key}{bloat};
   1.360 +        if ($needsHeading) {
   1.361 +            printf "--CLASSES-THAT-WENT-AWAY----------------------leaks------bloat------------------------\n";
   1.362 +            $needsHeading = 0;
   1.363 +        }
   1.364 +        printf "%-40s %10s %10s\n", ($key, $leaks, $bloat);
   1.365 +        if ($key !~ /TOTAL/) {
   1.366 +            $ltotal += $leaks;
   1.367 +            $btotal += $bloat;
   1.368 +        }
   1.369 +    }
   1.370 +}
   1.371 +if (!$needsHeading) {
   1.372 +    printf "%-40s %10s %10s\n", ("TOTAL", $ltotal, $btotal);
   1.373 +}
   1.374 +
   1.375 +print "--------------------------------------------------------------------------------------\n";

mercurial