Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion de.peeeq.wurstscript/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ dependencies {
implementation 'commons-lang:commons-lang:2.6'
implementation 'com.github.albfernandez:juniversalchardet:2.4.0'
implementation 'com.github.inwc3:jmpq3:29b55f2c32'
implementation 'com.github.inwc3:wc3libs:bab65b961b'
implementation 'com.github.inwc3:wc3libs:cc49c8e63c'
implementation('com.github.wurstscript:wurstsetup:393cf5ea39') {
exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit'
exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit.ssh.apache'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public class CompiletimeFunctionRunner {
private final ImTranslator translator;
private boolean injectObjects;
private final Deque<Runnable> delayedActions = new ArrayDeque<>();
private final Map<String, Long> compiletimeFunctionNanos = new LinkedHashMap<>();
private long compiletimeExprNanos = 0L;

public ILInterpreter getInterpreter() {
return interpreter;
Expand Down Expand Up @@ -97,21 +99,29 @@ public CompiletimeFunctionRunner(

public void run() {
try {
long t0 = System.nanoTime();
List<Either<ImCompiletimeExpr, ImFunction>> toExecute = new ArrayList<>();
collectCompiletimeExpressions(toExecute);
collectCompiletimeFunctions(toExecute);
long tCollected = System.nanoTime();

toExecute.sort(Comparator.comparing(this::getOrderIndex));
long tSorted = System.nanoTime();

execute(toExecute);
long tExecuted = System.nanoTime();


if (functionFlag == FunctionFlagToRun.CompiletimeFunctions) {
interpreter.writebackGlobalState(isInjectObjects());
}
long tWriteback = System.nanoTime();
runDelayedActions();
long tDelayed = System.nanoTime();

partitionCompiletimeStateInitFunction();
long tPartitioned = System.nanoTime();
logCompiletimeTiming(toExecute, t0, tCollected, tSorted, tExecuted, tWriteback, tDelayed, tPartitioned);

} catch (InterpreterException e) {
Element origin = e.getTrace();
Expand All @@ -136,6 +146,48 @@ public void run() {

}

private void logCompiletimeTiming(List<Either<ImCompiletimeExpr, ImFunction>> toExecute,
long t0, long tCollected, long tSorted, long tExecuted,
long tWriteback, long tDelayed, long tPartitioned) {
int exprCount = 0;
int funcCount = 0;
for (Either<ImCompiletimeExpr, ImFunction> e : toExecute) {
if (e.isLeft()) {
exprCount++;
} else {
funcCount++;
}
}
WLogger.info(String.format(
"Compiletime breakdown: total=%dms collect=%dms sort=%dms execute=%dms writeback=%dms delayed=%dms partition=%dms funcs=%d exprs=%d exprEval=%dms",
ms(tPartitioned - t0),
ms(tCollected - t0),
ms(tSorted - tCollected),
ms(tExecuted - tSorted),
ms(tWriteback - tExecuted),
ms(tDelayed - tWriteback),
ms(tPartitioned - tDelayed),
funcCount,
exprCount,
ms(compiletimeExprNanos)
));
if (!compiletimeFunctionNanos.isEmpty()) {
List<Map.Entry<String, Long>> top = compiletimeFunctionNanos.entrySet().stream()
.sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
.limit(10)
.collect(Collectors.toList());
StringBuilder sb = new StringBuilder("Top compiletime functions:");
for (Map.Entry<String, Long> e : top) {
sb.append("\n ").append(e.getKey()).append(": ").append(ms(e.getValue())).append("ms");
}
WLogger.info(sb.toString());
}
}

private static long ms(long nanos) {
return nanos / 1_000_000L;
}

private void partitionCompiletimeStateInitFunction() {
if (compiletimeStateInitFunction == null) {
return;
Expand Down Expand Up @@ -220,6 +272,7 @@ public void visit(ImCompiletimeExpr e) {


private void executeCompiletimeExpr(ImCompiletimeExpr cte) {
long t0 = System.nanoTime();
try {
ProgramState globalState = interpreter.getGlobalState();
globalState.setLastStatement(cte);
Expand Down Expand Up @@ -261,6 +314,8 @@ private void executeCompiletimeExpr(ImCompiletimeExpr cte) {
e.setStacktrace(msg);
e.setTrace(cte.attrTrace());
throw e;
} finally {
compiletimeExprNanos += System.nanoTime() - t0;
}
}

Expand Down Expand Up @@ -491,11 +546,12 @@ private ImFunction findNative(String funcName, WPos trace) {

private void executeCompiletimeFunction(ImFunction f) {
if (functionFlag.matches(f)) {
long t0 = System.nanoTime();
try {
if (!f.getBody().isEmpty()) {
interpreter.getGlobalState().setLastStatement(f.getBody().get(0));
}
WLogger.debug("running " + functionFlag + " function " + f.getName());
WLogger.debug(() -> "running " + functionFlag + " function " + f.getName());
interpreter.runVoidFunc(f, null);
successTests.add(f);
} catch (TestSuccessException e) {
Expand All @@ -505,6 +561,8 @@ private void executeCompiletimeFunction(ImFunction f) {
} catch (Throwable e) {
failTests.put(f, Pair.create(interpreter.getLastStatement(), e.toString()));
throw e;
} finally {
compiletimeFunctionNanos.merge(f.getName(), System.nanoTime() - t0, Long::sum);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,12 +535,14 @@ public JassProg transformProgToJass() {
}

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

// Re-run to avoid #883
optimizer.removeGarbage();
imProg.flatten(imTranslator);
if (garbageChanged) {
optimizer.removeGarbage();
imProg.flatten(imTranslator);
}

printDebugImProg("./test-output/im " + stage++ + "_afterremoveGarbage1.im");
timeTaker.endPhase();
Expand All @@ -561,7 +563,7 @@ public JassProg transformProgToJass() {
// translate flattened intermediate lang to jass:

beginPhase(14, "translate to jass");
getImTranslator().calculateCallRelationsAndUsedVariables();
getImTranslator().calculateCallRelationsAndReadVariables();
ImToJassTranslator translator =
new ImToJassTranslator(getImProg(), getImTranslator().getCalledFunctions(), getImTranslator().getMainFunc(), getImTranslator().getConfFunc());
prog = translator.translate();
Expand Down Expand Up @@ -952,12 +954,14 @@ public LuaCompilationUnit transformProgToLua() {

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

optimizer.removeGarbage();
boolean garbageChanged = optimizer.removeGarbage();
imProg.flatten(imTranslator);

// Re-run to avoid #883
optimizer.removeGarbage();
imProg.flatten(imTranslator);
if (garbageChanged) {
optimizer.removeGarbage();
imProg.flatten(imTranslator);
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static ILconst getDefaultValue(String type) {

public ILconst executeFunction(String name, ILconst... arguments) {
if (trace) {
WLogger.trace(name + "( " + Utils.join(arguments, ", ") + ")");
WLogger.trace(() -> name + "( " + Utils.join(arguments, ", ") + ")");
}

ExecutableJassFunction func = searchFunction(name);
Expand Down Expand Up @@ -99,13 +99,13 @@ ILconst executeJassFunction(JassFunction func, ILconst... arguments) {
this.executeStatements(localVarMap, body);
} catch (ReturnException e) {
if (trace) {
WLogger.trace("end function " + func.getName() + " returns " + e.getVal());
WLogger.trace(() -> "end function " + func.getName() + " returns " + e.getVal());
}
return e.getVal();
}

if (trace) {
WLogger.trace("end function " + func.getName());
WLogger.trace(() -> "end function " + func.getName());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public void DestroyForce(IlConstHandle force) {
public void ForForce(IlConstHandle force, ILconstFuncRef funcRef) {
// TODO take force param into account
// For now this simply executes the supplied function.
WLogger.trace("for force call");
interpreter.runFuncRef(funcRef, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,9 @@ public ILconst FirstOfGroup(IlConstHandle group) {
}

public void ForGroup(IlConstHandle group, ILconstFuncRef funcRef) {
WLogger.trace("for group call");
LinkedHashSet<IlConstHandle> groupList = (LinkedHashSet<IlConstHandle>) group.getObj();
groupList.forEach((IlConstHandle u) -> {
enumUnitStack.push(u);
WLogger.trace("for group call itr: " + funcRef.getFuncName());
interpreter.runFuncRef(funcRef, null);
enumUnitStack.pop();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private void refreshCacheAsync() {
}
})
.exceptionally(e -> {
WLogger.trace("Background config refresh failed (this is normal if client is busy): " + e.getMessage());
WLogger.trace(() -> "Background config refresh failed (this is normal if client is busy): " + e.getMessage());
return null;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,30 @@ private List<CompilationUnit> getJassdocCUs(Path jassdoc, WurstGui gui) {

@Override
public Changes removeCompilationUnit(WFile resource) {
parseErrors.remove(resource);
WurstModel model2 = model;
if (model2 == null) {
return Changes.empty();
}

syncCompilationUnitContent(resource, "");
List<CompilationUnit> toRemove = new ArrayList<>();
for (CompilationUnit compilationUnit : model2) {
if (wFile(compilationUnit).equals(resource)) {
toRemove.add(compilationUnit);
if (model2 != null) {
for (CompilationUnit compilationUnit : model2) {
if (wFile(compilationUnit).equals(resource)) {
toRemove.add(compilationUnit);
}
}
model2.removeAll(toRemove);
}
model2.removeAll(toRemove);
return new Changes(toRemove.stream()
.map(this::wFile),

// Always clear state and diagnostics for removed files.
clearFileState(resource);
reportErrors("remove cu ", resource, Collections.emptyList());

toRemove.forEach(compilationunitFile::remove);

return new Changes(
java.util.Collections.singletonList(resource),
toRemove.stream()
.flatMap(cu -> cu.getPackages().stream())
.map(WPackage::getName));
.map(WPackage::getName)
.collect(Collectors.toList())
);
}

@Override
Expand Down Expand Up @@ -366,7 +371,6 @@ private WurstCompilerJassImpl getCompiler(WurstGui gui) {
}

private void updateModel(CompilationUnit cu, WurstGui gui) {
WLogger.trace("update model with " + cu.getCuInfo().getFile());
parseErrors.put(wFile(cu), new ArrayList<>(gui.getErrorsAndWarnings()));

WurstModel model2 = model;
Expand Down Expand Up @@ -526,15 +530,20 @@ private CompilationUnit replaceCompilationUnit(WFile filename, String contents,
if (fileHashcodes.containsKey(filename)) {
int oldHash = fileHashcodes.get(filename);
if (oldHash == contents.hashCode()) {
// no change
WLogger.trace("CU " + filename + " was unchanged.");
return getCompilationUnit(filename);
CompilationUnit existing = getCompilationUnit(filename);
if (existing != null) {
// no change
WLogger.trace(() -> "CU " + filename + " was unchanged.");
return existing;
}
// Stale hash cache after remove/move; CU is gone, so reparse.
WLogger.info("CU hash unchanged but model entry missing for " + filename + ", reparsing.");
} else {
WLogger.info("CU changed. oldHash = " + oldHash + " == " + contents.hashCode());
}
}

WLogger.trace("replace CU " + filename);
WLogger.trace(() -> "replace CU " + filename);
WurstGui gui = new WurstGuiLogger();
WurstCompilerJassImpl c = getCompiler(gui);
CompilationUnit cu = c.parse(filename.toString(), new StringReader(contents));
Expand All @@ -557,6 +566,12 @@ private CompilationUnit replaceCompilationUnit(WFile filename, String contents,
return cu;
}

private void clearFileState(WFile file) {
parseErrors.remove(file);
otherErrors.remove(file);
fileHashcodes.remove(file);
}

@Override
public CompilationUnit getCompilationUnit(WFile filename) {
List<CompilationUnit> matches = getCompilationUnits(Collections.singletonList(filename));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,28 @@ public Object execute(ModelManager modelManager) throws IOException {
// first we copy in same location to ensure validity
File buildDir = getBuildDir();
String fileName = projectConfig.getBuildMapData().getFileName();
Optional<File> targetMap = Optional.of(
new File(buildDir, fileName.isEmpty() ? projectConfig.getProjectName() + ".w3x" : fileName + ".w3x"));
CompilationResult result = compileScript(modelManager, gui, targetMap, projectConfig, buildDir, true);

injectMapData(gui, targetMap, result);

Files.copy(getCachedMapFile().toPath(), targetMap.get().toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
File targetMapFile = new File(buildDir, fileName.isEmpty() ? projectConfig.getProjectName() + ".w3x" : fileName + ".w3x");
targetMapFile = ensureWritableTargetFile(
targetMapFile,
"Build Map",
"The output map file is in use and cannot be replaced.\nClose Warcraft III and click Retry, choose Rename to use a temporary file name, or Cancel.",
"Build canceled because output map target is in use."
);
CompilationResult result = compileScript(modelManager, gui, Optional.of(targetMapFile), projectConfig, buildDir, true);

injectMapData(gui, Optional.of(targetMapFile), result);

targetMapFile = ensureWritableTargetFile(
targetMapFile,
"Build Map",
"The output map file is still in use and cannot be replaced.\nClick Retry, choose Rename to use a temporary file name, or Cancel.",
"Build canceled because output map target is in use."
);
Files.copy(getCachedMapFile().toPath(), targetMapFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);

gui.sendProgress("Finalizing map");

try (MpqEditor mpq = MpqEditorFactory.getEditor(targetMap)) {
try (MpqEditor mpq = MpqEditorFactory.getEditor(Optional.of(targetMapFile))) {
if (mpq != null) {
mpq.closeWithCompression();
}
Expand Down
Loading
Loading