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

This commit is contained in:
Ilya Chernikov
2015-09-02 12:52:39 +02:00
parent 4dbfce605e
commit f6c6087fe3
5 changed files with 49 additions and 42 deletions
+2 -2
View File
@@ -202,8 +202,8 @@
<fileset dir="compiler/builtins-serializer/src"/>
<fileset dir="compiler/cli/src"/>
<fileset dir="compiler/cli/cli-common/src"/>
<include name="compiler/rmi/rmi-server/src"/>
<include name="compiler/rmi/rmi-interface/src"/>
<fileset dir="compiler/rmi/rmi-server/src"/>
<fileset dir="compiler/rmi/rmi-interface/src"/>
<fileset dir="compiler/container/src"/>
<fileset dir="compiler/frontend/src"/>
<fileset dir="compiler/frontend.java/src"/>
@@ -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 {
@@ -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<C, P: KMutableProperty1<C, String>>(dest: C,
fromString = fromString, toString = toString, skipIf = skipIf, mergeDelimiter = mergeDelimiter)
class BoolPropMapper<C, P: KMutableProperty1<C, Boolean>>(dest: C, prop: P, names: List<String> = listOf())
: PropMapper<C, Boolean, P>(dest = dest, prop = prop, names = if (names.any()) names else listOf(prop.name),
: PropMapper<C, Boolean, P>(dest = dest, prop = prop, names = if (names.any()) names else listOf(prop.name),
fromString = { true }, toString = { null }, skipIf = { !prop.get(dest) })
class RestPropMapper<C, P: KMutableProperty1<C, MutableCollection<String>>>(dest: C, prop: P)
: PropMapper<C, MutableCollection<String>, P>(dest = dest, prop = prop, toString = { null }, fromString = { arrayListOf() })
class RestPropMapper<C, P: KMutableProperty1<C, MutableCollection<String>>>(dest: C, prop: P)
: PropMapper<C, MutableCollection<String>, P>(dest = dest, prop = prop, toString = { null }, fromString = { arrayListOf() })
{
override fun toArgs(prefix: String): List<String> = 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("(?<!\\\\),".toRegex())
.map { it.replace("[\\\\](.)".toRegex(), "$1") }
.filterExtractProps(opts.mappers, "-", opts.restMapper))
}
return opts
}
@@ -17,14 +17,20 @@
package org.jetbrains.kotlin.rmi.service
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.rmi.*
import org.jetbrains.kotlin.rmi.COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX
import org.jetbrains.kotlin.rmi.CompilerId
import org.jetbrains.kotlin.rmi.DaemonOptions
import org.jetbrains.kotlin.rmi.filterExtractProps
import org.jetbrains.kotlin.service.CompileServiceImpl
import java.io.IOException
import java.io.OutputStream
import java.io.PrintStream
import java.rmi.RMISecurityManager
import java.lang.management.ManagementFactory
import java.net.URLClassLoader
import java.rmi.registry.LocateRegistry
import java.text.SimpleDateFormat
import java.util.*
import java.util.jar.Manifest
import java.util.logging.LogManager
import java.util.logging.Logger
import kotlin.platform.platformStatic
@@ -89,8 +95,24 @@ public class CompileDaemon {
val log by lazy { Logger.getLogger("daemon") }
private fun loadVersionFromResource(): String? {
(javaClass.classLoader as? URLClassLoader)
?.findResource("META-INF/MANIFEST.MF")
?.let {
try {
return Manifest(it.openStream()).mainAttributes.getValue("Implementation-Version") ?: ""
}
catch (e: IOException) {}
}
return null
}
platformStatic public fun main(args: Array<String>) {
log.info("Kotlin compiler daemon version " + (loadVersionFromResource() ?: "<unknown>"))
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)
@@ -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<Compiler: CLICompiler<*>>(
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<R> checkedCompile(args: Array<out String>, 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) {