From 61de1c3212715e67b3c5314edabf6352ec30f78f Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Thu, 20 Aug 2015 17:36:26 +0200 Subject: [PATCH] Fixes after review --- .../rmi/kotlinr}/KotlinCompilerClient.kt | 86 ++++++++++--------- .../kotlinr}/RemoteIncrementalCacheServer.kt | 0 .../rmi/kotlinr}/RemoteOutputStreamServer.kt | 4 +- .../org/jetbrains/kotlin/rmi/DaemonParams.kt | 9 +- .../kotlin/rmi/service/CompileDaemon.kt | 5 +- .../kotlin/rmi/service/CompileServiceImpl.kt | 11 +++ .../kotlin/rmi/service/DaemonPermissions.kt | 20 +---- .../compilerRunner/KotlinCompilerRunner.java | 7 +- 8 files changed, 72 insertions(+), 70 deletions(-) rename compiler/rmi/kotlinr/src/{ => org/jetbrains/kotlin/rmi/kotlinr}/KotlinCompilerClient.kt (80%) rename compiler/rmi/kotlinr/src/{ => org/jetbrains/kotlin/rmi/kotlinr}/RemoteIncrementalCacheServer.kt (100%) rename compiler/rmi/kotlinr/src/{ => org/jetbrains/kotlin/rmi/kotlinr}/RemoteOutputStreamServer.kt (91%) diff --git a/compiler/rmi/kotlinr/src/KotlinCompilerClient.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt similarity index 80% rename from compiler/rmi/kotlinr/src/KotlinCompilerClient.kt rename to compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt index 7808fbdf82d..87fbae84c5f 100644 --- a/compiler/rmi/kotlinr/src/KotlinCompilerClient.kt +++ b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt @@ -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() 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") } } } diff --git a/compiler/rmi/kotlinr/src/RemoteIncrementalCacheServer.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteIncrementalCacheServer.kt similarity index 100% rename from compiler/rmi/kotlinr/src/RemoteIncrementalCacheServer.kt rename to compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteIncrementalCacheServer.kt diff --git a/compiler/rmi/kotlinr/src/RemoteOutputStreamServer.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteOutputStreamServer.kt similarity index 91% rename from compiler/rmi/kotlinr/src/RemoteOutputStreamServer.kt rename to compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteOutputStreamServer.kt index 7a96d0dc927..4b67c389486 100644 --- a/compiler/rmi/kotlinr/src/RemoteOutputStreamServer.kt +++ b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteOutputStreamServer.kt @@ -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) { 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 2c4f0c74f12..87a48243b63 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 @@ -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) { diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt index 54b7927c34a..184699b1df2 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt @@ -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) } 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 2719bc17e7b..fd2b51fbaf2 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 @@ -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>( 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>( 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) { diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/DaemonPermissions.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/DaemonPermissions.kt index 51d88d97837..909e1a6dd1f 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/DaemonPermissions.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/DaemonPermissions.kt @@ -53,29 +53,17 @@ public class DaemonPolicy(val port: Int) : Policy() { class DaemonPermissionCollection : PermissionCollection() { - var perms = ArrayList() + val perms = ArrayList() 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 { - return Collections.enumeration(perms) - } + override fun elements(): Enumeration = Collections.enumeration(perms) - override fun isReadOnly(): Boolean { - return false - } + override fun isReadOnly(): Boolean = false // // companion object { // diff --git a/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java b/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java index 25b917c6b6e..658343708d3 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java +++ b/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java @@ -62,7 +62,8 @@ public class KotlinCompilerRunner { CompilerSettings compilerSettings, MessageCollector messageCollector, CompilerEnvironment environment, - Map incrementalCaches, File moduleFile, + Map 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 incrementalCaches, @NotNull OutputItemsCollector collector, + Map incrementalCaches, + @NotNull OutputItemsCollector collector, @NotNull Collection sourceFiles, @NotNull List 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);