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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user