Skip to content

Commit

Permalink
[performance] BatchImageBuilder: write .class files in batches
Browse files Browse the repository at this point in the history
ProcessTaskManager
* use java.util.concurrent for queue
* signal Cancel/Exception/Stop via the queue
* implements AutoCloseable for try-with-resource
* drain as much Elements as possible from the queue

Improves the performance of "Clean all projects"

For example building platform workspace on Windows
AbstractImageBuilder.compile(): 120 sec -> 80 sec

With this change the Compiler is actually waiting for parsing most time
and not for the write to FileSystem anymore.
  • Loading branch information
EcljpseB0T committed Sep 25, 2024
1 parent f0b1b9e commit b330810
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ protected void restoreAptProblems() {

protected void processCompiledUnits(int startingIndex, boolean lastRound) throws java.lang.Error {
CompilationUnitDeclaration unit = null;
ProcessTaskManager processingTask = null;
try {
if (this.useSingleThread) {
// process all units (some more could be injected in the loop by the lookup environment)
Expand Down Expand Up @@ -596,30 +595,37 @@ protected void processCompiledUnits(int startingIndex, boolean lastRound) throws
}));
}
} else {
processingTask = new ProcessTaskManager(this, startingIndex);
int acceptedCount = 0;
// process all units (some more could be injected in the loop by the lookup environment)
// the processTask can continue to process units until its fixed sized cache is full then it must wait
// for this this thread to accept the units as they appear (it only waits if no units are available)
while (true) {
try (ProcessTaskManager processingTask = new ProcessTaskManager(this, startingIndex)){
int acceptedCount = 0;
// process all units (some more could be injected in the loop by the lookup environment)
// the processTask can continue to process units until its fixed sized cache is full then it must wait
// for this this thread to accept the units as they appear (it only waits if no units are available)
this.requestor.startBatch();
try {
unit = processingTask.removeNextUnit(); // waits if no units are in the processed queue
} catch (Error | RuntimeException e) {
unit = processingTask.unitToProcess;
throw e;
Collection<CompilationUnitDeclaration> units;
do {
try {
units = processingTask.removeNextUnits();
} catch (Error | RuntimeException e) {
unit = processingTask.getUnitWithError();
throw e;
}
for (CompilationUnitDeclaration u : units) {
unit = u;
reportWorked(1, acceptedCount++);
this.stats.lineCount += unit.compilationResult.lineSeparatorPositions.length;
this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
if (this.options.verbose)
this.out.println(Messages.bind(Messages.compilation_done,
new String[] { String.valueOf(acceptedCount),
String.valueOf(this.totalUnits), new String(unit.getFileName()) }));
}
// processingTask had no more units available => use the time to flush:
this.requestor.flushBatch();
} while (!units.isEmpty());
} finally {
this.requestor.endBatch();
}
if (unit == null) break;
reportWorked(1, acceptedCount++);
this.stats.lineCount += unit.compilationResult.lineSeparatorPositions.length;
this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
if (this.options.verbose)
this.out.println(
Messages.bind(Messages.compilation_done,
new String[] {
String.valueOf(acceptedCount),
String.valueOf(this.totalUnits),
new String(unit.getFileName())
}));
}
}
if (!lastRound) {
Expand All @@ -640,10 +646,6 @@ protected void processCompiledUnits(int startingIndex, boolean lastRound) throws
this.handleInternalException(e, unit, null);
throw e; // rethrow
} finally {
if (processingTask != null) {
processingTask.shutdown();
processingTask = null;
}
reset();
this.annotationProcessorStartIndex = 0;
this.stats.endTime = System.currentTimeMillis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,26 @@ public interface ICompilerRequestor {
* Accept a compilation result.
*/
public void acceptResult(CompilationResult result);

/**
* Optionally called to start multiple {@link #acceptResult(CompilationResult)}
*/
public default void startBatch() {
//nothing
}

/**
* Optionally called after some {@link #acceptResult(CompilationResult)} to signal a good point in time
*/
public default void flushBatch() {
//nothing
}

/**
* if {@link #startBatch} was called then endBatch is called to finalize possibly multiple
* {@link #acceptResult(CompilationResult)}
*/
public default void endBatch() {
// nothing
}
}
Loading

0 comments on commit b330810

Please sign in to comment.