Add option to print size statistics of generated JS code

This commit is contained in:
Alexey Andreev 2018-10-03 11:08:15 +03:00
parent 614f95d376
commit 168bf1fa9c
4 changed files with 95 additions and 0 deletions

View File

@ -15,12 +15,18 @@
*/
package org.teavm.backend.javascript;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -83,6 +89,9 @@ import org.teavm.vm.spi.RendererListener;
import org.teavm.vm.spi.TeaVMHostExtension;
public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
private static final NumberFormat STATS_NUM_FORMAT = new DecimalFormat("#,##0");
private static final NumberFormat STATS_PERCENT_FORMAT = new DecimalFormat("0.000 %");
private TeaVMTargetController controller;
private boolean minifying = true;
private final Map<MethodReference, Generator> methodGenerators = new HashMap<>();
@ -285,6 +294,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
for (RendererListener listener : rendererListeners) {
listener.begin(renderer, target);
}
int start = sourceWriter.getOffset();
sourceWriter.append("\"use strict\";").newLine();
renderer.renderRuntime();
renderer.render(clsNodes);
@ -300,11 +310,46 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
for (RendererListener listener : rendererListeners) {
listener.complete();
}
int totalSize = sourceWriter.getOffset() - start;
printStats(renderer, totalSize);
} catch (IOException e) {
throw new RenderingException("IO Error occured", e);
}
}
private void printStats(Renderer renderer, int totalSize) {
if (!Boolean.parseBoolean(System.getProperty("teavm.js.stats", "false"))) {
return;
}
System.out.println("Total output size: " + STATS_NUM_FORMAT.format(totalSize));
System.out.println("Metadata size: " + getSizeWithPercentage(renderer.getMetadataSize(), totalSize));
System.out.println("String pool size: " + getSizeWithPercentage(renderer.getStringPoolSize(), totalSize));
ObjectIntMap<String> packageSizeMap = new ObjectIntHashMap<>();
for (String className : renderer.getClassesInStats()) {
String packageName = className.substring(0, className.lastIndexOf('.') + 1);
int classSize = renderer.getClassSize(className);
packageSizeMap.put(packageName, packageSizeMap.getOrDefault(packageName, 0) + classSize);
}
String[] packageNames = packageSizeMap.keys().toArray(String.class);
Arrays.sort(packageNames, Comparator.comparing(p -> -packageSizeMap.getOrDefault(p, 0)));
for (String packageName : packageNames) {
System.out.println("Package '" + packageName + "' size: "
+ getSizeWithPercentage(packageSizeMap.get(packageName), totalSize));
}
}
private String getSizeWithPercentage(int size, int totalSize) {
return STATS_NUM_FORMAT.format(size) + " (" + STATS_PERCENT_FORMAT.format((double) size / totalSize) + ")";
}
static class PackageNode {
String name;
Map<String, PackageNode> children = new HashMap<>();
}
private List<ClassNode> modelToAst(ListableClassHolderSource classes) {
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(controller.getDependencyInfo().getCallGraph(),
controller.getDiagnostics());

View File

@ -19,4 +19,6 @@ public interface LocationProvider {
int getLine();
int getColumn();
int getOffset();
}

View File

@ -30,6 +30,7 @@ public class SourceWriter implements Appendable, LocationProvider {
private final int lineWidth;
private int column;
private int line;
private int offset;
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
this.naming = naming;
@ -62,6 +63,7 @@ public class SourceWriter implements Appendable, LocationProvider {
newLine();
} else {
column++;
offset++;
}
return this;
}
@ -92,6 +94,7 @@ public class SourceWriter implements Appendable, LocationProvider {
}
appendIndent();
column += end - start;
offset += end - start;
innerWriter.append(csq, start, end);
}
@ -149,6 +152,7 @@ public class SourceWriter implements Appendable, LocationProvider {
for (int i = 0; i < indentSize; ++i) {
innerWriter.append(" ");
column += 4;
offset += 4;
}
lineStart = false;
}
@ -158,6 +162,7 @@ public class SourceWriter implements Appendable, LocationProvider {
innerWriter.append('\n');
column = 0;
++line;
++offset;
lineStart = true;
return this;
}
@ -169,6 +174,7 @@ public class SourceWriter implements Appendable, LocationProvider {
if (!minified) {
innerWriter.append(' ');
column++;
offset++;
}
}
return this;
@ -185,6 +191,7 @@ public class SourceWriter implements Appendable, LocationProvider {
if (!minified) {
innerWriter.append('\n');
column = 0;
++offset;
++line;
lineStart = true;
}
@ -214,4 +221,9 @@ public class SourceWriter implements Appendable, LocationProvider {
public int getLine() {
return line;
}
@Override
public int getOffset() {
return offset;
}
}

View File

@ -15,6 +15,8 @@
*/
package org.teavm.backend.javascript.rendering;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
@ -66,6 +68,10 @@ public class Renderer implements RenderingManager {
private RenderingContext context;
private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>();
private ObjectIntMap<String> sizeByClass = new ObjectIntHashMap<>();
private int stringPoolSize;
private int metadataSize;
public Renderer(SourceWriter writer, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
Diagnostics diagnostics, RenderingContext context) {
this.naming = context.getNaming();
@ -79,6 +85,22 @@ public class Renderer implements RenderingManager {
this.context = context;
}
public int getStringPoolSize() {
return stringPoolSize;
}
public int getMetadataSize() {
return metadataSize;
}
public String[] getClassesInStats() {
return sizeByClass.keys().toArray(String.class);
}
public int getClassSize(String className) {
return sizeByClass.getOrDefault(className, 0);
}
@Override
public SourceWriter getWriter() {
return writer;
@ -133,6 +155,7 @@ public class Renderer implements RenderingManager {
return;
}
try {
int start = writer.getOffset();
writer.append("$rt_stringPool([");
for (int i = 0; i < context.getStringPool().size(); ++i) {
if (i > 0) {
@ -141,6 +164,7 @@ public class Renderer implements RenderingManager {
writer.append('"').append(RenderingUtil.escapeString(context.getStringPool().get(i))).append('"');
}
writer.append("]);").newLine();
stringPoolSize = writer.getOffset() - start;
} catch (IOException e) {
throw new RenderingException("IO error", e);
}
@ -149,14 +173,21 @@ public class Renderer implements RenderingManager {
public void renderStringConstants() throws RenderingException {
try {
for (PostponedFieldInitializer initializer : postponedFieldInitializers) {
int start = writer.getOffset();
writer.appendStaticField(initializer.field).ws().append("=").ws()
.append(context.constantToString(initializer.value)).append(";").softNewLine();
int sz = writer.getOffset() - start;
appendClassSize(initializer.field.getClassName(), sz);
}
} catch (IOException e) {
throw new RenderingException("IO error", e);
}
}
private void appendClassSize(String className, int sz) {
sizeByClass.put(className, sizeByClass.getOrDefault(className, 0) + sz);
}
public void renderRuntime() throws RenderingException {
try {
renderSetCloneMethod();
@ -291,8 +322,10 @@ public class Renderer implements RenderingManager {
}
}
for (ClassNode cls : classes) {
int start = writer.getOffset();
renderDeclaration(cls);
renderMethodBodies(cls);
appendClassSize(cls.getName(), writer.getOffset() - start);
}
renderClassMetadata(classes);
}
@ -452,6 +485,7 @@ public class Renderer implements RenderingManager {
}
private void renderClassMetadata(List<ClassNode> classes) {
int start = writer.getOffset();
try {
writer.append("$rt_metadata([");
boolean first = true;
@ -506,6 +540,8 @@ public class Renderer implements RenderingManager {
} catch (IOException e) {
throw new RenderingException("IO error occurred", e);
}
metadataSize = writer.getOffset() - start;
}
private void collectMethodsToCopyFromInterfaces(ClassReader cls, List<MethodReference> targetList) {