Skip to content

Commit

Permalink
More performance improvements & fixes (#1081)
Browse files Browse the repository at this point in the history
* only extract map script if map changed
* some more parallelization
* update wc3libs to fix loading screen issues
* only apply loading screen background when not null
  • Loading branch information
Frotty authored Nov 22, 2023
1 parent 1588f63 commit b82dc39
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 195 deletions.
2 changes: 1 addition & 1 deletion de.peeeq.wurstscript/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ dependencies {
implementation group: 'com.github.inwc3', name: 'jmpq3', version: '264c54cfc8'

// Water's wc3 libs
implementation 'com.github.inwc3:wc3libs:ad25440d15'
implementation 'com.github.inwc3:wc3libs:01fb9e23bf'

// The setup tool for wurst.build handling
implementation 'com.github.wurstscript:wurstsetup:475cc7fae8'
Expand Down
19 changes: 19 additions & 0 deletions de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/TimeTaker.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import de.peeeq.wurstscript.utils.Utils;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
Expand Down Expand Up @@ -53,6 +55,8 @@ class Recording implements TimeTaker {
private long currentPhaseStart;
private Map<String, Long> accumulatedTimes = new LinkedHashMap<>();

private Long startTime = 0L;

public <T> T measure(String name, Supplier<T> f) {
name = withNesting(name);
nesting++;
Expand All @@ -76,6 +80,9 @@ private void reportDuration(String name, long duration) {

@Override
public void beginPhase(String description) {
if (accumulatedTimes.isEmpty()) {
this.startTime = System.currentTimeMillis();
}
if (currentPhaseDescription != null) {
endPhase();
}
Expand All @@ -101,9 +108,21 @@ public void endPhase() {
public void printReport() {
System.out.println("#############################");
System.out.println("Run times:");

for (Map.Entry<String, Long> e : accumulatedTimes.entrySet()) {
System.out.println(e.getKey() + ": " + e.getValue() + "ms");
}

System.out.println("Total runtime: " + (System.currentTimeMillis() - startTime) + "ms");
System.out.println("GC time: " + getGarbageCollectionTime() + "ms");
}

private static long getGarbageCollectionTime() {
long collectionTime = 0;
for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans()) {
collectionTime += garbageCollectorMXBean.getCollectionTime();
}
return collectionTime;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,25 +421,31 @@ public JassProg transformProgToJass() {
beginPhase(2, "Eliminate generics");
new EliminateGenerics(imTranslator2, imProg2).transform();
printDebugImProg("./test-output/im " + stage++ + "_genericsEliminated.im");

timeTaker.endPhase();
// eliminate classes
beginPhase(2, "translate classes");

new EliminateClasses(imTranslator2, imProg2, !runArgs.isUncheckedDispatch()).eliminateClasses();
imTranslator2.assertProperties();
printDebugImProg("./test-output/im " + stage++ + "_classesEliminated.im");
timeTaker.endPhase();

new VarargEliminator(imProg2).run();
printDebugImProg("./test-output/im " + stage++ + "_varargEliminated.im");
imTranslator2.assertProperties();

timeTaker.endPhase();

if (runArgs.isNoDebugMessages()) {
beginPhase(3, "remove debug messages");
DebugMessageRemover.removeDebugMessages(imProg2);
timeTaker.endPhase();
} else {
// debug: add stacktraces
if (runArgs.isIncludeStacktraces()) {
beginPhase(4, "add stack traces");
new StackTraceInjector2(imProg2, imTranslator2).transform(timeTaker);
timeTaker.endPhase();
}
}
imTranslator2.assertProperties();
Expand All @@ -453,49 +459,60 @@ public JassProg transformProgToJass() {
imTranslator2.assertProperties();

printDebugImProg("./test-output/im " + stage++ + "_afterinline.im");
timeTaker.endPhase();
}

// eliminate tuples
beginPhase(6, "eliminate tuples");
getImProg().flatten(imTranslator2);
EliminateTuples.eliminateTuplesProg(getImProg(), imTranslator2);
timeTaker.measure("flatten", () -> getImProg().flatten(imTranslator2));
timeTaker.measure("kill tuples", () -> EliminateTuples.eliminateTuplesProg(getImProg(), imTranslator2));
getImTranslator().assertProperties(AssertProperty.NOTUPLES);

printDebugImProg("./test-output/im " + stage++ + "_withouttuples.im");

timeTaker.endPhase();

beginPhase(7, "eliminate multi arrays");
new MultiArrayEliminator(imProg2, imTranslator2, runArgs.isIncludeStacktraces() && !runArgs.isNoDebugMessages()).run();
printDebugImProg("./test-output/im " + stage++ + "_withoutmultiarrays.im");
imTranslator2.assertProperties();
timeTaker.endPhase();

beginPhase(7, "remove func refs");
beginPhase(8, "remove func refs");
new FuncRefRemover(imProg2, imTranslator2).run();
timeTaker.endPhase();

// remove cycles:
beginPhase(8, "remove cyclic functions");
beginPhase(9, "remove cyclic functions");
new CyclicFunctionRemover(imTranslator2, imProg2, timeTaker).work();

printDebugImProg("./test-output/im " + stage++ + "_nocyc.im");
timeTaker.endPhase();

// flatten
beginPhase(9, "flatten");
beginPhase(10, "flatten");
getImProg().flatten(imTranslator2);
getImTranslator().assertProperties(AssertProperty.NOTUPLES, AssertProperty.FLAT);

printDebugImProg("./test-output/im " + stage++ + "_flat.im");
timeTaker.endPhase();

if (runArgs.isLocalOptimizations()) {
beginPhase(10, "local optimizations");
beginPhase(11, "local optimizations");
optimizer.localOptimizations();
timeTaker.endPhase();
}

printDebugImProg("./test-output/im " + stage++ + "_afterlocalopts.im");

if (runArgs.isNullsetting()) {
beginPhase(11, "null setting");
beginPhase(12, "null setting");
optimizer.doNullsetting();
printDebugImProg("./test-output/im " + stage++ + "_afternullsetting.im");
timeTaker.endPhase();
}

beginPhase(13, "flatten");
optimizer.removeGarbage();
imProg.flatten(imTranslator);

Expand All @@ -504,12 +521,13 @@ public JassProg transformProgToJass() {
imProg.flatten(imTranslator);

printDebugImProg("./test-output/im " + stage++ + "_afterremoveGarbage1.im");
timeTaker.endPhase();

if (runArgs.isHotStartmap() || runArgs.isHotReload()) {
addJassHotCodeReloadCode();
}
if (runArgs.isOptimize()) {
beginPhase(12, "froptimize");
beginPhase(13, "froptimize");
optimizer.optimize();

optimizer.removeGarbage();
Expand All @@ -521,7 +539,7 @@ public JassProg transformProgToJass() {

// translate flattened intermediate lang to jass:

beginPhase(13, "translate to jass");
beginPhase(14, "translate to jass");
getImTranslator().calculateCallRelationsAndUsedVariables();
ImToJassTranslator translator =
new ImToJassTranslator(getImProg(), getImTranslator().getCalledFunctions(), getImTranslator().getMainFunc(), getImTranslator().getConfFunc());
Expand Down Expand Up @@ -841,11 +859,13 @@ public LuaCompilationUnit transformProgToLua() {
if (runArgs.isNoDebugMessages()) {
beginPhase(3, "remove debug messages");
DebugMessageRemover.removeDebugMessages(imProg);
timeTaker.endPhase();
} else {
// debug: add stacktraces
if (runArgs.isIncludeStacktraces()) {
beginPhase(4, "add stack traces");
new StackTraceInjector2(imProg, imTranslator).transform(timeTaker);
timeTaker.endPhase();
}
}
ImTranslator imTranslator2 = getImTranslator();
Expand All @@ -858,6 +878,7 @@ public LuaCompilationUnit transformProgToLua() {
imTranslator2.assertProperties();

printDebugImProg("./test-output/lua/im " + stage++ + "_afterinline.im");
timeTaker.endPhase();
}

// eliminate local types
Expand All @@ -867,11 +888,12 @@ public LuaCompilationUnit transformProgToLua() {

optimizer.removeGarbage();
imProg.flatten(imTranslator);

timeTaker.endPhase();
stage = 10;
if (runArgs.isLocalOptimizations()) {
beginPhase(10, "local optimizations");
optimizer.localOptimizations();
timeTaker.endPhase();
}

printDebugImProg("./test-output/lua/im " + stage++ + "_afterlocalopts.im");
Expand All @@ -893,11 +915,13 @@ public LuaCompilationUnit transformProgToLua() {
optimizer.removeGarbage();
imProg.flatten(imTranslator);
printDebugImProg("./test-output/lua/im " + stage++ + "_afteroptimize.im");
timeTaker.endPhase();
}
beginPhase(13, "translate to lua");
LuaTranslator luaTranslator = new LuaTranslator(imProg, imTranslator);
LuaCompilationUnit luaCode = luaTranslator.translate();
ImAttrType.setWurstClassType(TypesHelper.imInt());
timeTaker.endPhase();
return luaCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,60 @@
import de.peeeq.wurstscript.intermediatelang.ILconst;
import de.peeeq.wurstscript.intermediatelang.interpreter.NativesProvider;
import de.peeeq.wurstscript.intermediatelang.interpreter.NoSuchNativeException;
import de.peeeq.wurstscript.utils.Pair;

import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.stream.Collectors;

public abstract class ReflectionBasedNativeProvider implements NativesProvider {

protected PrintStream outStream = System.err;

@Override
public ILconst invoke(String funcname, ILconst[] args) throws NoSuchNativeException {
Method candidate = null;
nextMethod:
private final HashMap<Pair<String, Integer>, Method> methodMap = new HashMap<>();

public ReflectionBasedNativeProvider() {
for (Method method : this.getClass().getMethods()) {
if (method.getName().equals(funcname)) {
// this is a candidate as it has the correct name
candidate = method;
Object r;
try {
if (args.length != method.getParameterTypes().length) {
continue;
}
int i = 0;
for (Class<?> paramType : method.getParameterTypes()) {
if (!paramType.isAssignableFrom(args[i].getClass())) {
continue nextMethod;
}
i++;
}
r = method.invoke(this, (Object[]) args);
} catch (IllegalAccessException | IllegalArgumentException e) {
WLogger.severe(e);
throw new Error(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof InterpreterException) {
throw (InterpreterException) e.getCause();
} if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
throw new Error(e.getCause());
}
return (ILconst) r;
Pair<String, Integer> keyPair = Pair.create(method.getName(), method.getParameterTypes().length);
if (methodMap.containsKey(keyPair)) {
throw new RuntimeException("native entry already exists");
}
methodMap.put(keyPair, method);
}
String msg = "Calling method " + funcname + "(" +
}

@Override
public ILconst invoke(String funcname, ILconst[] args) throws NoSuchNativeException {
Method method = methodMap.get(Pair.create(funcname, args.length));
if (method == null) {
String msg = "Calling method " + funcname + "(" +
Arrays.stream(args).map(Object::toString).collect(Collectors.joining(", ")) + ")";
msg += "\nwith types " + funcname + "(" +
Arrays.stream(args).map(o -> o.getClass().getSimpleName()).collect(Collectors.joining(", ")) + ")";
if (candidate != null) {
msg += "\nDid you mean " + funcname + "(" +
Arrays.stream(candidate.getParameterTypes()).map(Class::getSimpleName).collect(Collectors.joining(", ")) + ")?";
msg += "\nwith types " + funcname + "(" +
Arrays.stream(args).map(o -> o.getClass().getSimpleName()).collect(Collectors.joining(", ")) + ")";
// if (candidate != null) {
// msg += "\nDid you mean " + funcname + "(" +
// Arrays.stream(candidate.getParameterTypes()).map(Class::getSimpleName).collect(Collectors.joining(", ")) + ")?";
// }
throw new NoSuchNativeException(msg);
}
throw new NoSuchNativeException(msg);
try {
return (ILconst) method.invoke(this, (Object[]) args);
} catch (IllegalAccessException | IllegalArgumentException e) {
WLogger.severe(e);
throw new Error(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof InterpreterException) {
throw (InterpreterException) e.getCause();
}
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
throw new Error(e.getCause());
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import java.util.HashMap;

public class ReflectionNativeProvider implements NativesProvider {
private HashMap<String, NativeJassFunction> methodMap = new HashMap<>();
private final HashMap<String, NativeJassFunction> methodMap = new HashMap<>();

public ReflectionNativeProvider(AbstractInterpreter interpreter) {
addProvider(new GamecacheProvider(interpreter));
Expand Down Expand Up @@ -70,10 +70,6 @@ private void addProvider(Provider provider) {

@Override
public ILconst invoke(String funcname, ILconst[] args) throws NoSuchNativeException {
String msg = "Calling method " + funcname + "(" +
Utils.printSep(", ", args) + ")";
WLogger.trace(msg);

NativeJassFunction candidate = methodMap.get(funcname);
if (candidate == null) {
throw new NoSuchNativeException("");
Expand Down
Loading

0 comments on commit b82dc39

Please sign in to comment.