All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.soyc.MakeTopLevelHtmlForPerm Maven / Gradle / Ivy

/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.gwt.soyc;

import com.google.gwt.core.ext.linker.CompilationMetricsArtifact;
import com.google.gwt.core.ext.linker.ModuleMetricsArtifact;
import com.google.gwt.core.ext.linker.PrecompilationMetricsArtifact;
import com.google.gwt.core.ext.soyc.impl.SizeMapRecorder;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.collect.Lists;
import com.google.gwt.dev.util.collect.Sets;
import com.google.gwt.soyc.io.OutputDirectory;
import com.google.gwt.thirdparty.guava.common.base.Joiner;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A utility to make all the HTML files for one permutation.
 */
public class MakeTopLevelHtmlForPerm {
  /**
   * A dependency linker for the initial code download. It links to the
   * dependencies for the initial download.
   */
  public class DependencyLinkerForInitialCode implements DependencyLinker {
    @Override
    public String dependencyLinkForClass(String className) {
      String packageName = globalInformation.getClassToPackage().get(className);
      assert packageName != null;
      return dependenciesFileName("initial") + "#" + className;
    }
  }

  /**
   * A dependency linker for the leftovers fragment. It links to leftovers
   * status pages.
   */
  public class DependencyLinkerForLeftoversFragment implements DependencyLinker {
    @Override
    public String dependencyLinkForClass(String className) {
      return leftoversStatusFileName() + "#"
          + hashedFilenameFragment(className);
    }
  }

  /**
   * A dependency linker for the total program breakdown. It links to a split
   * status page.
   *
   */
  public class DependencyLinkerForTotalBreakdown implements DependencyLinker {
    @Override
    public String dependencyLinkForClass(String className) {
      return splitStatusFileName() + "#" + hashedFilenameFragment(className);
    }
  }

  /**
   * A dependency linker that never links to anything.
   */
  public static class NullDependencyLinker implements DependencyLinker {
    @Override
    public String dependencyLinkForClass(String className) {
      return null;
    }
  }

  interface DependencyLinker {
    String dependencyLinkForClass(String className);
  }

  /**
   * Use this class to intern strings to save space in the generated HTML. After
   * populating the map, call getJs to create a JS array of all possible methods
   * in this report.
   */
  @SuppressWarnings("serial")
  private class HtmlInterner {
    // Hashes the interned string to the number of times this string is referenced.
    Map builder = new HashMap();
    // Hashes the interned string to its position in the final array of interned strings.
    // Populated after the call to {@link #freeze()}
    Map frozen = null;

    /**
     * Call this method after all calls to {@link #intern(String)} are complete.
     * This routine then re-orders the interned calls in order of the number of
     * times each string was referenced by intern() so that lower numbered index
     * values represent more frequently referenced strings.
     */
    public void freeze() {
      final int maxDigits = 9;
      assert (frozen == null);
      assert (builder.size() < Math.pow(10, maxDigits));

      // order the interned values with the most referenced first.
      String[] temp = new String[builder.size()];
      int index = 0;
      for (String key : builder.keySet()) {
        temp[index++] = key.format("%0" + maxDigits + "d%s", builder.get(key), key);
      }
      builder = null;
      Arrays.sort(temp);

      // strip off the numeric prefix on the key to build the frozen hash table
      index = 0;
      frozen = new LinkedHashMap();
      for (int i = temp.length - 1; i >= 0; i--) {
        frozen.put(temp[i].substring(maxDigits), index++);
      }
    }

    /**
     * Stores a string for later interning. Keeps track of the number of times a
     * particular string is interned which will be used by {@link #freeze()} to
     * place the most frequently used strings at the beginning of the
     * dictionary. After a call to {@link #freeze()}, it is no longer valid to
     * call this method.
     *
     * @param key string to be added to the intern dictionary.
     */
    public void intern(String key) {
      if (builder == null) {
        throw new RuntimeException("freeze() already called.");
      }
      if (!builder.containsKey(key)) {
        builder.put(key, 1);
      } else {
        int value = builder.get(key) + 1;
        builder.put(key, value);
      }
    }

    /**
     * Displays a link for a split point that contains this code.
     */
    public void printHasCodeInSplitPoint(PrintWriter outFile, String className,
        int sp) {
      outFile.print("h(" + frozen.get(getPackageSubstring(className)) + ","
          + frozen.get(getClassSubstring(className)) + "," + sp + ");");
    }

    /**
     * Non specific message that there is code in an initial fragment.
     */
    public void printHasInitialFragment(PrintWriter outFile) {
      outFile.print("f();");
    }

    /**
     * Displays a link for code in an initial fragment.
     */
    public void printHasInitialFragment(PrintWriter outFile, String className) {
      String packageName = getPackageSubstring(className);
      outFile.print("g(" + frozen.get(packageName) + ","
          + frozen.get(getClassSubstring(className)) + ","
          + frozen.get(hashedFilenameFragment(packageName)) + ");");
    }

    public void printSomeCodeLeftover(PrintWriter outFile) {
      outFile.print("i();");
    }

    /**
     * Prints an h3 element with the class name and an anchor.
     */
    private void printClassHeader(PrintWriter outFile, String className) {
      outFile.print("e(" + frozen.get(getPackageSubstring(className)) + ","
          + frozen.get(getClassSubstring(className)) + ",'"
          + hashedFilenameFragment(className) + "');");
    }

    /**
     * Print out a single class dependency stack in the methodDependencies
     * report.
     */
    private void printDependency(PrintWriter outFile,
        Map dependencies, String method, String depMethod) {
      String nameArray = "[" + frozen.get(getPackageSubstring(method)) + ","
          + frozen.get(getClassSubstring(method)) + ","
          + frozen.get(getMethodSubstring(method)) + "]";
      outFile.print("b(" + nameArray + ",");
      outFile.print("[");
      while (depMethod != null) {
        String nextDep = dependencies.get(depMethod);
        // The bottom of the stack frame is not interesting.
        if (nextDep != null) {
          String packageString = getPackageSubstring(depMethod);
          String classString = getClassSubstring(depMethod);
          String methodString = getMethodSubstring(depMethod);
          outFile.print("[" + frozen.get(packageString) + ","
              + frozen.get(classString) + "," + frozen.get(methodString) + "]");
        }
        depMethod = nextDep;
        if (nextDep != null && dependencies.get(nextDep) != null) {
          outFile.print(",");
        }
      }
      outFile.print("]);");
    }

    /**
     * Prints out a class header for the methodDependendies report.
     */
    private void printDependencyClassHeader(PrintWriter outFile,
        String className) {
      outFile.print("a(" + frozen.get(getPackageSubstring(className)) + ","
          + frozen.get(getClassSubstring(className)) + ");");
    }

    /**
     * Prints a JavaScript snippet that includes the dictionary of interned
     * strings and methods to use interned strings to create lines in the
     * report.
     *
     * Call this method after invoking {@link #freeze()}.
     *
     * @param outFile open file to write the data to.
     */
    private void printInternedDataAsJs(PrintWriter outFile) {
      if (frozen == null) {
        throw new RuntimeException("freeze() not called.");
      }
      outFile.println("  var internedStrings = [");
      for (String key : frozen.keySet()) {
        outFile.print("\"" + key + "\",");
      }
      outFile.println("];");

      // array of split point descriptions
      outFile.println("  var spl = [");
      for (int fragment = 1; fragment <= globalInformation.getNumFragments(); fragment++) {
        final List fragmentDescriptors = globalInformation.getFragmentDescriptors(fragment);
        String[] escapedFragmentDescriptors =
            new String[fragmentDescriptors.size()];
        for (int i = 0; i < fragmentDescriptors.size(); i++) {
          escapedFragmentDescriptors[i] =
              escapeJSString(fragmentDescriptors.get(i));
        }
        outFile.println("        '" + Joiner.on(",").join(escapedFragmentDescriptors) + "',");
      }
      outFile.println("  ];");

      // object/dictionary containing method sizes
      outFile.println("  var methodSizes = {");
      for (SizeBreakdown breakdown : globalInformation.allSizeBreakdowns()) {
        for (Entry methodEntry : breakdown.methodToSize.entrySet()) {
          String methodSignature = methodEntry.getKey();
          String method = methodSignature.substring(0, methodSignature.indexOf("("));
          outFile.println("    \"" + method + "\" : " + methodEntry.getValue() + ",");
        }
      }
      outFile.println("};");

      // dropdown button image srcs
      outFile.println("  var images = {");
      outFile.println("    \"closed\" : \"images/play-g16.png\",");
      outFile.println("    \"open\" : \"images/play-g16-down.png\",");
      outFile.println("  };");

      // TODO(zundel): Most of this below is just inserting a fixed string into the code. It would
      // be easier to read and maintain if we could store the fixed part in a flat file. Use some
      // kind of HTML template?

      // function to print a class header in the methodDependencies report
      // see printDependencyClassHeader()
      outFile.println("  function a(packageRef, classRef) {");
      outFile.println("    var className = internedStrings[packageRef] + \".\" + "
          + "internedStrings[classRef];");
      outFile.println("    document.write(\"
\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" }"); outFile.println(" function swapShowHide(elementName) {"); outFile.println(" hp = document.getElementById(elementName);"); outFile.println(" arrow = document.getElementById(\"dropdown-\" + elementName);"); outFile.println(" if (hp.style.display !== \"none\" && hp.style.display " + "!== \"inline\") {"); outFile.println(" hp.style.display = \"inline\";"); outFile.println(" arrow.src = images[\"open\"];"); outFile.println(" } else if (hp.style.display === \"none\") {"); outFile.println(" hp.style.display = \"inline\";"); outFile.println(" arrow.src = images[\"open\"];"); outFile.println(" } else {"); outFile.println(" hp.style.display = \"none\";"); outFile.println(" arrow.src = images[\"closed\"];"); outFile.println(" }"); outFile.println(" }"); // function to print a single dependency in the methodDependencies report // see printDependency() outFile.println(" function b(c, deps) {"); outFile.println(" var methodName = internedStrings[c[0]] + \".\" + internedStrings[c[1]] " + "+ \"::\" + internedStrings[c[2]];"); outFile.println(" var methodSize = methodSizes[methodName];"); outFile.println(" if (methodSize === undefined) methodSize = \"--\";"); outFile.println(" var callstackId = \"callstack-\" + methodName;"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\");"); outFile.println(" }"); // follows all method dependency stacks outFile.println(" function j() {"); outFile.println(" document.write(\"
" + "Class: \" + className + \"Size " + "(bytes)
\");"); outFile.println(" document.write(\"\");"); outFile.println(" document.write(\"\" + methodName + \"\");"); outFile.println(" document.write(\"
    \");"); outFile.println(" for (var i = 0; i < deps.length ; i++) {"); outFile.println(" var s = deps[i];"); outFile.println(" document.write(\"
  • \" + internedStrings[s[0]] + \".\" + " + "internedStrings[s[1]] + \"::\" + internedStrings[s[2]] + \"
  • \");"); outFile.println(" }"); outFile.println(" document.write(\"
\");"); outFile.println(" document.write(\"
\" + " + "methodSize + \"
\");"); outFile.println(" }"); // leftovers status line outFile.println(" function c(packageRef,classRef,packageHashRef) {"); outFile.println(" var packageName = internedStrings[packageRef];"); outFile.println(" var className = packageName + \".\" + internedStrings[classRef];"); outFile.println(" var d1 = 'methodDependencies-total-" + getPermutationId() + ".html';"); outFile.println(" document.write(\"\");"); outFile.println(" }"); // leftovers status package header line outFile.println(" function d(packageRef) {"); outFile.println(" document.write(\"
Package: \" + " + "internedStrings[packageRef] + \"
\");"); outFile.println(" }"); // leftovers status class header line outFile.println(" function e(packageRef,classRef,classHashRef) {"); outFile.println(" document.write(\"

\" + " + "internedStrings[packageRef] + \".\" + internedStrings[classRef] + \"

\");"); outFile.println(" }"); // split point has a class with code in the initial fragment - no link outFile.println(" function f() {"); outFile.println(" document.write(\"

Some code is included in the initial fragment" + "

\");"); outFile.println(" }"); // split point has a class with code in the initial fragment outFile.println(" function g(packageRef, classRef, packageHashRef) {"); outFile.println(" document.write(\"

Some code is included in the initial fragment " + "( See why)

\");"); outFile.println(" }"); // split point has code from class outFile.println(" function h(packageRef, classRef, sp) {"); outFile.println(" document.write(\"

Some code downloads with split point \" + sp + " + "\": \" + spl[sp - 1] + \"

\");"); outFile.println(" }"); // some code is left over outFile.println(" function i() {"); outFile.println(" document.write(\"

Some code is left over:

\");"); outFile.println(" }"); } /** * Prints links to each split point showing why a leftover fragment isn't * exclusive. */ private void printLeftoversStatus(PrintWriter outFile, String packageName, String className) { outFile.println("c(" + frozen.get(packageName) + "," + frozen.get(getClassSubstring(className)) + "," + frozen.get(hashedFilenameFragment(packageName)) + ");"); } /** * Prints a div containing the package name in a blue block. */ private void printPackageHeader(PrintWriter outFile, String packageName) { outFile.print("d(" + frozen.get(packageName) + ");"); } } /** * By a convention shared with the compiler, the initial download is fragment * number 0. */ private static final int FRAGMENT_NUMBER_INITIAL_DOWNLOAD = 0; /** * Just within this file, the convention is that the total program is fragment * number -1. */ private static final int FRAGMENT_NUMBER_TOTAL_PROGRAM = -1; /** * A pattern describing the name of dependency graphs for code fragments * corresponding to a specific split point. These can be either exclusive * fragments or fragments of code for split points in the initial load * sequence. */ private static final Pattern PATTERN_SP_INT = Pattern.compile("sp([0-9]+)"); public static void makeTopLevelHtmlForAllPerms( Map> allPermsInfo, OutputDirectory outDir) throws IOException { PrintWriter outFile = new PrintWriter(outDir.getOutputStream("index.html")); addStandardHtmlProlog(outFile, "Compile report", "Compile report", "Overview of permutations"); outFile.println("
    "); // in order to print these in ascending order, we have to sort by // integers SortedSet sortedPermIds = new TreeSet(); for (String permutationId : allPermsInfo.keySet()) { sortedPermIds.add(Integer.parseInt(permutationId)); } for (Integer sortedPermId : sortedPermIds) { String permutationId = Integer.toString(sortedPermId); List permutationInfoList = allPermsInfo.get(permutationId); outFile.print("
  • Permutation " + permutationId); for (String desc : permutationInfoList) { outFile.println(" (" + desc + ")"); } outFile.println("
      "); outFile.println("
    • "); outFile.println("Split Point Report"); outFile.println("
    • "); outFile.println("
    • "); outFile.println("Compiler Metrics"); outFile.println("
    • "); outFile.println("
    "); outFile.println("
  • "); } outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } /** * @return given "com.foo.myClass" or "com.foo.myClass::myMethod" returns * "myClass" */ static String getClassSubstring(String fullMethodName) { if (fullMethodName.length() == 0) { return ""; } int startIndex = getPackageSubstring(fullMethodName).length() + 1; int endIndex = fullMethodName.indexOf("::"); if (endIndex == -1) { endIndex = fullMethodName.length(); } if (startIndex > endIndex || startIndex > fullMethodName.length()) { return ""; } return fullMethodName.substring(startIndex, endIndex); } /** * @return given "com.foo.myClass::myMethod" returns "myMethod" */ static String getMethodSubstring(String fullMethodName) { int index = fullMethodName.indexOf("::"); if (index == -1) { return ""; } index += 2; if (index >= fullMethodName.length()) { return ""; } return fullMethodName.substring(index); } /** * @return given "com.foo.myClass" or "com.foo.myClass::myMethod" returns * "com.foo" */ static String getPackageSubstring(String fullMethodName) { int endIndex = fullMethodName.lastIndexOf('.'); if (endIndex == -1) { endIndex = fullMethodName.length(); } return fullMethodName.substring(0, endIndex); } private static void addSmallHtmlProlog(final PrintWriter outFile, String title) { outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(title); outFile.println(""); outFile.println(""); outFile.println(""); } private static void addStandardHtmlEnding(final PrintWriter out) { out.println("
"); out.println(""); out.println(""); } private static void addStandardHtmlProlog(final PrintWriter outFile, String title, String header1, String header2) { outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(title); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("

"); outFile.println(""); outFile.println("Google Web Toolkit"); outFile.println(""); outFile.println("

"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("

" + header1 + "

"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
"); if (header2 != null && header2.length() > 0) { outFile.println("

" + header2 + "

"); } } private static String classesInPackageFileName(SizeBreakdown breakdown, String permutationId) { return breakdown.getId() + "_" + permutationId + "_Classes.html"; } private String escapeJSString(String str) { // TODO(rluble): make into a Util routine. return str.replaceAll("/", "\\/"); } private static String escapeXml(String unescaped) { // TODO(rluble): see why SizeMapRecorder.escapeXML is different from Util.escapeXML. If two // different versions are needed at all move SizeMapRecorder.escapeXML to Util. return SizeMapRecorder.escapeXml(unescaped); } /** * Convert a potentially long string into a short file name. The current * implementation simply hashes the long name. */ private static String hashedFilenameFragment(String longFileName) { try { return Util.computeStrongName(longFileName.getBytes(Util.DEFAULT_ENCODING)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } private static String headerLineForBreakdown(SizeBreakdown breakdown) { return "(Analyzing code subset: " + breakdown.getDescription() + ")"; } private static String shellFileName(SizeBreakdown breakdown, String permutationId) { return breakdown.getId() + "-" + permutationId + "-overallBreakdown.html"; } /** * Global information for this permutation. */ private final GlobalInformation globalInformation; private final OutputDirectory outDir; MakeTopLevelHtmlForPerm(GlobalInformation globalInformation, OutputDirectory outDir) { this.globalInformation = globalInformation; this.outDir = outDir; } public void makeBreakdownShell(SizeBreakdown breakdown) throws IOException { Map nameToCodeColl = breakdown.nameToCodeColl; Map nameToLitColl = breakdown.nameToLitColl; String packageBreakdownFileName = makePackageHtml(breakdown); String codeTypeBreakdownFileName = makeCodeTypeHtml(breakdown, nameToCodeColl, nameToLitColl); PrintWriter outFile = new PrintWriter(getOutFile(shellFileName(breakdown, getPermutationId()))); addStandardHtmlProlog(outFile, "Application breakdown analysis", "Application breakdown analysis", ""); String popupName = "packageBreakdownPopup"; String popupTitle = "Package breakdown"; String popupBody = "The package breakdown blames pieces of JavaScript " + "code on Java packages wherever possible. Note that this is not possible for all " + "code, so the sizes of the packages here will not normally add up to the full code " + "size. More specifically, the sum will exclude strings, whitespace, and a few pieces " + "of JavaScript code that are produced during compilation but cannot be attributed to " + "any Java package."; outFile.println("

"); addPopupLink(outFile, popupName, popupTitle, null); outFile.println("

"); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); popupName = "codeTypeBreakdownPopup"; popupTitle = "Code Type Breakdown"; popupBody = "The code type breakdown breaks down the JavaScript code according to its " + "type or function. For example, it tells you how much of your code can be attributed to " + "JRE, GWT-RPC, etc. As above, strings and some other JavaScript snippets are not " + "included in the breakdown."; outFile.println("

"); addPopupLink(outFile, popupName, popupTitle, null); outFile.println("

"); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } public void makeCodeTypeClassesHtmls(SizeBreakdown breakdown) throws IOException { HashMap nameToCodeColl = breakdown.nameToCodeColl; for (String codeType : nameToCodeColl.keySet()) { // construct file name String outFileName = breakdown.getId() + "_" + codeType + "-" + getPermutationId() + "Classes.html"; float sumSize = 0f; TreeMap> sortedClasses = new TreeMap>( Collections.reverseOrder()); for (String className : nameToCodeColl.get(codeType).classes) { if (breakdown.classToSize.containsKey(className)) { int curSize = 0; if (breakdown.classToSize.containsKey(className)) { curSize = breakdown.classToSize.get(className); } if (curSize != 0) { if (sortedClasses.containsKey(curSize)) { Set existingSet = sortedClasses.get(curSize); existingSet.add(className); sortedClasses.put(curSize, existingSet); } else { Set newSet = new TreeSet(); newSet.add(className); sortedClasses.put(curSize, newSet); } sumSize += curSize; } } } final PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); addStandardHtmlProlog(outFile, "Classes in package " + codeType, "Classes in package " + codeType, headerLineForBreakdown(breakdown)); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); NumberFormat bytesFormatter = NumberFormat.getInstance(); bytesFormatter.setGroupingUsed(true); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); percentFormatter.setMinimumFractionDigits(1); percentFormatter.setMaximumFractionDigits(1); for (Integer size : sortedClasses.keySet()) { Set classNames = sortedClasses.get(size); for (String className : classNames) { float perc = (float) size / sumSize; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); } } addStandardHtmlEnding(outFile); outFile.close(); } } public void makeCompilerMetricsPermFiles(ModuleMetricsArtifact moduleMetrics, PrecompilationMetricsArtifact precompilationMetrics, CompilationMetricsArtifact compilationMetrics) throws IOException { String outFileName = "CompilerMetrics-" + precompilationMetrics.getPermutationBase() + "-index.html"; PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "Compiler Metrics for Permutation " + compilationMetrics.getPermutationId(); addStandardHtmlProlog(outFile, title, title, "Build Time Metrics"); NumberFormat elapsedFormatter = NumberFormat.getInstance(); elapsedFormatter.setGroupingUsed(true); elapsedFormatter.setMinimumFractionDigits(3); elapsedFormatter.setMaximumFractionDigits(3); outFile.println("
"); int permutationId = compilationMetrics.getPermutationId(); // Build Time Metrics outFile.println("
Code type"); outFile.println(""); outFile.println("Size (Bytes)"); outFile.println("% of total
" + className + ""); outFile.println("
"); // CHECKSTYLE_OFF outFile.println("
"); // CHECKSTYLE_ON outFile.println("
"); outFile.println("
"); outFile.println(bytesFormatter.format(size)); outFile.println("" + percentFormatter.format(perc) + "
"); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println("
PhaseElapsed Time
"); outFile.println("Module Analysis"); outFile.println("" + elapsedFormatter.format(moduleMetrics.getElapsedMilliseconds() / 1000.0) + " s"); outFile.println("
"); outFile.println("Precompile (may include Module Analysis)"); outFile.println("" + elapsedFormatter.format(precompilationMetrics.getElapsedMilliseconds() / 1000.0) + " s"); outFile.println("
"); outFile.println("Compile"); outFile.println("" + elapsedFormatter.format(compilationMetrics.getElapsedMilliseconds() / 1000.0) + " s"); outFile.println("
"); NumberFormat referencesFormatter = NumberFormat.getInstance(); referencesFormatter.setGroupingUsed(true); outFile.println("

"); outFile.println("

Source/Type Metrics

"); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); String sourcesFileName = "CompilerMetrics-sources.html"; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); makeCompilerMetricsSources(sourcesFileName, moduleMetrics, popupBody); String initialTypesFileName = "CompilerMetrics-initialTypes-" + permutationId + ".html"; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); makeCompilerMetricsInitialTypeOracleTypes(initialTypesFileName, moduleMetrics, popupBody); String finalTypesFileName = "CompilerMetrics-finalTypes-" + permutationId + ".html"; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); makeCompilerMetricsFinalTypeOracleTypes(finalTypesFileName, precompilationMetrics, popupBody); String[] generatedTypes = getGeneratedTypes(moduleMetrics, precompilationMetrics); String generatedTypesFileName = "CompilerMetrics-generatedTypes-" + permutationId + ".html"; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); makeCompilerMetricsGeneratedTypes(generatedTypesFileName, generatedTypes, popupBody); String astFileName = "CompilerMetrics-ast-" + permutationId + ".html"; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); makeCompilerMetricsAstTypes(astFileName, precompilationMetrics, popupBody); String[] unreferencedTypes = getUnreferencedTypes(precompilationMetrics); String unreferencedFileName = "CompilerMetrics-unreferencedTypes-" + permutationId + ".html"; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); makeCompilerMetricsUnreferencedTypes(unreferencedFileName, unreferencedTypes, popupBody); outFile.println("
DescriptionReferences
"); String popupName = "compilerMetricsSourceFiles"; String popupTitle = "Source files"; String popupBody = "All source files on the module source path."; addPopupLink(outFile, popupName, popupTitle, sourcesFileName); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println(referencesFormatter.format(moduleMetrics.getSourceFiles().length)); outFile.println("
"); popupName = "compilerMetricsInitialTypes"; popupTitle = "Initial Type Oracle Types"; popupBody = "All types in the type oracle after compiling sources on the source path."; addPopupLink(outFile, popupName, popupTitle, initialTypesFileName); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println(referencesFormatter.format(moduleMetrics.getInitialTypes().length)); outFile.println("
"); popupName = "compilerMetricsFinalTypes"; popupTitle = "Final Type Oracle Types"; popupBody = "All types in the type oracle after constructing the Java AST."; addPopupLink(outFile, popupName, popupTitle, finalTypesFileName); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println(referencesFormatter.format( precompilationMetrics.getFinalTypeOracleTypes().length)); outFile.println("
"); popupName = "compilerMetricsGeneratedTypes"; popupTitle = "GeneratedTypes"; popupBody = "Types that were added to the type oracle while running generators."; addPopupLink(outFile, popupName, popupTitle, generatedTypesFileName); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println(referencesFormatter.format(generatedTypes.length)); outFile.println("
"); popupName = "compilerMetricsAstTypes"; popupTitle = "AST Referenced Types"; popupBody = "All types referenced by the Java AST after performing " + "reachability analysis from the module EntryPoint."; addPopupLink(outFile, popupName, popupTitle, astFileName); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println(referencesFormatter.format(precompilationMetrics.getAstTypes().length)); outFile.println("
"); popupName = "compilerMetricsUnreferenceTypes"; popupTitle = "Unreferenced Types"; popupBody = "Types that were on the initial source path but never referenced in " + "the Java AST."; addPopupLink(outFile, popupName, popupTitle, unreferencedFileName); addPopup(outFile, popupName, popupTitle, popupBody); outFile.println(""); outFile.println(referencesFormatter.format(unreferencedTypes.length)); outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } public void makeDependenciesHtml() throws IOException { for (String depGraphName : globalInformation.dependencies.keySet()) { makeDependenciesHtml(depGraphName, globalInformation.dependencies.get(depGraphName)); } } public void makeLeftoverStatusPages() throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(leftoversStatusFileName())); addStandardHtmlProlog(outFile, "Leftovers page", "Leftovers page", ""); outFile.println("
"); outFile.println("

These classes have some leftover code, neither initial nor " + "exclusive to any split point:

"); String curPackageName = ""; HtmlInterner interner = new HtmlInterner(); for (String className : globalInformation.getClassToPackage().keySet()) { String packageName = globalInformation.getClassToPackage().get(className); interner.intern(packageName); interner.intern(getClassSubstring(className)); interner.intern(hashedFilenameFragment(packageName)); } interner.freeze(); outFile.println(""); addStandardHtmlEnding(outFile); outFile.close(); } public void makeLiteralsClassesTableHtmls(SizeBreakdown breakdown) throws IOException { Map nameToLitColl = breakdown.nameToLitColl; for (String literalType : nameToLitColl.keySet()) { String outFileName = literalType + "-" + getPermutationId() + "Lits.html"; final PrintWriter outFile = new PrintWriter(getOutFile(breakdown.getId() + "_" + outFileName)); addStandardHtmlProlog(outFile, "Literals of type " + literalType, "Literals of type " + literalType, headerLineForBreakdown(breakdown)); outFile.println(""); for (String literal : nameToLitColl.get(literalType).literals) { if (literal.trim().length() == 0) { literal = "[whitespace only string]"; } String escliteral = escapeXml(literal); outFile.println(""); outFile.println(""); outFile.println(""); } outFile.println("
" + escliteral + "
"); outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } } /** * Make size breakdowns for each package for one code collection. */ public void makePackageClassesHtmls(SizeBreakdown breakdown, DependencyLinker depLinker) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(classesInPackageFileName( breakdown, getPermutationId()))); addStandardHtmlProlog(outFile, "Classes in " + breakdown.getDescription(), "Classes in " + breakdown.getDescription(), headerLineForBreakdown(breakdown)); String[] packageNames = globalInformation.getPackageToClasses().keySet().toArray( new String[0]); Arrays.sort(packageNames); for (String packageName : packageNames) { TreeMap> sortedClasses = new TreeMap>( Collections.reverseOrder()); int sumSize = 0; for (String className : globalInformation.getPackageToClasses().get( packageName)) { int curSize = 0; if (!breakdown.classToSize.containsKey(className)) { // This class not present in this code collection } else { curSize = breakdown.classToSize.get(className); } if (curSize != 0f) { if (sortedClasses.containsKey(curSize)) { Set existingSet = sortedClasses.get(curSize); existingSet.add(className); sortedClasses.put(curSize, existingSet); } else { Set newSet = new TreeSet(); newSet.add(className); sortedClasses.put(curSize, newSet); } sumSize += curSize; } } if (sortedClasses.size() > 0) { outFile.println("

"); outFile.println("

"); outFile.print(""); outFile.print(""); outFile.print(""); outFile.println(""); outFile.print(""); outFile.print(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.print(""); NumberFormat bytesFormatter = NumberFormat.getInstance(); bytesFormatter.setGroupingUsed(true); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); percentFormatter.setMinimumFractionDigits(1); percentFormatter.setMaximumFractionDigits(1); for (Integer size : sortedClasses.keySet()) { Set classNames = sortedClasses.get(size); for (String className : classNames) { String drillDownFileName = depLinker.dependencyLinkForClass(className); float perc = (float) size / (float) sumSize; outFile.println(""); if (drillDownFileName == null) { outFile.println(""); } else { outFile.println(""); } outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); } } outFile.println("
Package: " + packageName + ""); outFile.println("Size (Bytes)"); outFile.println("% of total
" + className + "" + className + ""); outFile.println("
"); // CHECKSTYLE_OFF outFile.println("
"); // CHECKSTYLE_ON outFile.println("
"); outFile.println("
"); outFile.println(bytesFormatter.format(size)); outFile.println("" + percentFormatter.format(perc) + "
"); outFile.println("

"); } } addStandardHtmlEnding(outFile); outFile.close(); } public void makeSplitStatusPages() throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(splitStatusFileName())); addStandardHtmlProlog(outFile, "Split point status", "Split point status", ""); outFile.println("
"); HtmlInterner interner = new HtmlInterner(); for (String className : globalInformation.getClassToPackage().keySet()) { String packageName = globalInformation.getClassToPackage().get(className); interner.intern(packageName); interner.intern(getClassSubstring(className)); interner.intern(hashedFilenameFragment(packageName)); } interner.freeze(); outFile.println(""); addStandardHtmlEnding(outFile); outFile.close(); } public void makeTopLevelShell() throws IOException { String permutationId = getPermutationId(); PrintWriter outFile = new PrintWriter(getOutFile("SoycDashboard" + "-" + getPermutationId() + "-index.html")); addStandardHtmlProlog(outFile, "Compile report: Permutation " + permutationId, "Compile report: Permutation " + permutationId, ""); NumberFormat bytesFormatter = NumberFormat.getInstance(); bytesFormatter.setGroupingUsed(true); outFile.println("
"); outFile.println("
"); outFile.println("
"); outFile.println("
Full code size
"); outFile.println("
" + bytesFormatter.format(globalInformation.getTotalCodeBreakdown().sizeAllCode) + " Bytes
"); outFile.println("
Report
"); outFile.println("
"); outFile.println("
"); outFile.println("
Initial download size
"); // TODO(kprobst) -- add percentage here: (48%)"); outFile.println("
" + bytesFormatter.format(globalInformation.getInitialCodeBreakdown().sizeAllCode) + " Bytes
"); outFile.println("
Report
"); outFile.println("
"); outFile.println("
"); outFile.println("
Left over code
"); outFile.println("
" + bytesFormatter.format(globalInformation.getLeftoversBreakdown().sizeAllCode) + " Bytes
"); outFile.println("
Report
"); outFile.println("
"); outFile.println("
"); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); percentFormatter.setMinimumFractionDigits(1); percentFormatter.setMaximumFractionDigits(1); if (globalInformation.getNumFragments() >= 1) { int numFragments = globalInformation.getNumFragments(); int maxSize = globalInformation.getTotalCodeBreakdown().sizeAllCode; for (int fragment = FRAGMENT_NUMBER_TOTAL_PROGRAM; fragment <= numFragments + 1; fragment++) { SizeBreakdown breakdown; if (fragment == FRAGMENT_NUMBER_TOTAL_PROGRAM || fragment == numFragments + 1 // leftovers || fragment == FRAGMENT_NUMBER_INITIAL_DOWNLOAD) { continue; } breakdown = globalInformation.fragmentCodeBreakdown(fragment); String drillDownFileName = shellFileName(breakdown, getPermutationId()); final List fragmentDescriptors = globalInformation.getFragmentDescriptors(fragment); String[] escapedFragmentDescriptors = new String[fragmentDescriptors.size()]; for (int i = 0; i < fragmentDescriptors.size(); i++) { escapedFragmentDescriptors[i] = escapeXml(fragmentDescriptors.get(i)); } String fragmentDescription = Joiner.on("
").join(escapedFragmentDescriptors); int size = breakdown.sizeAllCode; float perc = (float) size / (float) maxSize; outFile.println("
"); outFile.println(""); outFile.print(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); } } outFile.println(""); outFile.println("
"); outFile.println("Split Points"); outFile.println("
#Location"); outFile.println("Size (Bytes)"); outFile.println("% of total
" + fragment + "" + fragmentDescription + ""); outFile.println("
"); // CHECKSTYLE_OFF outFile.println("
"); // CHECKSTYLE_ON outFile.println("
"); outFile.println("
"); outFile.println(bytesFormatter.format(size)); outFile.println("" + percentFormatter.format(perc) + "
"); outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } private void addPopup(PrintWriter outFile, String popupName, String popupTitle, String popupBody) { outFile.println("
"); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println("
" + popupTitle + "
" + popupBody + "
"); outFile.println("
"); } private void addPopupLink(PrintWriter outFile, String popupName, String popupTitle, String href) { outFile.println("" + popupTitle + ""); } /** * Returns a file name for the dependencies list. */ private String dependenciesFileName(String depGraphName) { return "methodDependencies-" + depGraphName + "-" + getPermutationId() + ".html"; } private String[] getGeneratedTypes(ModuleMetricsArtifact moduleMetrics, PrecompilationMetricsArtifact precompilationMetrics) { List initialTypes = Lists.create(moduleMetrics.getInitialTypes()); Set generatedTypes = Sets.create(precompilationMetrics.getFinalTypeOracleTypes()); generatedTypes.removeAll(initialTypes); String[] results = generatedTypes.toArray(new String[generatedTypes.size()]); Arrays.sort(results); return results; } /** * Return a {@link java.io.File} object for a file to be emitted into the * output directory. */ private OutputStream getOutFile(String localFileName) throws IOException { return outDir.getOutputStream(localFileName); } /** * @return the ID for the current permutation */ private String getPermutationId() { return globalInformation.getPermutationId(); } private String[] getUnreferencedTypes( PrecompilationMetricsArtifact precompilationMetrics) { List astTypes = Lists.create(precompilationMetrics.getAstTypes()); Set unreferencedTypes = Sets.create(precompilationMetrics.getFinalTypeOracleTypes()); unreferencedTypes.removeAll(astTypes); String[] results = unreferencedTypes.toArray(new String[unreferencedTypes.size()]); Arrays.sort(results); return results; } /** * Describe the code covered by the dependency graph with the supplied name. */ private String inferDepGraphDescription(String depGraphName) { if (depGraphName.equals("initial")) { return "Initially Live Code"; } if (depGraphName.equals("total")) { return "All Code"; } Matcher matcher = PATTERN_SP_INT.matcher(depGraphName); if (matcher.matches()) { int splitPoint = Integer.valueOf(matcher.group(1)); if (isInitialSplitPoint(splitPoint)) { return "Code Becoming Live at Split Point " + splitPoint; } else { return "Code not Exclusive to Split Point " + splitPoint; } } throw new RuntimeException("Unexpected dependency graph name: " + depGraphName); } /** * Returns whether a split point is initial or not. * * @param splitPoint * @returns true of the split point is initial, false otherwise */ private boolean isInitialSplitPoint(int splitPoint) { return globalInformation.getInitialFragmentLoadSequence().contains( splitPoint); } /** * Makes a file name for a leftovers status file. * * @return the file name of the leftovers status file */ private String leftoversStatusFileName() { return "leftoverStatus-" + getPermutationId() + ".html"; } /** * Produces an HTML file that breaks down by code type. * * @param breakdown * @param nameToCodeColl * @param nameToLitColl * @return the name of the produced file * @throws IOException */ private String makeCodeTypeHtml(SizeBreakdown breakdown, Map nameToCodeColl, Map nameToLitColl) throws IOException { String outFileName = breakdown.getId() + "-" + getPermutationId() + "-codeTypeBreakdown.html"; int sumSize = 0; TreeMap> sortedCodeTypes = new TreeMap>( Collections.reverseOrder()); for (String codeType : nameToCodeColl.keySet()) { int curSize = nameToCodeColl.get(codeType).getCumSize(breakdown); sumSize += curSize; if (curSize != 0) { if (sortedCodeTypes.containsKey(curSize)) { Set existingSet = sortedCodeTypes.get(curSize); existingSet.add(codeType); sortedCodeTypes.put(curSize, existingSet); } else { Set newSet = new TreeSet(); newSet.add(codeType); sortedCodeTypes.put(curSize, newSet); } } } final PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); addSmallHtmlProlog(outFile, "Code breakdown"); outFile.println(""); outFile.println("
"); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); NumberFormat bytesFormatter = NumberFormat.getInstance(); bytesFormatter.setGroupingUsed(true); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); percentFormatter.setMinimumFractionDigits(1); percentFormatter.setMaximumFractionDigits(1); for (Integer size : sortedCodeTypes.keySet()) { Set codeTypes = sortedCodeTypes.get(size); for (String codeType : codeTypes) { String drillDownFileName = breakdown.getId() + "_" + codeType + "-" + getPermutationId() + "Classes.html"; float perc = (float) size / (float) sumSize; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); } } outFile.println("
Type"); outFile.println("Size (Bytes)"); outFile.println("% of total
" + codeType + ""); outFile.println("
"); // CHECKSTYLE_OFF outFile.println("
"); // CHECKSTYLE_ON outFile.println("
"); outFile.println("
"); outFile.println(bytesFormatter.format(size)); outFile.println("" + percentFormatter.format(perc) + "
"); int stringSize = nameToLitColl.get("string").size; String drillDownFileName = breakdown.getId() + "_string-" + getPermutationId() + "Lits.html"; outFile.println("

" + stringSize + " bytes occupied by Strings

"); int unaccountedForSize = breakdown.sizeAllCode - sumSize - stringSize; outFile.println("

" + unaccountedForSize + " bytes of the JavaScript output cannot be attributed to any package or code type.

"); addStandardHtmlEnding(outFile); outFile.close(); return outFileName; } private void makeCompilerMetricsAstTypes(String outFileName, PrecompilationMetricsArtifact precompilationMetrics, String helpText) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "AST Types"; addStandardHtmlProlog(outFile, title, title, ""); outFile.println("

"); outFile.println(helpText); outFile.println("

"); outFile.println("
");
    String[] types = precompilationMetrics.getAstTypes();
    Arrays.sort(types);
    for (String type : types) {
      outFile.println(type);
    }
    outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } private void makeCompilerMetricsFinalTypeOracleTypes(String outFileName, PrecompilationMetricsArtifact precompilationMetrics, String helpText) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "Final Type Oracle Types"; addStandardHtmlProlog(outFile, title, title, ""); outFile.println("

"); outFile.println(helpText); outFile.println("

"); outFile.println("
");
    String[] types = precompilationMetrics.getFinalTypeOracleTypes();
    Arrays.sort(types);
    for (String type : types) {
      outFile.println(type);
    }
    outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } private void makeCompilerMetricsGeneratedTypes(String outFileName, String[] generatedTypes, String helpText) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "Generated Types"; addStandardHtmlProlog(outFile, title, title, ""); outFile.println("

"); outFile.println(helpText); outFile.println("

"); outFile.println("
");
    for (String type : generatedTypes) {
      outFile.println(type);
    }
    outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } private void makeCompilerMetricsInitialTypeOracleTypes(String outFileName, ModuleMetricsArtifact moduleMetrics, String helpText) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "Initial Type Oracle Types (built from source path)"; addStandardHtmlProlog(outFile, title, title, ""); outFile.println("

"); outFile.println(helpText); outFile.println("

"); outFile.println("
");
    String[] types = moduleMetrics.getInitialTypes();
    Arrays.sort(types);
    for (String type : types) {
      outFile.println(type);
    }
    outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } private void makeCompilerMetricsSources(String outFileName, ModuleMetricsArtifact moduleMetrics, String helpText) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "Sources on Source Path"; addStandardHtmlProlog(outFile, title, title, ""); outFile.println("

"); outFile.println(helpText); outFile.println("

"); outFile.println("
");
    String[] sources = moduleMetrics.getSourceFiles();
    Arrays.sort(sources);
    for (String source : sources) {
      outFile.println(source);
    }
    outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } private void makeCompilerMetricsUnreferencedTypes(String outFileName, String[] unreferencedTypes, String helpText) throws IOException { PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); String title = "Unreferenced Types"; addStandardHtmlProlog(outFile, title, title, ""); outFile.println("

"); outFile.println(helpText); outFile.println("

"); outFile.println("
");
    for (String type : unreferencedTypes) {
      outFile.println(type);
    }
    outFile.println("
"); addStandardHtmlEnding(outFile); outFile.close(); } /** * Produces an HTML file that displays dependencies. * * @param depGraphName name of dependency graph * @param dependencies map of dependencies * @throws IOException */ private void makeDependenciesHtml(String depGraphName, Map dependencies) throws IOException { String curPackageName = ""; HtmlInterner interner = new HtmlInterner(); for (String reportMethod : dependencies.keySet()) { interner.intern(getPackageSubstring(reportMethod)); interner.intern(getClassSubstring(reportMethod)); interner.intern(getMethodSubstring(reportMethod)); String depMethod = dependencies.get(reportMethod); while (depMethod != null) { interner.intern(getPackageSubstring(depMethod)); interner.intern(getClassSubstring(depMethod)); interner.intern(getMethodSubstring(depMethod)); depMethod = dependencies.get(depMethod); } } interner.freeze(); // Write out the interned data values as a script element String jsFileName = "methodDependencies-" + depGraphName + "-" + getPermutationId() + ".js"; PrintWriter outFile = new PrintWriter(getOutFile(jsFileName)); interner.printInternedDataAsJs(outFile); outFile.close(); List classesInPackage = new ArrayList(); for (String method : dependencies.keySet()) { classesInPackage.add(method); } makeDependenciesInternedHtml(depGraphName, classesInPackage, dependencies, interner, jsFileName); } /** * Produces an HTML file that displays dependencies. * * @param depGraphName name of dependency graph * @param dependencies map of dependencies * @throws IOException */ private void makeDependenciesInternedHtml(String depGraphName, List classesInSplitPoint, Map dependencies, HtmlInterner interner, String jsFileName) throws IOException { String depGraphDescription = inferDepGraphDescription(depGraphName); PrintWriter outFile = null; String curClassName = ""; String outFileName = dependenciesFileName(depGraphName); outFile = new PrintWriter(getOutFile(outFileName)); addStandardHtmlProlog(outFile, "Method Dependencies for " + depGraphDescription, "Method Dependencies for " + depGraphDescription, null); outFile.print(""); // Write out the HTML outFile.print(""); addStandardHtmlEnding(outFile); outFile.close(); } /** * Produces an HTML file that shows information about a package. * * @param breakdown * @return the name of the HTML file */ private String makePackageHtml(SizeBreakdown breakdown) throws IOException { String outFileName = breakdown.getId() + "-" + getPermutationId() + "-" + "packageBreakdown.html"; Map packageToPartialSize = breakdown.packageToSize; TreeMap> sortedPackages = new TreeMap>( Collections.reverseOrder()); float sumSize = 0f; for (String packageName : packageToPartialSize.keySet()) { Integer curSize = packageToPartialSize.get(packageName); if (sortedPackages.containsKey(curSize)) { Set existingSet = sortedPackages.get(curSize); existingSet.add(packageName); sortedPackages.put(curSize, existingSet); } else { Set newSet = new TreeSet(); newSet.add(packageName); sortedPackages.put(curSize, newSet); } sumSize += curSize; } final PrintWriter outFile = new PrintWriter(getOutFile(outFileName)); addSmallHtmlProlog(outFile, "Package breakdown"); outFile.println(""); outFile.println("
"); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); NumberFormat bytesFormatter = NumberFormat.getInstance(); bytesFormatter.setGroupingUsed(true); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); percentFormatter.setMinimumFractionDigits(1); percentFormatter.setMaximumFractionDigits(1); for (int size : sortedPackages.keySet()) { if (size == 0) { continue; } Set packageNames = sortedPackages.get(size); for (String packageName : packageNames) { String drillDownFileName = classesInPackageFileName(breakdown, getPermutationId()) + "#" + hashedFilenameFragment(packageName); float perc = size / sumSize; outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); outFile.println(""); } } outFile.println("
Packages (Sorted by size)"); outFile.println("Size (Bytes)"); outFile.println("% of total
" + packageName + ""); outFile.println("
"); // CHECKSTYLE_OFF outFile.println("
"); // CHECKSTYLE_ON outFile.println("
"); outFile.println("
"); outFile.println(bytesFormatter.format(size)); outFile.println("" + percentFormatter.format(perc) + "
"); addStandardHtmlEnding(outFile); outFile.close(); return outFileName; } /** * Find which split points include code belonging to className. */ private Iterable splitPointsWithClass(String className) { List sps = new ArrayList(); for (int sp = 1; sp <= globalInformation.getNumFragments(); sp++) { Map classToSize = globalInformation.fragmentCodeBreakdown(sp).classToSize; if (classToSize.containsKey(className)) { sps.add(sp); } } return sps; } private String splitStatusFileName() { return "splitStatus-" + getPermutationId() + ".html"; } }