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/builtins-serializer/src"/>
<fileset dir="compiler/cli/src"/> <fileset dir="compiler/cli/src"/>
<fileset dir="compiler/cli/cli-common/src"/> <fileset dir="compiler/cli/cli-common/src"/>
<include name="compiler/rmi/rmi-server/src"/> <fileset dir="compiler/rmi/rmi-server/src"/>
<include name="compiler/rmi/rmi-interface/src"/> <fileset dir="compiler/rmi/rmi-interface/src"/>
<fileset dir="compiler/container/src"/> <fileset dir="compiler/container/src"/>
<fileset dir="compiler/frontend/src"/> <fileset dir="compiler/frontend/src"/>
<fileset dir="compiler/frontend.java/src"/> <fileset dir="compiler/frontend.java/src"/>
@@ -42,7 +42,7 @@ public class KotlinCompilerClient {
companion object { 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? { private fun connectToService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream): CompileService? {
@@ -103,16 +103,25 @@ public class KotlinCompilerClient {
try { try {
// trying to wait for process // trying to wait for process
if (daemonOptions.startEcho.isNotEmpty()) { 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") 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()) if (!daemon.isAlive())
throw Exception("Daemon terminated unexpectedly") throw Exception("Daemon terminated unexpectedly")
if (!succeeded) 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 else
// without startEcho defined waiting for max timeout // without startEcho defined waiting for max timeout
Thread.sleep(DAEMON_STARTUP_TIMEOUT_MS) Thread.sleep(DAEMON_DEFAULT_STARTUP_TIMEOUT_MS)
} }
finally { finally {
// assuming that all important output is already done, the rest should be routed to the log by the daemon itself // 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 (!clientOptions.stop) {
if (compilerId.compilerClasspath.none()) { if (compilerId.compilerClasspath.none()) {
// attempt to find compiler to use // 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") System.getProperty("java.class.path")
?.split(File.pathSeparator) ?.split(File.pathSeparator)
?.map { File(it).parent } ?.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) val daemon = connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, System.out, autostart = !clientOptions.stop, checkId = !clientOptions.stop)
if (daemon == null) { 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 throw Exception("Unable to connect to daemon")
} }
else when { 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_ENABLED_PROPERTY: String ="kotlin.daemon.enabled"
public val COMPILE_DAEMON_JVM_OPTIONS_PROPERTY: String ="kotlin.daemon.jvm.options" 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_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_CMDLINE_OPTIONS_PREFIX: String ="--daemon-"
public val COMPILE_DAEMON_TIMEOUT_INFINITE_S: Int = 0 public val COMPILE_DAEMON_TIMEOUT_INFINITE_S: Int = 0
public val COMPILE_DAEMON_MEMORY_THRESHOLD_INFINITE: Long = 0L 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) fromString = fromString, toString = toString, skipIf = skipIf, mergeDelimiter = mergeDelimiter)
class BoolPropMapper<C, P: KMutableProperty1<C, Boolean>>(dest: C, prop: P, names: List<String> = listOf()) 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) }) fromString = { true }, toString = { null }, skipIf = { !prop.get(dest) })
class RestPropMapper<C, P: KMutableProperty1<C, MutableCollection<String>>>(dest: C, prop: P) 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() }) : 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 toArgs(prefix: String): List<String> = prop.get(dest).map { prefix + it }
override fun apply(s: String) = add(s) override fun apply(s: String) = add(s)
@@ -248,7 +249,10 @@ public fun configureDaemonLaunchingOptions(opts: DaemonJVMOptions, inheritMemory
ManagementFactory.getRuntimeMXBean().inputArguments.filterExtractProps(opts.mappers, "-") ManagementFactory.getRuntimeMXBean().inputArguments.filterExtractProps(opts.mappers, "-")
System.getProperty(COMPILE_DAEMON_JVM_OPTIONS_PROPERTY)?.let { 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 return opts
} }
@@ -17,14 +17,20 @@
package org.jetbrains.kotlin.rmi.service package org.jetbrains.kotlin.rmi.service
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler 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 org.jetbrains.kotlin.service.CompileServiceImpl
import java.io.IOException
import java.io.OutputStream import java.io.OutputStream
import java.io.PrintStream import java.io.PrintStream
import java.rmi.RMISecurityManager import java.lang.management.ManagementFactory
import java.net.URLClassLoader
import java.rmi.registry.LocateRegistry import java.rmi.registry.LocateRegistry
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.jar.Manifest
import java.util.logging.LogManager import java.util.logging.LogManager
import java.util.logging.Logger import java.util.logging.Logger
import kotlin.platform.platformStatic import kotlin.platform.platformStatic
@@ -89,8 +95,24 @@ public class CompileDaemon {
val log by lazy { Logger.getLogger("daemon") } 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>) { 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 compilerId = CompilerId()
val daemonOptions = DaemonOptions() val daemonOptions = DaemonOptions()
val filteredArgs = args.asIterable().filterExtractProps(compilerId, daemonOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) 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.*
import org.jetbrains.kotlin.rmi.service.RemoteIncrementalCacheClient import org.jetbrains.kotlin.rmi.service.RemoteIncrementalCacheClient
import org.jetbrains.kotlin.rmi.service.RemoteOutputStreamClient import org.jetbrains.kotlin.rmi.service.RemoteOutputStreamClient
import java.io.IOException
import java.io.PrintStream import java.io.PrintStream
import java.lang.management.ManagementFactory
import java.net.URLClassLoader
import java.rmi.registry.Registry import java.rmi.registry.Registry
import java.rmi.server.UnicastRemoteObject import java.rmi.server.UnicastRemoteObject
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.concurrent.locks.ReentrantReadWriteLock
import java.util.jar.Manifest
import java.util.logging.Logger import java.util.logging.Logger
import kotlin.concurrent.read import kotlin.concurrent.read
import kotlin.concurrent.write import kotlin.concurrent.write
@@ -104,43 +100,19 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
return (rt.totalMemory() - rt.freeMemory()) 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 { fun<R> checkedCompile(args: Array<out String>, body: () -> R): R {
try { try {
if (args.none()) if (args.none())
throw IllegalArgumentException("Error: empty arguments list.") throw IllegalArgumentException("Error: empty arguments list.")
log.info("Starting compilation with args: " + args.joinToString(" ")) log.info("Starting compilation with args: " + args.joinToString(" "))
val startMemMX = usedMemoryMX() / 1024
val startMem = usedMemory() / 1024 val startMem = usedMemory() / 1024
val startTime = System.nanoTime() val startTime = System.nanoTime()
val res = body() val res = body()
val endTime = System.nanoTime() val endTime = System.nanoTime()
val endMem = usedMemory() / 1024 val endMem = usedMemory() / 1024
val endMemMX = usedMemoryMX() / 1024
log.info("Done with result " + res.toString()) log.info("Done with result " + res.toString())
log.info("Elapsed time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms") 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: $endMem kb (${"%+d".format(endMem - startMem)} kb)")
log.info("Used memory (from MemoryMXBean): $endMemMX kb (${"%+d".format(endMemMX - startMemMX)} kb)")
return res return res
} }
catch (e: Exception) { catch (e: Exception) {