Fixes after review
This commit is contained in:
+45
-41
@@ -24,6 +24,7 @@ import java.io.PrintStream
|
||||
import java.rmi.ConnectException
|
||||
import java.rmi.Remote
|
||||
import java.rmi.registry.LocateRegistry
|
||||
import java.util.concurrent.Semaphore
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
@@ -45,7 +46,6 @@ public class KotlinCompilerClient {
|
||||
companion object {
|
||||
|
||||
val DAEMON_STARTUP_TIMEOUT_MS = 10000L
|
||||
val DAEMON_STARTUP_CHECK_INTERVAL_MS = 100L
|
||||
|
||||
private fun connectToService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream): CompileService? {
|
||||
|
||||
@@ -71,9 +71,13 @@ public class KotlinCompilerClient {
|
||||
|
||||
|
||||
private fun startDaemon(compilerId: CompilerId, daemonLaunchingOptions: DaemonLaunchingOptions, daemonOptions: DaemonOptions, errStream: PrintStream) {
|
||||
val javaExecutable = listOf(System.getProperty("java.home"), "bin", "java").joinToString(File.separator)
|
||||
val javaExecutable = File(System.getProperty("java.home"), "bin").let {
|
||||
val javaw = File(it, "javaw.exe")
|
||||
if (javaw.exists()) javaw
|
||||
else File(it, "java")
|
||||
}
|
||||
// TODO: add some specific environment variables to the cp and may be command line, to allow some specific startup configs
|
||||
val args = listOf(javaExecutable,
|
||||
val args = listOf(javaExecutable.absolutePath,
|
||||
"-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)) +
|
||||
daemonLaunchingOptions.jvmParams +
|
||||
COMPILER_DAEMON_CLASS_FQN +
|
||||
@@ -84,16 +88,18 @@ public class KotlinCompilerClient {
|
||||
// assuming daemon process is deaf and (mostly) silent, so do not handle streams
|
||||
val daemon = processBuilder.start()
|
||||
|
||||
val lock = ReentrantReadWriteLock()
|
||||
var isEchoRead = false
|
||||
var isEchoRead = Semaphore(1)
|
||||
isEchoRead.acquire()
|
||||
|
||||
val stdouThread =
|
||||
val stdoutThread =
|
||||
thread {
|
||||
daemon.getInputStream()
|
||||
.reader()
|
||||
.forEachLine {
|
||||
if (daemonOptions.startEcho.isNotEmpty() && it.contains(daemonOptions.startEcho))
|
||||
lock.write { isEchoRead = true; return@forEachLine }
|
||||
if (daemonOptions.startEcho.isNotEmpty() && it.contains(daemonOptions.startEcho)) {
|
||||
isEchoRead.release()
|
||||
return@forEachLine
|
||||
}
|
||||
errStream.println("[daemon] " + it)
|
||||
}
|
||||
}
|
||||
@@ -101,14 +107,10 @@ public class KotlinCompilerClient {
|
||||
// trying to wait for process
|
||||
if (daemonOptions.startEcho.isNotEmpty()) {
|
||||
errStream.println("[daemon client] waiting for daemon to respond")
|
||||
var waitMillis: Long = DAEMON_STARTUP_TIMEOUT_MS / DAEMON_STARTUP_CHECK_INTERVAL_MS
|
||||
while (waitMillis-- > 0) {
|
||||
Thread.sleep(DAEMON_STARTUP_CHECK_INTERVAL_MS)
|
||||
if (!daemon.isAlive() || lock.read { isEchoRead } == true) break;
|
||||
}
|
||||
val succeeded = isEchoRead.tryAcquire(DAEMON_STARTUP_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
if (!daemon.isAlive())
|
||||
throw Exception("Daemon terminated unexpectedly")
|
||||
if (lock.read { isEchoRead } == false)
|
||||
if (!succeeded)
|
||||
throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MS ms")
|
||||
}
|
||||
else
|
||||
@@ -117,9 +119,9 @@ public class KotlinCompilerClient {
|
||||
}
|
||||
finally {
|
||||
// assuming that all important output is already done, the rest should be routed to the log by the daemon itself
|
||||
if (stdouThread.isAlive)
|
||||
if (stdoutThread.isAlive)
|
||||
// TODO: find better method to stop the thread, but seems it will require asynchronous consuming of the stream
|
||||
lock.write { stdouThread.stop() }
|
||||
stdoutThread.stop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +184,7 @@ public class KotlinCompilerClient {
|
||||
val outStrm = RemoteOutputStreamServer(out)
|
||||
val cacheServers = hashMapOf<String, RemoteIncrementalCacheServer>()
|
||||
try {
|
||||
caches.forEach { cacheServers.put( it.getKey(), RemoteIncrementalCacheServer( it.getValue())) }
|
||||
caches.mapValuesTo(cacheServers, { RemoteIncrementalCacheServer( it.getValue()) })
|
||||
return compiler.remoteIncrementalCompile(args, cacheServers, outStrm, CompileService.OutputFormat.XML)
|
||||
}
|
||||
finally {
|
||||
@@ -242,34 +244,36 @@ public class KotlinCompilerClient {
|
||||
compilerId.updateDigest()
|
||||
}
|
||||
|
||||
connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, System.out, autostart = !clientOptions.stop, checkId = !clientOptions.stop)?.let {
|
||||
when {
|
||||
clientOptions.stop -> {
|
||||
println("Shutdown the daemon")
|
||||
it.shutdown()
|
||||
println("Daemon shut down successfully")
|
||||
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")
|
||||
else throw Exception("Unable to connect to daemon")
|
||||
}
|
||||
else when {
|
||||
clientOptions.stop -> {
|
||||
println("Shutdown the daemon")
|
||||
daemon.shutdown()
|
||||
println("Daemon shut down successfully")
|
||||
}
|
||||
else -> {
|
||||
println("Executing daemon compilation with args: " + filteredArgs.joinToString(" "))
|
||||
val outStrm = RemoteOutputStreamServer(System.out)
|
||||
try {
|
||||
val memBefore = daemon.getUsedMemory() / 1024
|
||||
val startTime = System.nanoTime()
|
||||
val res = daemon.remoteCompile(filteredArgs.toArrayList().toTypedArray(), outStrm, CompileService.OutputFormat.PLAIN)
|
||||
val endTime = System.nanoTime()
|
||||
println("Compilation result code: $res")
|
||||
val memAfter = daemon.getUsedMemory() / 1024
|
||||
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
||||
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
|
||||
}
|
||||
else -> {
|
||||
println("Executing daemon compilation with args: " + filteredArgs.joinToString(" "))
|
||||
val outStrm = RemoteOutputStreamServer(System.out)
|
||||
try {
|
||||
val memBefore = it.getUsedMemory() / 1024
|
||||
val startTime = System.nanoTime()
|
||||
val res = it.remoteCompile(filteredArgs.toArrayList().toTypedArray(), outStrm, CompileService.OutputFormat.PLAIN)
|
||||
val endTime = System.nanoTime()
|
||||
println("Compilation result code: $res")
|
||||
val memAfter = it.getUsedMemory() / 1024
|
||||
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
||||
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
|
||||
}
|
||||
finally {
|
||||
outStrm.disconnect()
|
||||
}
|
||||
finally {
|
||||
outStrm.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
?: if (clientOptions.stop) println("No daemon found to shut down")
|
||||
else throw Exception("Unable to connect to daemon")
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -35,8 +35,8 @@ class RemoteOutputStreamServer(val out: OutputStream) : RemoteOutputStream {
|
||||
out.close()
|
||||
}
|
||||
|
||||
override fun write(data: ByteArray, start: Int, length: Int) {
|
||||
out.write(data, start, length)
|
||||
override fun write(data: ByteArray, offset: Int, length: Int) {
|
||||
out.write(data, offset, length)
|
||||
}
|
||||
|
||||
override fun write(dataByte: Int) {
|
||||
@@ -117,10 +117,11 @@ val COMPILER_ID_DIGEST = "MD5"
|
||||
|
||||
|
||||
fun updateSingleFileDigest(file: File, md: MessageDigest) {
|
||||
val stream = DigestInputStream(file.inputStream(), md)
|
||||
val buf = ByteArray(1024)
|
||||
while (stream.read(buf) == buf.size()) {}
|
||||
stream.close()
|
||||
DigestInputStream(file.inputStream(), md).use {
|
||||
val buf = ByteArray(1024)
|
||||
while (it.read(buf) != -1) { }
|
||||
it.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateForAllClasses(dir: File, md: MessageDigest) {
|
||||
|
||||
@@ -57,10 +57,7 @@ class LogStream(name: String) : OutputStream() {
|
||||
}
|
||||
|
||||
fun flush(data: ByteArray, offset: Int, length: Int) {
|
||||
if (offset == 0 && length == data.size())
|
||||
log.info(lineBuf.toString() + data.toString())
|
||||
else
|
||||
log.info(lineBuf.toString() + data.toString().substring(offset, length))
|
||||
log.info(lineBuf.toString() + data.toString().substring(offset, length))
|
||||
lineBuf.setLength(0)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
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
|
||||
@@ -103,6 +104,13 @@ 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
|
||||
}
|
||||
|
||||
private fun loadKotlinVersionFromResource(): String {
|
||||
(javaClass.classLoader as? URLClassLoader)
|
||||
?.findResource("META-INF/MANIFEST.MF")
|
||||
@@ -121,14 +129,17 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
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) {
|
||||
|
||||
@@ -53,29 +53,17 @@ public class DaemonPolicy(val port: Int) : Policy() {
|
||||
|
||||
|
||||
class DaemonPermissionCollection : PermissionCollection() {
|
||||
var perms = ArrayList<Permission>()
|
||||
val perms = ArrayList<Permission>()
|
||||
|
||||
override fun add(p: Permission) {
|
||||
perms.add(p)
|
||||
}
|
||||
|
||||
override fun implies(p: Permission): Boolean {
|
||||
val i = perms.iterator()
|
||||
while (i.hasNext()) {
|
||||
if (i.next().implies(p)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
override fun implies(p: Permission): Boolean = perms.any { implies(p) }
|
||||
|
||||
override fun elements(): Enumeration<Permission> {
|
||||
return Collections.enumeration(perms)
|
||||
}
|
||||
override fun elements(): Enumeration<Permission> = Collections.enumeration(perms)
|
||||
|
||||
override fun isReadOnly(): Boolean {
|
||||
return false
|
||||
}
|
||||
override fun isReadOnly(): Boolean = false
|
||||
//
|
||||
// companion object {
|
||||
//
|
||||
|
||||
@@ -62,7 +62,8 @@ public class KotlinCompilerRunner {
|
||||
CompilerSettings compilerSettings,
|
||||
MessageCollector messageCollector,
|
||||
CompilerEnvironment environment,
|
||||
Map<String, IncrementalCache> incrementalCaches, File moduleFile,
|
||||
Map<String, IncrementalCache> incrementalCaches,
|
||||
File moduleFile,
|
||||
OutputItemsCollector collector
|
||||
) {
|
||||
K2JVMCompilerArguments arguments = mergeBeans(commonArguments, k2jvmArguments);
|
||||
@@ -78,7 +79,8 @@ public class KotlinCompilerRunner {
|
||||
@NotNull CompilerSettings compilerSettings,
|
||||
@NotNull MessageCollector messageCollector,
|
||||
@NotNull CompilerEnvironment environment,
|
||||
Map<String, IncrementalCache> incrementalCaches, @NotNull OutputItemsCollector collector,
|
||||
Map<String, IncrementalCache> incrementalCaches,
|
||||
@NotNull OutputItemsCollector collector,
|
||||
@NotNull Collection<File> sourceFiles,
|
||||
@NotNull List<String> libraryFiles,
|
||||
@NotNull File outputFile
|
||||
@@ -156,7 +158,6 @@ public class KotlinCompilerRunner {
|
||||
// exec() returns an ExitCode object, class of which is loaded with a different class loader,
|
||||
// so we take it's contents through reflection
|
||||
return getReturnCodeFromObject(rc);
|
||||
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MessageCollectorUtil.reportException(messageCollector, e);
|
||||
|
||||
Reference in New Issue
Block a user