From e3aeae9548e303da2659790e7982fd74884dfd74 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 25 Jan 2012 12:37:57 +0100 Subject: [PATCH] external javac mode + options for switching it on; compile server defaults altered --- .../compiler/CompileServerManager.java | 24 +++++-- .../org/jetbrains/jps/api/GlobalOptions.java | 13 ++++ .../jps/incremental/java/JavaBuilder.java | 66 +++++++++++++++---- .../src/org/jetbrains/jps/server/Server.java | 4 +- .../src/misc/registry.properties | 10 ++- 5 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index b35cf712a3c6..e6ed3ce7245c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -397,7 +397,7 @@ public class CompileServerManager implements ApplicationComponent{ // commandLine.add((launcherUsed? "-J" : "") + "-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + CharsetToolkit.getDefaultSystemCharset().name()); //} - private Process launchServer(int port) throws ExecutionException { + private Process launchServer(final int port) throws ExecutionException { // validate tools.jar presence final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler(); if (systemCompiler == null) { @@ -406,7 +406,8 @@ public class CompileServerManager implements ApplicationComponent{ final Sdk projectJdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk(); final GeneralCommandLine cmdLine = new GeneralCommandLine(); - cmdLine.setExePath(((JavaSdkType)projectJdk.getSdkType()).getVMExecutablePath(projectJdk)); + final String vmExecutablePath = ((JavaSdkType)projectJdk.getSdkType()).getVMExecutablePath(projectJdk); + cmdLine.setExePath(vmExecutablePath); cmdLine.addParameter("-server"); cmdLine.addParameter("-ea"); cmdLine.addParameter("-XX:MaxPermSize=150m"); @@ -416,12 +417,21 @@ public class CompileServerManager implements ApplicationComponent{ cmdLine.addParameter("-Xmx" + Registry.intValue("compiler.server.heap.size") + "m"); // debugging - cmdLine.addParameter("-XX:+HeapDumpOnOutOfMemoryError"); - //cmdLine.addParameter("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5008"); - - if (Registry.is("compiler.server.use.memory.temp.cache")) { - cmdLine.addParameter("-D"+Server.USE_MEMORY_TEMP_CACHE_OPTION + "=true"); + final int debugPort = Registry.intValue("compiler.server.debug.port"); + if (debugPort > 0) { + cmdLine.addParameter("-XX:+HeapDumpOnOutOfMemoryError"); + cmdLine.addParameter("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + debugPort); } + + if (Registry.is("compiler.server.use.memory.temp.cache")) { + cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION + "=true"); + } + if (Registry.is("compiler.server.use.external.javac.process")) { + cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION + "=true"); + } + cmdLine.addParameter("-D"+ GlobalOptions.HOSTNAME_OPTION + "=" + NetUtils.getLocalHostString()); + cmdLine.addParameter("-D"+ GlobalOptions.VM_EXE_PATH_OPTION + "=" + FileUtil.toSystemIndependentName(vmExecutablePath)); + // javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language final String lang = System.getProperty("user.language"); if (lang != null) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java b/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java new file mode 100644 index 000000000000..ee4e99bd02bc --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java @@ -0,0 +1,13 @@ +package org.jetbrains.jps.api; + +/** + * @author Eugene Zhuravlev + * Date: 1/24/12 + */ +public interface GlobalOptions { + + String USE_MEMORY_TEMP_CACHE_OPTION = "use.memory.temp.cache"; + String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process"; + String HOSTNAME_OPTION = "localhost.name"; + String VM_EXE_PATH_OPTION = "vm.executable.path"; +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 66446954646c..55382b5c6139 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -18,6 +18,7 @@ import org.jetbrains.jps.Module; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.Project; import org.jetbrains.jps.ProjectPaths; +import org.jetbrains.jps.api.GlobalOptions; import org.jetbrains.jps.api.RequestFuture; import org.jetbrains.jps.incremental.*; import org.jetbrains.jps.incremental.messages.BuildMessage; @@ -36,6 +37,7 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.*; import java.net.MalformedURLException; +import java.net.ServerSocket; import java.net.URL; import java.net.URLClassLoader; import java.util.*; @@ -48,9 +50,9 @@ import java.util.concurrent.ExecutorService; */ public class JavaBuilder extends Builder{ public static final String BUILDER_NAME = "java"; - private static final String JAVA_EXTENSION = ".java"; private static final String FORM_EXTENSION = ".form"; + private static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null; private static final FileFilter JAVA_SOURCES_FILTER = new FileFilter() { public boolean accept(File file) { @@ -222,7 +224,6 @@ public class JavaBuilder extends Builder{ final Collection classpath = paths.getCompilationClasspath(chunk, context.isCompilingTests(), false/*context.isProjectRebuild()*/); final Collection platformCp = paths.getPlatformCompilationClasspath(chunk, context.isCompilingTests(), false/*context.isProjectRebuild()*/); final Map> outs = buildOutputDirectoriesMap(context, chunk); - final List options = getCompilationOptions(context, chunk); // begin compilation round final DiagnosticSink diagnosticSink = new DiagnosticSink(context); @@ -234,7 +235,7 @@ public class JavaBuilder extends Builder{ final Set sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context,Collections.emptySet()); final boolean compiledOk = compileJava( - options, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink + files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink ); final Map chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests()); @@ -291,12 +292,12 @@ public class JavaBuilder extends Builder{ return exitCode; } - private boolean compileJava(List options, Collection files, Collection classpath, Collection platformCp, Collection sourcePath, Map> outs, CompileContext context, DiagnosticOutputConsumer diagnosticSink, final OutputFileConsumer outputSink) throws Exception { - final boolean useEmbeddedJavac = true; // todo: make configurable + private boolean compileJava(Collection files, Collection classpath, Collection platformCp, Collection sourcePath, Map> outs, CompileContext context, DiagnosticOutputConsumer diagnosticSink, final OutputFileConsumer outputSink) throws Exception { + final List options = getCompilationOptions(context); final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink); try { final boolean rc; - if (useEmbeddedJavac) { + if (USE_EMBEDDED_JAVAC) { rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus()); } else { @@ -326,13 +327,12 @@ public class JavaBuilder extends Builder{ return descriptor.client; } // start server here - final String javaHome = System.getProperty("java.home"); + final String vmExecPath = System.getProperty(GlobalOptions.VM_EXE_PATH_OPTION, System.getProperty("java.home") + "/bin/java"); + final String hostString = System.getProperty(GlobalOptions.HOSTNAME_OPTION, "localhost"); + final int port = findFreePort(); + final int heapSize = getJavacServerHeapSize(context); - final String hostString = "localhost"; // todo: obtain from IDEA - final int port = 9999; // todo: obtain from IDEA - final int heapSize = 512; // todo: make configurable; either obtain from IDEA or calculate - - final BaseOSProcessHandler processHandler = JavacServerBootstrap.launchJavacServer(javaHome + "/bin/java", heapSize, port, Paths.getSystemRoot()); + final BaseOSProcessHandler processHandler = JavacServerBootstrap.launchJavacServer(vmExecPath, heapSize, port, Paths.getSystemRoot()); final JavacServerClient client = new JavacServerClient(); try { client.connect(hostString, port); @@ -345,6 +345,46 @@ public class JavaBuilder extends Builder{ return client; } + private static int findFreePort() { + try { + final ServerSocket serverSocket = new ServerSocket(0); + try { + return serverSocket.getLocalPort(); + } + finally { + //workaround for linux : calling close() immediately after opening socket + //may result that socket is not closed + synchronized(serverSocket) { + try { + serverSocket.wait(1); + } + catch (Throwable ignored) { + } + } + serverSocket.close(); + } + } + catch (IOException e) { + e.printStackTrace(System.err); + return JavacServer.DEFAULT_SERVER_PORT; + } + } + + private static int getJavacServerHeapSize(CompileContext context) { + int heapSize = 512; + final Project project = context.getProject(); + final Map javacOpts = project.getCompilerConfiguration().getJavacOptions(); + final String hSize = javacOpts.get("MAXIMUM_HEAP_SIZE"); + if (hSize != null) { + try { + heapSize = Integer.parseInt(hSize); + } + catch (NumberFormatException ignored) { + } + } + return heapSize; + } + private static ClassLoader createInstrumentationClassLoader(Collection classpath, Collection platformCp, Map chunkSourcePath, OutputFilesSink outputSink) throws MalformedURLException { final List urls = new ArrayList(); @@ -361,7 +401,7 @@ public class JavaBuilder extends Builder{ return new CompiledClassesLoader(outputSink, urls.toArray(new URL[urls.size()])); } - private static List getCompilationOptions(CompileContext context, ModuleChunk chunk) { + private static List getCompilationOptions(CompileContext context) { final List options = new ArrayList(); options.add("-verbose"); diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java index c1ddd4d58b12..8403017c21ae 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java @@ -10,6 +10,7 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; +import org.jetbrains.jps.api.GlobalOptions; import org.jetbrains.jps.api.JpsRemoteProto; import org.jetbrains.jps.incremental.Paths; @@ -27,7 +28,6 @@ public class Server { private static final int MAX_SIMULTANEOUS_BUILD_SESSIONS = Math.max(2, Runtime.getRuntime().availableProcessors()); public static final String SERVER_SUCCESS_START_MESSAGE = "Compile Server started successfully. Listening on port: "; public static final String SERVER_ERROR_START_MESSAGE = "Error starting Compile Server: "; - public static final String USE_MEMORY_TEMP_CACHE_OPTION = "use.memory.temp.cache"; private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("compile-server"); private final ChannelFactory myChannelFactory; @@ -99,7 +99,7 @@ public class Server { } }); - ServerState.getInstance().setKeepTempCachesInMemory(System.getProperty(USE_MEMORY_TEMP_CACHE_OPTION) != null); + ServerState.getInstance().setKeepTempCachesInMemory(System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null); System.out.println("Server classpath: " + System.getProperty("java.class.path")); System.err.println(SERVER_SUCCESS_START_MESSAGE + port); diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 998e01a5aa92..f27367c763ef 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -125,12 +125,18 @@ compiler.perform.outputs.refresh.on.start.description=Whether to perform initial compiler.max.static.constants.searches=10000 compiler.max.static.constants.searches.description=If the number of changed compile time constants exceeds this value, make will start full-project rebuild -compiler.server.heap.size=600 +compiler.server.heap.size=300 compiler.server.heap.size.description=Heap size value in MB for the compile server process -compiler.server.use.memory.temp.cache=false +compiler.server.use.memory.temp.cache=true compiler.server.use.memory.temp.cache.description=Store temporary data in memory for faster compilation; requires larger server heap size +compiler.server.use.external.javac.process=true +compiler.server.use.external.javac.process.description=Run javac compiler in external process (allows to run compile server with smaller heap size) + +compiler.server.debug.port=-1 +#compiler.server.javac.debug.port=-1 + vcs.show.colored.annotations=true vcs.showConsole=true