blob: d901071f9509e1aea6f1ca2b3ce4480cbd660c04 [file] [log] [blame]
/*
* Copyright 2010 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.ArtifactSet;
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.dev.util.collect.Lists;
import com.google.gwt.dev.util.collect.Sets;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* Exports the compiler metrics gathered by the precompile and
* compilePermutation steps into an XML file to be read by external tools.
*
* See compilerMetrics.xsd for an XML schema describing the output.
*
* <pre>
* &lt;metrics version="1">
*
* &lt;module elapsed="1234">
* &lt;sources count="1">
* &lt;source name="foo.java" />
* &lt;/sources>
* &lt;types count="1" kind="initial">
* &lt;type name="com.google.foo.Foo" />
* &lt;/types>
* &lt;/module>
*
* &lt;precompilations>
* &lt;precompilation base="0" ids="0,1,2" elapsed="1">
* &lt;types count="1" kind="generated">
* &lt;type name="com.google.foo.Bar" />
* &lt;/types>
* &lt;types count="2" kind="ast">
* &lt;type name="com.google.foo.Foo" />
* &lt;type name="com.google.foo.Bar" />
* &lt;/types>
* &lt;/precompilation>
* &lt;/precompilations>
*
* &lt;compilations>
* &lt;compilation id="0" elapsed="1" totalElapsed="2" description="foo">
* &lt;javascript fragments="1" size="123">
* &lt;fragment size="123" initial="true" />
* &lt;/javascript>
* &lt;/compilation>
* &lt;/compilations>
*
* &lt;/metrics>
*
*</pre>
*
*/
public class CompilerMetricsXmlFormatter {
public static final int XML_FORMAT_VERSION = 1;
public static byte[] writeMetricsAsXml(ArtifactSet artifacts,
ModuleMetricsArtifact moduleMetrics) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(out);
pw.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
pw.append("<metrics version=\"" + XML_FORMAT_VERSION + "\" >\n");
writeModuleMetricsAsXml(moduleMetrics, pw);
Set<PrecompilationMetricsArtifact> precompilationMetrics = artifacts.find(PrecompilationMetricsArtifact.class);
if (!precompilationMetrics.isEmpty()) {
pw.append(" <precompilations>\n");
for (PrecompilationMetricsArtifact metrics : precompilationMetrics) {
writePrecompilationMetricsAsXml(moduleMetrics, metrics, pw);
}
pw.append(" </precompilations>\n");
}
Set<CompilationMetricsArtifact> compilationMetrics = artifacts.find(CompilationMetricsArtifact.class);
if (!compilationMetrics.isEmpty()) {
pw.append(" <compilations>\n");
for (CompilationMetricsArtifact metrics : compilationMetrics) {
writeCompilationMetricsAsXml(metrics, pw);
}
pw.append(" </compilations>\n");
}
pw.append("</metrics>\n");
pw.close();
return out.toByteArray();
}
private static String escapeXmlAttributeContent(String content) {
String result = content.replaceAll("\'", "&apos;");
return result.replaceAll("\"", "&quot;");
}
private static void writeCompilationMetricsAsXml(
CompilationMetricsArtifact metrics, PrintWriter pw) {
pw.append(" <compilation id=\"" + metrics.getPermutationId() + "\" ");
pw.append("elapsed=\"" + metrics.getCompileElapsedMilliseconds() + "\" ");
pw.append("totalElapsed=\"" + metrics.getElapsedMilliseconds() + "\" ");
// TODO(zundel): Print out captured GC and heap memory analysis if it is
// available.
String description = metrics.getPermutationDescription();
if (description != null) {
pw.append(" description=\"" + escapeXmlAttributeContent(description) + "\"");
}
pw.append(">\n");
int[] jsSizes = metrics.getJsSize();
if (jsSizes != null) {
int totalSize = 0, numFragments = 0;
for (int size : jsSizes) {
totalSize += size;
numFragments++;
}
pw.append(" <javascript size=\"" + totalSize + "\" fragments=\""
+ numFragments + "\">\n");
boolean initialFragment = true;
for (int size : jsSizes) {
pw.append(" <fragment ");
if (initialFragment) {
pw.append("initial=\"true\" ");
initialFragment = false;
}
pw.append("size=\"" + size + "\" />\n");
}
pw.append(" </javascript>\n");
}
pw.append(" </compilation>\n");
}
private static void writeModuleMetricsAsXml(ModuleMetricsArtifact metrics,
PrintWriter pw) {
pw.append(" <module elapsed=\"" + metrics.getElapsedMilliseconds()
+ "\" ");
pw.append(">\n");
String[] sourceFiles = metrics.getSourceFiles();
if (sourceFiles != null) {
Arrays.sort(sourceFiles);
pw.append(" <sources count=\"" + sourceFiles.length + "\">\n");
for (String sourceFile : sourceFiles) {
pw.append(" <source name=\"" + sourceFile + "\" />\n");
}
pw.append(" </sources>\n");
}
String[] initialTypes = metrics.getInitialTypes();
if (initialTypes != null) {
Arrays.sort(initialTypes);
pw.append(" <types kind=\"initial\" count=\"" + initialTypes.length
+ "\">\n");
for (String typeName : initialTypes) {
pw.append(" <type name=\"" + typeName + "\" />\n");
}
pw.append(" </types>\n");
}
pw.append(" </module>\n");
}
private static void writePrecompilationMetricsAsXml(
ModuleMetricsArtifact moduleMetrics,
PrecompilationMetricsArtifact metrics, PrintWriter pw) {
pw.append(" <precompilation ");
pw.append("base=\"" + metrics.getPermutationBase() + "\" ");
int[] permutationIds = metrics.getPermutationIds();
if (permutationIds != null) {
StringBuilder builder = new StringBuilder();
for (int perm : permutationIds) {
builder.append("" + perm + ",");
}
String idList = builder.substring(0, builder.length() - 1);
pw.append("ids=\"" + idList + "\" ");
}
pw.append("elapsed=\"" + metrics.getElapsedMilliseconds() + "\" ");
// TODO(zundel): Print out captured GC and heap memory analysis if it is
// available.
pw.append(">\n");
String[] astTypes = metrics.getAstTypes();
if (astTypes != null) {
Arrays.sort(astTypes);
pw.append(" <types kind=\"ast\" count=\"" + astTypes.length + "\">\n");
for (String typeName : astTypes) {
pw.append(" <type name=\"" + typeName + "\" />\n");
}
pw.append(" </types>\n");
}
String[] finalTypeOracleTypes = metrics.getFinalTypeOracleTypes();
if (finalTypeOracleTypes != null) {
assert finalTypeOracleTypes.length > 0;
List<String> initialTypes = Lists.create(moduleMetrics.getInitialTypes());
Set<String> generatedTypesList = Sets.create(finalTypeOracleTypes);
generatedTypesList.removeAll(initialTypes);
String[] generatedTypes = generatedTypesList.toArray(new String[generatedTypesList.size()]);
Arrays.sort(generatedTypes);
pw.append(" <types kind=\"generated\" count=\"" + generatedTypes.length
+ "\">\n");
for (String typeName : generatedTypes) {
pw.append(" <type name=\"" + typeName + "\" />\n");
}
pw.append(" </types>\n");
}
pw.append(" </precompilation>\n");
}
private CompilerMetricsXmlFormatter() {
// do not instantiate
}
}