Added stat summarization to PermutatinInfo.

Change-Id: If45de84516844f8e3eff451d4c19030aa3de875c
diff --git a/src/main/java/com/google/gwt/benchmark/artifacts/PermutationInfo.java b/src/main/java/com/google/gwt/benchmark/artifacts/PermutationInfo.java
index 7ba085a..dd549f8 100644
--- a/src/main/java/com/google/gwt/benchmark/artifacts/PermutationInfo.java
+++ b/src/main/java/com/google/gwt/benchmark/artifacts/PermutationInfo.java
@@ -13,6 +13,7 @@
  */
 package com.google.gwt.benchmark.artifacts;
 
+import com.google.common.base.Function;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.gwt.benchmark.util.Util;
@@ -40,7 +41,19 @@
    * <p>
    * All sizes is are in bytes.
    */
-  public class Stats {
+  public static class Stats {
+    /**
+     * Computes an average from a list of stats.
+     */
+    public static Stats average(List<Stats> statsList) {
+      Stats result = new Stats();
+      for (Stats stats : statsList) {
+        result.add(stats);
+      }
+      result.divideBy(statsList.size());
+      return result;
+    }
+
     private long initialCompressedSize;
     private long initialUncompressedSize;
     private long leftoverCompressedSize;
@@ -114,6 +127,30 @@
       return totalUncompressedSize;
     }
 
+    private final void add(Stats from) {
+      this.initialCompressedSize += from.initialCompressedSize;
+      this.initialUncompressedSize += from.initialUncompressedSize;
+      this.leftoverCompressedSize += from.leftoverCompressedSize;
+      this.leftoverUncompressedSize += from.leftoverUncompressedSize;
+      this.totalCompressedSize += from.totalCompressedSize;
+      this.totalUncompressedSize += from.totalUncompressedSize;
+      this.numberOfFragments += from.numberOfFragments;
+      this.symbolMapItems += from.symbolMapItems;
+      this.symbolMapSize += from.symbolMapSize;
+    }
+
+    private final void divideBy(int d) {
+      this.initialCompressedSize /= d;
+      this.initialUncompressedSize /= d;
+      this.leftoverCompressedSize /= d;
+      this.leftoverUncompressedSize /= d;
+      this.totalCompressedSize /= d;
+      this.totalUncompressedSize /= d;
+      this.numberOfFragments /= d;
+      this.symbolMapItems /= d;
+      this.symbolMapSize /= d;
+    }
+
     private final void setInitialCompressedSize(long initialCompressedSize) {
       this.initialCompressedSize = initialCompressedSize;
     }
@@ -156,23 +193,33 @@
   private static final String MAIN_FILE_SUFFIX = ".cache.js";
 
   /**
+   * Computes the average stats from a list of permutations.
+   */
+  public static Stats computeAverages(List<PermutationInfo> allPermutationInfos) {
+    return Stats.average(Lists.transform(allPermutationInfos,
+        new Function<PermutationInfo, Stats>() {
+          @Override
+          public Stats apply(PermutationInfo permutationInfo) {
+            return permutationInfo.getStats();
+          }
+        }));
+  }
+
+  /**
    * Retrieves the PermutationInfo for all permutations in a compilation result.
    */
   public static List<PermutationInfo> getAllPemutationInfo(String outputJar, String auxJar,
       String basePath) throws IOException {
 
     int count = 0;
-    try (
-        ZipFile jarFile = new ZipFile(outputJar);
-        ZipFile auxJarFile = new ZipFile(auxJar)) {
+    try (ZipFile jarFile = new ZipFile(outputJar); ZipFile auxJarFile = new ZipFile(auxJar)) {
 
       // Read compile mappings.
-      List <PermutationInfo> permutationInfos =
-          processCompilationMappingsFile(basePath, jarFile);
+      List<PermutationInfo> permutationInfos = processCompilationMappingsFile(basePath, jarFile);
 
       // Compute the stats for each permutation defined in compilation-mappings.txt.
       for (PermutationInfo permInfo : permutationInfos) {
-        PermutationInfo.Stats stats = permInfo.new Stats();
+        Stats stats = new Stats();
         computeJsSizes(basePath, jarFile, permInfo, stats);
         computeSymbolInformation(basePath, auxJarFile, permInfo, stats);
         permInfo.setStats(stats);
@@ -206,10 +253,10 @@
         return null;
       }
       PermutationInfo permInfo =
-          new PermutationInfo(line.substring(0, line.length() -  MAIN_FILE_SUFFIX.length()));
+          new PermutationInfo(line.substring(0, line.length() - MAIN_FILE_SUFFIX.length()));
 
       // Read the properties.
-      while((line = in.readLine()) != null) {
+      while ((line = in.readLine()) != null) {
         String[] property = line.split(" ");
         if (property.length != 2) {
           break;
@@ -238,8 +285,7 @@
     }
     // The artifact was gzipped and then zipped so get the uncompressed size by
     // looking into the file and use the compressed size the gzipped size.
-    return Pair.of(getUncompressedFromGZippedEntry(jarFile, entry),
-        entry.getSize());
+    return Pair.of(getUncompressedFromGZippedEntry(jarFile, entry), entry.getSize());
   }
 
   /**
@@ -255,9 +301,10 @@
     stats.setInitialCompressedSize(compressedSize);
     long totalUncompressedSize = uncompressedSize;
     long totalCompressedSize = compressedSize;
-    for (int i = 1; ; i++) {
-      sizes = computeJsFileSizes(jarFile,
-          basePath + "/deferredjs/" + permInfo.getHash() + "/" + i+ MAIN_FILE_SUFFIX);
+    for (int i = 1;; i++) {
+      sizes =
+          computeJsFileSizes(jarFile, basePath + "/deferredjs/" + permInfo.getHash() + "/" + i
+              + MAIN_FILE_SUFFIX);
       if (sizes == null) {
         break;
       }
@@ -281,13 +328,12 @@
    */
   private static void computeSymbolInformation(String basePath, ZipFile auxJarFile,
       PermutationInfo permInfo, Stats stats) throws IOException {
-    ZipEntry entry = auxJarFile.getEntry(basePath + "/symbolMaps/" + permInfo.getHash() +
-        ".symbolMap");
+    ZipEntry entry =
+        auxJarFile.getEntry(basePath + "/symbolMaps/" + permInfo.getHash() + ".symbolMap");
     assert entry != null;
 
     stats.setSymbolMapSize(entry.getSize());
-    try (
-        InputStream entryStream = auxJarFile.getInputStream(entry);
+    try (InputStream entryStream = auxJarFile.getInputStream(entry);
         Scanner scanner = new Scanner(entryStream)) {
       scanner.useDelimiter("\n");
       int lines = 0;
@@ -302,7 +348,7 @@
    * before being zipped.
    */
   private static long getUncompressedFromGZippedEntry(ZipFile jarFile, ZipEntry gzippedEntry) {
-    try (InputStream entryStream = jarFile.getInputStream(gzippedEntry)){
+    try (InputStream entryStream = jarFile.getInputStream(gzippedEntry)) {
       return Util.getGzUncompressedSizeFromInputStream(entryStream, gzippedEntry.getSize());
     } catch (IOException e) {
       return -1;
@@ -313,14 +359,14 @@
    * Processes the compilation-mappings.txt file and creates an empty permutation info
    * for each permutation in it.
    */
-  private static List<PermutationInfo> processCompilationMappingsFile(
-      String basePath, ZipFile jarFile) throws IOException {
+  private static List<PermutationInfo> processCompilationMappingsFile(String basePath,
+      ZipFile jarFile) throws IOException {
     List<PermutationInfo> permutationInfos = Lists.newArrayList();
     ZipEntry compilationMappings = jarFile.getEntry(basePath + "/" + "compilation-mappings.txt");
-    try (BufferedReader compilationMappingsReader = new BufferedReader(
-        new InputStreamReader(jarFile.getInputStream(compilationMappings)))) {
+    try (BufferedReader compilationMappingsReader =
+        new BufferedReader(new InputStreamReader(jarFile.getInputStream(compilationMappings)))) {
       PermutationInfo permInfo;
-      while ((permInfo = readPermutationInfo(compilationMappingsReader)) != null){
+      while ((permInfo = readPermutationInfo(compilationMappingsReader)) != null) {
         permutationInfos.add(permInfo);
       }
     }
@@ -379,11 +425,13 @@
     result.append(stats.getSymbolMapSize());
     result.append(" ");
     result.append(String.format("total size= %s, initial size = %s, leftoversize = %s",
-        Util.formatSize(stats.getTotalCompressedSize()), Util.formatSize(stats.getInitialCompressedSize()),
+        Util.formatSize(stats.getTotalCompressedSize()),
+        Util.formatSize(stats.getInitialCompressedSize()),
         Util.formatSize(stats.getLeftoverCompressedSize())));
 
     result.append(String.format(" - total ucsize= %s, initial ucsize = %s, ucleftoversize = %s",
-        Util.formatSize(stats.getTotalUncompressedSize()), Util.formatSize(stats.getInitialUncompressedSize()),
+        Util.formatSize(stats.getTotalUncompressedSize()),
+        Util.formatSize(stats.getInitialUncompressedSize()),
         Util.formatSize(stats.getLeftoverUncompressedSize())));
     return result.toString();
   }
@@ -395,4 +443,4 @@
   private void setStats(Stats stats) {
     this.stats = stats;
   }
-}
\ No newline at end of file
+}