| /* |
| * 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> |
| * <metrics version="1"> |
| * |
| * <module elapsed="1234"> |
| * <sources count="1"> |
| * <source name="foo.java" /> |
| * </sources> |
| * <types count="1" kind="initial"> |
| * <type name="com.google.foo.Foo" /> |
| * </types> |
| * </module> |
| * |
| * <precompilations> |
| * <precompilation base="0" ids="0,1,2" elapsed="1"> |
| * <types count="1" kind="generated"> |
| * <type name="com.google.foo.Bar" /> |
| * </types> |
| * <types count="2" kind="ast"> |
| * <type name="com.google.foo.Foo" /> |
| * <type name="com.google.foo.Bar" /> |
| * </types> |
| * </precompilation> |
| * </precompilations> |
| * |
| * <compilations> |
| * <compilation id="0" elapsed="1" totalElapsed="2" description="foo"> |
| * <javascript fragments="1" size="123"> |
| * <fragment size="123" initial="true" /> |
| * </javascript> |
| * </compilation> |
| * </compilations> |
| * |
| * </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("\'", "'"); |
| return result.replaceAll("\"", """); |
| } |
| |
| 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 |
| } |
| } |