mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
Add option to print size statistics of generated JS code
This commit is contained in:
parent
614f95d376
commit
168bf1fa9c
@ -15,12 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.teavm.backend.javascript;
|
package org.teavm.backend.javascript;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||||
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -83,6 +89,9 @@ import org.teavm.vm.spi.RendererListener;
|
|||||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||||
|
|
||||||
public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
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 TeaVMTargetController controller;
|
||||||
private boolean minifying = true;
|
private boolean minifying = true;
|
||||||
private final Map<MethodReference, Generator> methodGenerators = new HashMap<>();
|
private final Map<MethodReference, Generator> methodGenerators = new HashMap<>();
|
||||||
@ -285,6 +294,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||||||
for (RendererListener listener : rendererListeners) {
|
for (RendererListener listener : rendererListeners) {
|
||||||
listener.begin(renderer, target);
|
listener.begin(renderer, target);
|
||||||
}
|
}
|
||||||
|
int start = sourceWriter.getOffset();
|
||||||
sourceWriter.append("\"use strict\";").newLine();
|
sourceWriter.append("\"use strict\";").newLine();
|
||||||
renderer.renderRuntime();
|
renderer.renderRuntime();
|
||||||
renderer.render(clsNodes);
|
renderer.render(clsNodes);
|
||||||
@ -300,11 +310,46 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||||||
for (RendererListener listener : rendererListeners) {
|
for (RendererListener listener : rendererListeners) {
|
||||||
listener.complete();
|
listener.complete();
|
||||||
}
|
}
|
||||||
|
int totalSize = sourceWriter.getOffset() - start;
|
||||||
|
printStats(renderer, totalSize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO Error occured", 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) {
|
private List<ClassNode> modelToAst(ListableClassHolderSource classes) {
|
||||||
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(controller.getDependencyInfo().getCallGraph(),
|
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(controller.getDependencyInfo().getCallGraph(),
|
||||||
controller.getDiagnostics());
|
controller.getDiagnostics());
|
||||||
|
@ -19,4 +19,6 @@ public interface LocationProvider {
|
|||||||
int getLine();
|
int getLine();
|
||||||
|
|
||||||
int getColumn();
|
int getColumn();
|
||||||
|
|
||||||
|
int getOffset();
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
private final int lineWidth;
|
private final int lineWidth;
|
||||||
private int column;
|
private int column;
|
||||||
private int line;
|
private int line;
|
||||||
|
private int offset;
|
||||||
|
|
||||||
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
||||||
this.naming = naming;
|
this.naming = naming;
|
||||||
@ -62,6 +63,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
newLine();
|
newLine();
|
||||||
} else {
|
} else {
|
||||||
column++;
|
column++;
|
||||||
|
offset++;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -92,6 +94,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
}
|
}
|
||||||
appendIndent();
|
appendIndent();
|
||||||
column += end - start;
|
column += end - start;
|
||||||
|
offset += end - start;
|
||||||
innerWriter.append(csq, start, end);
|
innerWriter.append(csq, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +152,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
for (int i = 0; i < indentSize; ++i) {
|
for (int i = 0; i < indentSize; ++i) {
|
||||||
innerWriter.append(" ");
|
innerWriter.append(" ");
|
||||||
column += 4;
|
column += 4;
|
||||||
|
offset += 4;
|
||||||
}
|
}
|
||||||
lineStart = false;
|
lineStart = false;
|
||||||
}
|
}
|
||||||
@ -158,6 +162,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
innerWriter.append('\n');
|
innerWriter.append('\n');
|
||||||
column = 0;
|
column = 0;
|
||||||
++line;
|
++line;
|
||||||
|
++offset;
|
||||||
lineStart = true;
|
lineStart = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -169,6 +174,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
if (!minified) {
|
if (!minified) {
|
||||||
innerWriter.append(' ');
|
innerWriter.append(' ');
|
||||||
column++;
|
column++;
|
||||||
|
offset++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -185,6 +191,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
if (!minified) {
|
if (!minified) {
|
||||||
innerWriter.append('\n');
|
innerWriter.append('\n');
|
||||||
column = 0;
|
column = 0;
|
||||||
|
++offset;
|
||||||
++line;
|
++line;
|
||||||
lineStart = true;
|
lineStart = true;
|
||||||
}
|
}
|
||||||
@ -214,4 +221,9 @@ public class SourceWriter implements Appendable, LocationProvider {
|
|||||||
public int getLine() {
|
public int getLine() {
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOffset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.teavm.backend.javascript.rendering;
|
package org.teavm.backend.javascript.rendering;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||||
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -66,6 +68,10 @@ public class Renderer implements RenderingManager {
|
|||||||
private RenderingContext context;
|
private RenderingContext context;
|
||||||
private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>();
|
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,
|
public Renderer(SourceWriter writer, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
|
||||||
Diagnostics diagnostics, RenderingContext context) {
|
Diagnostics diagnostics, RenderingContext context) {
|
||||||
this.naming = context.getNaming();
|
this.naming = context.getNaming();
|
||||||
@ -79,6 +85,22 @@ public class Renderer implements RenderingManager {
|
|||||||
this.context = context;
|
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
|
@Override
|
||||||
public SourceWriter getWriter() {
|
public SourceWriter getWriter() {
|
||||||
return writer;
|
return writer;
|
||||||
@ -133,6 +155,7 @@ public class Renderer implements RenderingManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
int start = writer.getOffset();
|
||||||
writer.append("$rt_stringPool([");
|
writer.append("$rt_stringPool([");
|
||||||
for (int i = 0; i < context.getStringPool().size(); ++i) {
|
for (int i = 0; i < context.getStringPool().size(); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
@ -141,6 +164,7 @@ public class Renderer implements RenderingManager {
|
|||||||
writer.append('"').append(RenderingUtil.escapeString(context.getStringPool().get(i))).append('"');
|
writer.append('"').append(RenderingUtil.escapeString(context.getStringPool().get(i))).append('"');
|
||||||
}
|
}
|
||||||
writer.append("]);").newLine();
|
writer.append("]);").newLine();
|
||||||
|
stringPoolSize = writer.getOffset() - start;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error", e);
|
throw new RenderingException("IO error", e);
|
||||||
}
|
}
|
||||||
@ -149,14 +173,21 @@ public class Renderer implements RenderingManager {
|
|||||||
public void renderStringConstants() throws RenderingException {
|
public void renderStringConstants() throws RenderingException {
|
||||||
try {
|
try {
|
||||||
for (PostponedFieldInitializer initializer : postponedFieldInitializers) {
|
for (PostponedFieldInitializer initializer : postponedFieldInitializers) {
|
||||||
|
int start = writer.getOffset();
|
||||||
writer.appendStaticField(initializer.field).ws().append("=").ws()
|
writer.appendStaticField(initializer.field).ws().append("=").ws()
|
||||||
.append(context.constantToString(initializer.value)).append(";").softNewLine();
|
.append(context.constantToString(initializer.value)).append(";").softNewLine();
|
||||||
|
int sz = writer.getOffset() - start;
|
||||||
|
appendClassSize(initializer.field.getClassName(), sz);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error", 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 {
|
public void renderRuntime() throws RenderingException {
|
||||||
try {
|
try {
|
||||||
renderSetCloneMethod();
|
renderSetCloneMethod();
|
||||||
@ -291,8 +322,10 @@ public class Renderer implements RenderingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ClassNode cls : classes) {
|
for (ClassNode cls : classes) {
|
||||||
|
int start = writer.getOffset();
|
||||||
renderDeclaration(cls);
|
renderDeclaration(cls);
|
||||||
renderMethodBodies(cls);
|
renderMethodBodies(cls);
|
||||||
|
appendClassSize(cls.getName(), writer.getOffset() - start);
|
||||||
}
|
}
|
||||||
renderClassMetadata(classes);
|
renderClassMetadata(classes);
|
||||||
}
|
}
|
||||||
@ -452,6 +485,7 @@ public class Renderer implements RenderingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void renderClassMetadata(List<ClassNode> classes) {
|
private void renderClassMetadata(List<ClassNode> classes) {
|
||||||
|
int start = writer.getOffset();
|
||||||
try {
|
try {
|
||||||
writer.append("$rt_metadata([");
|
writer.append("$rt_metadata([");
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
@ -506,6 +540,8 @@ public class Renderer implements RenderingManager {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occurred", e);
|
throw new RenderingException("IO error occurred", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metadataSize = writer.getOffset() - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectMethodsToCopyFromInterfaces(ClassReader cls, List<MethodReference> targetList) {
|
private void collectMethodsToCopyFromInterfaces(ClassReader cls, List<MethodReference> targetList) {
|
||||||
|
Loading…
Reference in New Issue
Block a user