From f6c6087fe316c7b576b7ddd8fa4622f0ed22e232 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Wed, 2 Sep 2015 12:52:39 +0200 Subject: [PATCH] Adding escaping to kotlin.daemon.jvm.options property processing to allow passing e.g. debugging agent params; adding kotlin.daemon.startup.timeout property to control startup timeout; more logging; some minor cleanup and fixes --- build.xml | 4 +-- .../rmi/kotlinr/KotlinCompilerClient.kt | 21 ++++++++++---- .../org/jetbrains/kotlin/rmi/DaemonParams.kt | 12 +++++--- .../kotlin/rmi/service/CompileDaemon.kt | 26 +++++++++++++++-- .../kotlin/rmi/service/CompileServiceImpl.kt | 28 ------------------- 5 files changed, 49 insertions(+), 42 deletions(-) diff --git a/build.xml b/build.xml index 34ade247460..ae08d9d5fb4 100644 --- a/build.xml +++ b/build.xml @@ -202,8 +202,8 @@ - - + + diff --git a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt index cdcfe11ff62..0d0335eb4a6 100644 --- a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt +++ b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt @@ -42,7 +42,7 @@ public class KotlinCompilerClient { companion object { - val DAEMON_STARTUP_TIMEOUT_MS = 10000L + val DAEMON_DEFAULT_STARTUP_TIMEOUT_MS = 10000L private fun connectToService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream): CompileService? { @@ -103,16 +103,25 @@ public class KotlinCompilerClient { try { // trying to wait for process if (daemonOptions.startEcho.isNotEmpty()) { + val daemonStartupTimeout = System.getProperty(COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY)?.let { + try { + it.toLong() + } + catch (e: Exception) { + errStream.println("[daemon client] unable to interpret $COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY property ('$it'); using default timeout $DAEMON_DEFAULT_STARTUP_TIMEOUT_MS ms") + null + } + } ?: DAEMON_DEFAULT_STARTUP_TIMEOUT_MS errStream.println("[daemon client] waiting for daemon to respond") - val succeeded = isEchoRead.tryAcquire(DAEMON_STARTUP_TIMEOUT_MS, TimeUnit.MILLISECONDS) + val succeeded = isEchoRead.tryAcquire(daemonStartupTimeout, TimeUnit.MILLISECONDS) if (!daemon.isAlive()) throw Exception("Daemon terminated unexpectedly") if (!succeeded) - throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MS ms") + throw Exception("Unable to get response from daemon in $daemonStartupTimeout ms") } else // without startEcho defined waiting for max timeout - Thread.sleep(DAEMON_STARTUP_TIMEOUT_MS) + Thread.sleep(DAEMON_DEFAULT_STARTUP_TIMEOUT_MS) } finally { // assuming that all important output is already done, the rest should be routed to the log by the daemon itself @@ -207,7 +216,7 @@ public class KotlinCompilerClient { if (!clientOptions.stop) { if (compilerId.compilerClasspath.none()) { // attempt to find compiler to use - println("compiler wasn't explicitly specified, attempt to find appropriate jar") + System.err.println("compiler wasn't explicitly specified, attempt to find appropriate jar") System.getProperty("java.class.path") ?.split(File.pathSeparator) ?.map { File(it).parent } @@ -231,7 +240,7 @@ public class KotlinCompilerClient { val daemon = connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, System.out, autostart = !clientOptions.stop, checkId = !clientOptions.stop) if (daemon == null) { - if (clientOptions.stop) println("No daemon found to shut down") + if (clientOptions.stop) System.err.println("No daemon found to shut down") else throw Exception("Unable to connect to daemon") } else when { diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt index eacf096d24b..acb9d55b515 100644 --- a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt @@ -31,6 +31,7 @@ public val COMPILE_DAEMON_DEFAULT_PORT: Int = 17031 public val COMPILE_DAEMON_ENABLED_PROPERTY: String ="kotlin.daemon.enabled" public val COMPILE_DAEMON_JVM_OPTIONS_PROPERTY: String ="kotlin.daemon.jvm.options" public val COMPILE_DAEMON_OPTIONS_PROPERTY: String ="kotlin.daemon.options" +public val COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY: String ="kotlin.daemon.startup.timeout" public val COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX: String ="--daemon-" public val COMPILE_DAEMON_TIMEOUT_INFINITE_S: Int = 0 public val COMPILE_DAEMON_MEMORY_THRESHOLD_INFINITE: Long = 0L @@ -66,11 +67,11 @@ class StringPropMapper>(dest: C, fromString = fromString, toString = toString, skipIf = skipIf, mergeDelimiter = mergeDelimiter) class BoolPropMapper>(dest: C, prop: P, names: List = listOf()) - : PropMapper(dest = dest, prop = prop, names = if (names.any()) names else listOf(prop.name), + : PropMapper(dest = dest, prop = prop, names = if (names.any()) names else listOf(prop.name), fromString = { true }, toString = { null }, skipIf = { !prop.get(dest) }) -class RestPropMapper>>(dest: C, prop: P) - : PropMapper, P>(dest = dest, prop = prop, toString = { null }, fromString = { arrayListOf() }) +class RestPropMapper>>(dest: C, prop: P) + : PropMapper, P>(dest = dest, prop = prop, toString = { null }, fromString = { arrayListOf() }) { override fun toArgs(prefix: String): List = prop.get(dest).map { prefix + it } override fun apply(s: String) = add(s) @@ -248,7 +249,10 @@ public fun configureDaemonLaunchingOptions(opts: DaemonJVMOptions, inheritMemory ManagementFactory.getRuntimeMXBean().inputArguments.filterExtractProps(opts.mappers, "-") System.getProperty(COMPILE_DAEMON_JVM_OPTIONS_PROPERTY)?.let { - opts.jvmParams.addAll(it.trim('"', '\'').split(",").filterExtractProps(opts.mappers, "-", opts.restMapper)) + opts.jvmParams.addAll( it.trim('"', '\'') + .split("(?) { + log.info("Kotlin compiler daemon version " + (loadVersionFromResource() ?: "")) + log.info("daemon JVM args: " + ManagementFactory.getRuntimeMXBean().inputArguments.joinToString(" ")) + log.info("daemon args: " + args.joinToString(" ")) + val compilerId = CompilerId() val daemonOptions = DaemonOptions() val filteredArgs = args.asIterable().filterExtractProps(compilerId, daemonOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt index 7b40d0efbb9..dcd7c488c14 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt @@ -26,15 +26,11 @@ import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.rmi.* import org.jetbrains.kotlin.rmi.service.RemoteIncrementalCacheClient import org.jetbrains.kotlin.rmi.service.RemoteOutputStreamClient -import java.io.IOException import java.io.PrintStream -import java.lang.management.ManagementFactory -import java.net.URLClassLoader import java.rmi.registry.Registry import java.rmi.server.UnicastRemoteObject import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantReadWriteLock -import java.util.jar.Manifest import java.util.logging.Logger import kotlin.concurrent.read import kotlin.concurrent.write @@ -104,43 +100,19 @@ class CompileServiceImpl>( return (rt.totalMemory() - rt.freeMemory()) } - fun usedMemoryMX(): Long { - System.gc() - val memoryMXBean= ManagementFactory.getMemoryMXBean() - val memHeap=memoryMXBean.getHeapMemoryUsage() - return memHeap.used - } - - // TODO: consider using version as a part of compiler ID or drop this function - private fun loadKotlinVersionFromResource(): String { - (javaClass.classLoader as? URLClassLoader) - ?.findResource("META-INF/MANIFEST.MF") - ?.let { - try { - return Manifest(it.openStream()).mainAttributes.getValue("Implementation-Version") ?: "" - } - catch (e: IOException) {} - } - return "" - } - - fun checkedCompile(args: Array, body: () -> R): R { try { if (args.none()) throw IllegalArgumentException("Error: empty arguments list.") log.info("Starting compilation with args: " + args.joinToString(" ")) - val startMemMX = usedMemoryMX() / 1024 val startMem = usedMemory() / 1024 val startTime = System.nanoTime() val res = body() val endTime = System.nanoTime() val endMem = usedMemory() / 1024 - val endMemMX = usedMemoryMX() / 1024 log.info("Done with result " + res.toString()) log.info("Elapsed time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms") log.info("Used memory: $endMem kb (${"%+d".format(endMem - startMem)} kb)") - log.info("Used memory (from MemoryMXBean): $endMemMX kb (${"%+d".format(endMemMX - startMemMX)} kb)") return res } catch (e: Exception) {