mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
wasm: add stats generator
This commit is contained in:
parent
9d3ac1a603
commit
0e7d6b65b4
|
@ -103,7 +103,9 @@ import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
|||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||
import org.teavm.backend.wasm.optimization.UnusedFunctionElimination;
|
||||
import org.teavm.backend.wasm.render.ReportingWasmBinaryStatsCollector;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryVersion;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||
import org.teavm.backend.wasm.render.WasmCRenderer;
|
||||
|
@ -205,6 +207,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
private Set<MethodReference> asyncMethods;
|
||||
private boolean hasThreads;
|
||||
private WasmRuntimeType runtimeType = WasmRuntimeType.TEAVM;
|
||||
private ReportingWasmBinaryStatsCollector statsCollector;
|
||||
|
||||
@Override
|
||||
public void setController(TeaVMTargetController controller) {
|
||||
|
@ -438,6 +441,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
@Override
|
||||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName)
|
||||
throws IOException {
|
||||
prepareStats();
|
||||
|
||||
var statsCollector = this.statsCollector != null ? this.statsCollector : WasmBinaryStatsCollector.EMPTY;
|
||||
WasmModule module = new WasmModule();
|
||||
WasmFunction initFunction = new WasmFunction("__start__");
|
||||
|
||||
|
@ -457,7 +463,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
: null;
|
||||
var classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),
|
||||
vtableProvider, tagRegistry, binaryWriter, names, metadataRequirements,
|
||||
controller.getClassInitializerInfo(), characteristics, dwarfClassGen);
|
||||
controller.getClassInitializerInfo(), characteristics, dwarfClassGen, statsCollector);
|
||||
|
||||
Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false);
|
||||
var stringPool = classGenerator.getStringPool();
|
||||
|
@ -550,22 +556,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
new IndirectCallTraceTransformation(module).apply();
|
||||
}
|
||||
|
||||
var writer = new WasmBinaryWriter();
|
||||
var debugBuilder = debugging ? new DebugInfoBuilder() : null;
|
||||
if (debugBuilder != null) {
|
||||
classGenerator.writeDebug(debugBuilder.classLayout());
|
||||
}
|
||||
var renderer = new WasmBinaryRenderer(
|
||||
writer, version, obfuscated, dwarfGenerator, dwarfClassGen,
|
||||
debugBuilder != null ? debugBuilder.lines() : null,
|
||||
debugBuilder != null ? debugBuilder.variables() : null
|
||||
);
|
||||
renderer.render(module, buildDebug(dwarfGenerator, dwarfClassGen, debugBuilder));
|
||||
|
||||
try (OutputStream output = buildTarget.createResource(outputName)) {
|
||||
output.write(writer.getData());
|
||||
output.flush();
|
||||
}
|
||||
writeBinaryWasm(buildTarget, outputName, module, classGenerator, dwarfGenerator, dwarfClassGen,
|
||||
statsCollector);
|
||||
|
||||
if (wastEmitted) {
|
||||
emitWast(module, buildTarget, getBaseName(outputName) + ".wast");
|
||||
|
@ -573,11 +565,52 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (cEmitted) {
|
||||
emitC(module, buildTarget, getBaseName(outputName) + ".wasm.c");
|
||||
}
|
||||
if (statsCollector != null) {
|
||||
writeStats(buildTarget, outputName);
|
||||
}
|
||||
|
||||
if (runtimeType == WasmRuntimeType.TEAVM) {
|
||||
emitRuntime(buildTarget, getBaseName(outputName) + ".wasm-runtime.js");
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareStats() {
|
||||
var statsProp = controller.getProperties().getProperty("teavm.wasm.stats");
|
||||
var stats = Boolean.parseBoolean(statsProp);
|
||||
if (stats) {
|
||||
statsCollector = new ReportingWasmBinaryStatsCollector();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStats(BuildTarget buildTarget, String outputName) throws IOException {
|
||||
try (var writer = new OutputStreamWriter(buildTarget.createResource(outputName + ".stats.txt"))) {
|
||||
statsCollector.write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBinaryWasm(BuildTarget buildTarget, String outputName,
|
||||
WasmModule module, WasmClassGenerator classGenerator, DwarfGenerator dwarfGenerator,
|
||||
DwarfClassGenerator dwarfClassGen, WasmBinaryStatsCollector statsCollector) throws IOException {
|
||||
|
||||
var writer = new WasmBinaryWriter();
|
||||
var debugBuilder = debugging ? new DebugInfoBuilder() : null;
|
||||
if (debugBuilder != null) {
|
||||
classGenerator.writeDebug(debugBuilder.classLayout());
|
||||
}
|
||||
|
||||
var renderer = new WasmBinaryRenderer(
|
||||
writer, version, obfuscated, dwarfGenerator, dwarfClassGen,
|
||||
debugBuilder != null ? debugBuilder.lines() : null,
|
||||
debugBuilder != null ? debugBuilder.variables() : null,
|
||||
statsCollector
|
||||
);
|
||||
renderer.render(module, buildDebug(dwarfGenerator, dwarfClassGen, debugBuilder));
|
||||
|
||||
try (var output = buildTarget.createResource(outputName)) {
|
||||
output.write(writer.getData());
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private Supplier<Collection<? extends WasmCustomSection>> buildDebug(DwarfGenerator generator,
|
||||
DwarfClassGenerator classGen, DebugInfoBuilder debugBuilder) {
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.teavm.backend.wasm.binary.DataType;
|
|||
import org.teavm.backend.wasm.binary.DataValue;
|
||||
import org.teavm.backend.wasm.debug.DebugClassLayout;
|
||||
import org.teavm.backend.wasm.debug.info.FieldType;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
import org.teavm.common.IntegerArray;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Function;
|
||||
|
@ -100,6 +101,7 @@ public class WasmClassGenerator {
|
|||
private ClassMetadataRequirements metadataRequirements;
|
||||
private ClassInitializerInfo classInitializerInfo;
|
||||
private DwarfClassGenerator dwarfClassGenerator;
|
||||
private WasmBinaryStatsCollector statsCollector;
|
||||
|
||||
private static final int CLASS_SIZE = 1;
|
||||
private static final int CLASS_FLAGS = 2;
|
||||
|
@ -121,18 +123,19 @@ public class WasmClassGenerator {
|
|||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter,
|
||||
NameProvider names, ClassMetadataRequirements metadataRequirements,
|
||||
ClassInitializerInfo classInitializerInfo, Characteristics characteristics,
|
||||
DwarfClassGenerator dwarfClassGenerator) {
|
||||
DwarfClassGenerator dwarfClassGenerator, WasmBinaryStatsCollector statsCollector) {
|
||||
this.processedClassSource = processedClassSource;
|
||||
this.classSource = classSource;
|
||||
this.vtableProvider = vtableProvider;
|
||||
this.tagRegistry = tagRegistry;
|
||||
this.binaryWriter = binaryWriter;
|
||||
this.stringPool = new WasmStringPool(this, binaryWriter);
|
||||
this.stringPool = new WasmStringPool(this, binaryWriter, statsCollector);
|
||||
this.names = names;
|
||||
this.metadataRequirements = metadataRequirements;
|
||||
this.classInitializerInfo = classInitializerInfo;
|
||||
this.characteristics = characteristics;
|
||||
this.dwarfClassGenerator = dwarfClassGenerator;
|
||||
this.statsCollector = statsCollector;
|
||||
}
|
||||
|
||||
public WasmStringPool getStringPool() {
|
||||
|
@ -193,6 +196,8 @@ public class WasmClassGenerator {
|
|||
calculateLayout(cls, binaryData, dwarfClass);
|
||||
if (binaryData.start >= 0) {
|
||||
binaryData.start = binaryWriter.append(createStructure(binaryData));
|
||||
var size = binaryWriter.getAddress() - binaryData.start;
|
||||
statsCollector.addClassMetadataSize(className, size);
|
||||
}
|
||||
if (dwarfClass != null) {
|
||||
dwarfClass.setSize(binaryData.size);
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.teavm.backend.wasm.binary.DataArray;
|
|||
import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||
import org.teavm.backend.wasm.binary.DataStructure;
|
||||
import org.teavm.backend.wasm.binary.DataValue;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
|
||||
|
@ -38,10 +39,13 @@ public class WasmStringPool {
|
|||
DataPrimitives.ADDRESS, /* monitor */
|
||||
DataPrimitives.ADDRESS, /* characters */
|
||||
DataPrimitives.INT /* hash code */);
|
||||
private WasmBinaryStatsCollector statsCollector;
|
||||
|
||||
public WasmStringPool(WasmClassGenerator classGenerator, BinaryWriter binaryWriter) {
|
||||
public WasmStringPool(WasmClassGenerator classGenerator, BinaryWriter binaryWriter,
|
||||
WasmBinaryStatsCollector statsCollector) {
|
||||
this.classGenerator = classGenerator;
|
||||
this.binaryWriter = binaryWriter;
|
||||
this.statsCollector = statsCollector;
|
||||
}
|
||||
|
||||
public int getStringPointer(String value) {
|
||||
|
@ -54,6 +58,8 @@ public class WasmStringPool {
|
|||
}
|
||||
|
||||
private int generateStringPointer(String value) {
|
||||
var start = binaryWriter.getAddress();
|
||||
|
||||
DataArray charactersType = new DataArray(DataPrimitives.SHORT, value.length());
|
||||
DataStructure wrapperType = new DataStructure((byte) 0, arrayHeaderType, charactersType);
|
||||
DataValue wrapper = wrapperType.createValue();
|
||||
|
@ -73,6 +79,9 @@ public class WasmStringPool {
|
|||
stringObject.setInt(0, (classPointer >>> 3) | RuntimeObject.GC_MARKED);
|
||||
stringObject.setAddress(2, binaryWriter.append(wrapper));
|
||||
|
||||
var size = binaryWriter.getAddress() - start;
|
||||
statsCollector.addStringsSize(size);
|
||||
|
||||
return stringPointer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2023 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.backend.wasm.render;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReportingWasmBinaryStatsCollector implements WasmBinaryStatsCollector {
|
||||
private Map<String, ClassStats> statsByClass = new LinkedHashMap<>();
|
||||
private ObjectIntMap<String> sectionSizes = new ObjectIntHashMap<>();
|
||||
private int stringsSize;
|
||||
|
||||
@Override
|
||||
public void addClassCodeSize(String className, int bytes) {
|
||||
getStats(className).codeSize += bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addClassMetadataSize(String className, int bytes) {
|
||||
getStats(className).metadataSize += bytes;
|
||||
}
|
||||
|
||||
private ClassStats getStats(String className) {
|
||||
return statsByClass.computeIfAbsent(className, k -> new ClassStats());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSectionSize(String name, int bytes) {
|
||||
sectionSizes.put(name, sectionSizes.get(name) + bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStringsSize(int bytes) {
|
||||
stringsSize += bytes;
|
||||
}
|
||||
|
||||
public void write(Writer writer) throws IOException {
|
||||
var pw = new PrintWriter(writer);
|
||||
pw.println("[classes]");
|
||||
for (var entry : statsByClass.entrySet()) {
|
||||
pw.append(entry.getKey()).append(" ");
|
||||
pw.print(entry.getValue().codeSize);
|
||||
pw.append(" ");
|
||||
pw.print(entry.getValue().metadataSize);
|
||||
pw.println();
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.println("[strings]");
|
||||
pw.println(stringsSize);
|
||||
|
||||
pw.println();
|
||||
pw.println("[sections]");
|
||||
for (var entry : sectionSizes) {
|
||||
pw.append(entry.key).append(" ");
|
||||
pw.print(entry.value);
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClassStats {
|
||||
int codeSize;
|
||||
int metadataSize;
|
||||
}
|
||||
}
|
|
@ -61,10 +61,11 @@ public class WasmBinaryRenderer {
|
|||
private DwarfFunctionGenerator dwarfFunctionGen;
|
||||
private DebugLines debugLines;
|
||||
private DebugVariables debugVariables;
|
||||
private WasmBinaryStatsCollector statsCollector;
|
||||
|
||||
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated,
|
||||
DwarfGenerator dwarfGenerator, DwarfClassGenerator dwarfClassGen, DebugLines debugLines,
|
||||
DebugVariables debugVariables) {
|
||||
DebugVariables debugVariables, WasmBinaryStatsCollector statsCollector) {
|
||||
this.output = output;
|
||||
this.version = version;
|
||||
this.obfuscated = obfuscated;
|
||||
|
@ -72,6 +73,7 @@ public class WasmBinaryRenderer {
|
|||
dwarfFunctionGen = dwarfClassGen != null ? new DwarfFunctionGenerator(dwarfClassGen, dwarfGenerator) : null;
|
||||
this.debugLines = debugLines;
|
||||
this.debugVariables = debugVariables;
|
||||
this.statsCollector = statsCollector;
|
||||
}
|
||||
|
||||
public void render(WasmModule module) {
|
||||
|
@ -279,8 +281,13 @@ public class WasmBinaryRenderer {
|
|||
section.writeLEB(functions.size());
|
||||
for (var function : functions) {
|
||||
var body = renderFunction(function, section.getPosition() + 4);
|
||||
var startPos = section.getPosition();
|
||||
section.writeLEB4(body.length);
|
||||
section.writeBytes(body);
|
||||
var size = section.getPosition() - startPos;
|
||||
if (function.getJavaMethod() != null) {
|
||||
statsCollector.addClassCodeSize(function.getJavaMethod().getClassName(), size);
|
||||
}
|
||||
}
|
||||
|
||||
if (dwarfGenerator != null) {
|
||||
|
@ -441,6 +448,7 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
|
||||
private void writeSection(int id, String name, byte[] data) {
|
||||
var start = output.getPosition();
|
||||
output.writeByte(id);
|
||||
int length = data.length;
|
||||
if (id == 0) {
|
||||
|
@ -452,5 +460,7 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
|
||||
output.writeBytes(data);
|
||||
|
||||
statsCollector.addSectionSize(name, output.getPosition() - start);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2023 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.backend.wasm.render;
|
||||
|
||||
public interface WasmBinaryStatsCollector {
|
||||
void addClassCodeSize(String className, int bytes);
|
||||
|
||||
void addClassMetadataSize(String className, int bytes);
|
||||
|
||||
void addStringsSize(int bytes);
|
||||
|
||||
void addSectionSize(String name, int bytes);
|
||||
|
||||
WasmBinaryStatsCollector EMPTY = new WasmBinaryStatsCollector() {
|
||||
@Override
|
||||
public void addClassCodeSize(String className, int bytes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addClassMetadataSize(String className, int bytes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStringsSize(int bytes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSectionSize(String name, int bytes) {
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user