JPS build: allow reuse of forked javac processes; adjusted memory allocation heuristics for forked javac processes

GitOrigin-RevId: aea927dc8cba5f4b39fea9d8ae6c7274cee266af
This commit is contained in:
Eugene Zhuravlev
2020-05-25 21:21:05 +03:00
committed by intellij-monorepo-bot
parent b98a7cf311
commit 0360502b85
4 changed files with 33 additions and 21 deletions
@@ -21,7 +21,8 @@ import org.jetbrains.jps.builders.impl.java.JavacCompilerTool;
import org.jetbrains.jps.builders.java.JavaCompilingTool;
import org.jetbrains.jps.javac.ast.api.JavacFileData;
import javax.tools.*;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.File;
import java.util.*;
import java.util.concurrent.*;
@@ -147,7 +148,7 @@ public class ExternalJavacProcess {
Collection<? extends File> sourcePath,
Map<File, Set<File>> outs,
final CanceledStatus canceledStatus) {
final long compileStart = System.nanoTime();
//final long compileStart = System.nanoTime();
//System.err.println("Compile start; since global start: " + TimeUnit.NANOSECONDS.toMillis(compileStart - myGlobalStart));
final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() {
@Override
@@ -197,11 +198,11 @@ public class ExternalJavacProcess {
e.printStackTrace(System.err);
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure(e.getMessage(), e));
}
finally {
final long compileEnd = System.nanoTime();
System.err.println("Compiled in " + TimeUnit.NANOSECONDS.toMillis(compileEnd - compileStart) + " ms");
//finally {
//final long compileEnd = System.nanoTime();
//System.err.println("Compiled in " + TimeUnit.NANOSECONDS.toMillis(compileEnd - compileStart) + " ms");
//System.err.println("Compiled in " + TimeUnit.NANOSECONDS.toMillis(compileEnd - compileStart) + " ms; since global start: " + TimeUnit.NANOSECONDS.toMillis(compileEnd - myGlobalStart));
}
//}
}
private static JavaCompilingTool getCompilingTool() {
@@ -269,7 +270,12 @@ public class ExternalJavacProcess {
}
finally {
myCanceled.remove(sessionId); // state cleanup
if (!myKeepRunning) {
if (myKeepRunning) {
JavacMain.clearCompilerZipFileCache();
//noinspection CallToSystemGC
System.gc();
}
else {
// in this mode this is only one-time compilation process that should stop after build is complete
ExternalJavacProcess.this.stop();
}
@@ -110,6 +110,6 @@ public class Utils {
if (maxMbytes < 0) {
return -1; // in case of int overflow, return -1 to let VM choose the heap size
}
return Math.max(maxMbytes * 75 / 100, 256); // minimum 256 Mb, maximum 75% from JPS max heap size
return Math.max(maxMbytes / 3, 256); // per-forked process: minimum 256 Mb, maximum 33% from JPS max heap size
}
}
@@ -54,7 +54,8 @@ import org.jetbrains.jps.model.serialization.PathMacroUtil;
import org.jetbrains.jps.service.JpsServiceManager;
import org.jetbrains.jps.service.SharedThreadPool;
import javax.tools.*;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
@@ -499,7 +500,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
final CompilationPaths paths = CompilationPaths.create(platformCp, classPath, upgradeModulePath, modulePath, sourcePath);
rc = server.forkJavac(
forkSdk.getFirst(), Utils.suggestForkedCompilerHeapSize(),
vmOptions, options, paths, files, outs, diagnosticSink, classesConsumer, compilingTool, context.getCancelStatus(), false
vmOptions, options, paths, files, outs, diagnosticSink, classesConsumer, compilingTool, context.getCancelStatus(), true
).get();
}
return rc;
@@ -714,7 +715,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
return server;
}
final int listenPort = findFreePort();
server = new ExternalJavacManager(Utils.getSystemRoot(), SharedThreadPool.getInstance()) {
server = new ExternalJavacManager(Utils.getSystemRoot(), SharedThreadPool.getInstance(), 2 * 60 * 1000L /*keep idle builds for 2 minutes*/) {
@Override
protected ExternalJavacProcessHandler createProcessHandler(UUID processId, @NotNull Process process, @NotNull String commandLine, boolean keepProcessAlive) {
return new ExternalJavacProcessHandler(processId, process, commandLine, keepProcessAlive) {
@@ -42,9 +42,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
/**
* @author Eugene Zhuravlev
*/
public class ExternalJavacManager extends ProcessAdapter {
private static final Logger LOG = Logger.getInstance(ExternalJavacManager.class);
@@ -154,8 +151,8 @@ public class ExternalJavacManager extends ProcessAdapter {
CanceledStatus cancelStatus, final boolean keepProcessAlive) {
try {
final ExternalJavacProcessHandler running = findRunningProcess(processHash(javaHome, vmOptions, compilingTool));
final ExternalJavacProcessHandler processHandler = running != null && running.lock()? running : launchExternalJavacProcess(
javaHome, heapSize, myListenPort, myWorkingDir, vmOptions, compilingTool, running == null && keepProcessAlive
final ExternalJavacProcessHandler processHandler = running != null? running : launchExternalJavacProcess(
javaHome, heapSize, myListenPort, myWorkingDir, vmOptions, compilingTool, keepProcessAlive
);
final Channel channel = lookupChannel(processHandler.getProcessId());
@@ -208,7 +205,9 @@ public class ExternalJavacManager extends ProcessAdapter {
}
private ExternalJavacProcessHandler findRunningProcess(int processHash) {
LOG.debug("findRunningProcess: looking for hash " + processHash);
if (LOG.isDebugEnabled()) {
LOG.debug("findRunningProcess: looking for hash " + processHash);
}
List<ExternalJavacProcessHandler> idleProcesses = null;
try {
synchronized (myRunningProcesses) {
@@ -220,20 +219,26 @@ public class ExternalJavacManager extends ProcessAdapter {
}
final Integer hash = PROCESS_HASH.get(process);
if (hash != null && hash == processHash) {
LOG.debug("findRunningProcess: returning process " + process.getProcessId() + " for hash " + processHash);
if (hash != null && hash == processHash && process.lock()) {
if (LOG.isDebugEnabled()) {
LOG.debug("findRunningProcess: returning process " + process.getProcessId() + " for hash " + processHash);
}
return process;
}
if (process.getIdleTime() > myKeepAliveTimeout) {
if (idleProcesses == null) {
idleProcesses = new ArrayList<>();
}
LOG.debug("findRunningProcess: adding " + process.getProcessId() + " to idle list");
if (LOG.isDebugEnabled()) {
LOG.debug("findRunningProcess: adding " + process.getProcessId() + " to idle list");
}
idleProcesses.add(process);
}
}
}
LOG.debug("findRunningProcess: no running process for " + hashCode() + " is found");
if (LOG.isDebugEnabled()) {
LOG.debug("findRunningProcess: no running process for " + processHash + " is found");
}
return null;
}
finally {