Fixes after review

This commit is contained in:
Ilya Chernikov
2015-08-20 17:36:26 +02:00
parent 434c30c1bc
commit 61de1c3212
8 changed files with 72 additions and 70 deletions
@@ -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")
}
}
}
@@ -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);