Extracting performance measuring utils into mini-framework, implement measurements of the rpc time, adding more measurements to performance logging, minor refactorings
This commit is contained in:
@@ -123,15 +123,13 @@ public object KotlinCompilerClient {
|
||||
}
|
||||
|
||||
|
||||
// TODO: remove jvmStatic after all use sites will switch to kotlin
|
||||
@JvmStatic
|
||||
public fun incrementalCompile(compiler: CompileService, args: Array<out String>, services: CompilationServices, compilerOut: OutputStream, daemonOut: OutputStream): Int {
|
||||
public fun incrementalCompile(compiler: CompileService, args: Array<out String>, services: CompilationServices, compilerOut: OutputStream, daemonOut: OutputStream, profiler: Profiler = DummyProfiler()): Int {
|
||||
|
||||
val compilerOutStreamServer = RemoteOutputStreamServer(compilerOut)
|
||||
val daemonOutStreamServer = RemoteOutputStreamServer(daemonOut)
|
||||
val cacheServers = hashMapOf<TargetId, RemoteIncrementalCacheServer>()
|
||||
try {
|
||||
return compiler.remoteIncrementalCompile(args, makeRemoteServices(services), compilerOutStreamServer, CompileService.OutputFormat.XML, daemonOutStreamServer)
|
||||
return profiler.withMeasure(this) { compiler.remoteIncrementalCompile(args, makeRemoteServices(services), compilerOutStreamServer, CompileService.OutputFormat.XML, daemonOutStreamServer) }
|
||||
}
|
||||
finally {
|
||||
cacheServers.forEach { it.getValue().disconnect() }
|
||||
|
||||
@@ -205,14 +205,18 @@ public data class DaemonOptions(
|
||||
public var runFilesPath: String = COMPILE_DAEMON_DEFAULT_RUN_DIR_PATH,
|
||||
public var autoshutdownMemoryThreshold: Long = COMPILE_DAEMON_MEMORY_THRESHOLD_INFINITE,
|
||||
public var autoshutdownIdleSeconds: Int = COMPILE_DAEMON_DEFAULT_IDLE_TIMEOUT_S,
|
||||
public var clientAliveFlagPath: String? = null
|
||||
public var clientAliveFlagPath: String? = null,
|
||||
public var verbose: Boolean = false,
|
||||
public var reportPerf: Boolean = false
|
||||
) : OptionsGroup {
|
||||
|
||||
override val mappers: List<PropMapper<*, *, *>>
|
||||
get() = listOf(PropMapper(this, DaemonOptions::runFilesPath, fromString = { it.trimQuotes() }),
|
||||
PropMapper(this, DaemonOptions::autoshutdownMemoryThreshold, fromString = { it.toLong() }, skipIf = { it == 0L }, mergeDelimiter = "="),
|
||||
PropMapper(this, DaemonOptions::autoshutdownIdleSeconds, fromString = { it.toInt() }, skipIf = { it == 0 }, mergeDelimiter = "="),
|
||||
NullablePropMapper(this, DaemonOptions::clientAliveFlagPath, fromString = { it }, toString = { "${it?.trimQuotes()}" }, mergeDelimiter = "="))
|
||||
NullablePropMapper(this, DaemonOptions::clientAliveFlagPath, fromString = { it }, toString = { "${it?.trimQuotes()}" }, mergeDelimiter = "="),
|
||||
BoolPropMapper(this, DaemonOptions::verbose),
|
||||
BoolPropMapper(this, DaemonOptions::reportPerf))
|
||||
}
|
||||
|
||||
|
||||
@@ -298,8 +302,6 @@ public fun configureDaemonJVMOptions(opts: DaemonJVMOptions, inheritMemoryLimits
|
||||
.filterExtractProps(opts.mappers, "-", opts.restMapper))
|
||||
}
|
||||
|
||||
System.getProperty(COMPILE_DAEMON_REPORT_PERF_PROPERTY)?.let { opts.jvmParams.add("D" + COMPILE_DAEMON_REPORT_PERF_PROPERTY) }
|
||||
System.getProperty(COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY)?.let { opts.jvmParams.add("D" + COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY) }
|
||||
System.getProperty(COMPILE_DAEMON_LOG_PATH_PROPERTY)?.let { opts.jvmParams.add("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"$it\"" ) }
|
||||
opts.jvmParams.addAll(additionalParams)
|
||||
return opts
|
||||
@@ -324,6 +326,8 @@ public fun configureDaemonOptions(opts: DaemonOptions): DaemonOptions {
|
||||
opts.clientAliveFlagPath = trimmed
|
||||
}
|
||||
}
|
||||
System.getProperty(COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY)?.let { opts.verbose = true }
|
||||
System.getProperty(COMPILE_DAEMON_REPORT_PERF_PROPERTY)?.let { opts.reportPerf = true }
|
||||
return opts
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.rmi
|
||||
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.lang.management.ThreadMXBean
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
interface PerfCounters {
|
||||
val count: Long
|
||||
val time: Long
|
||||
val threadTime: Long
|
||||
val threadUserTime: Long
|
||||
val memory: Long
|
||||
|
||||
fun addMeasurement(time: Long = 0, thread: Long = 0, threadUser: Long = 0, memory: Long = 0)
|
||||
}
|
||||
|
||||
interface Profiler {
|
||||
fun getCounters(): Map<Any?, PerfCounters>
|
||||
fun getTotalCounters(): PerfCounters
|
||||
|
||||
fun<R> withMeasure(obj: Any?, body: () -> R): R
|
||||
}
|
||||
|
||||
|
||||
open class SimplePerfCounters : PerfCounters {
|
||||
private val _count: AtomicLong = AtomicLong(0L)
|
||||
private val _time: AtomicLong = AtomicLong(0L)
|
||||
private val _threadTime: AtomicLong = AtomicLong(0L)
|
||||
private val _threadUserTime: AtomicLong = AtomicLong(0L)
|
||||
private val _memory: AtomicLong = AtomicLong(0L)
|
||||
|
||||
override val count: Long get() = _count.get()
|
||||
override val time: Long get() = _time.get()
|
||||
override val threadTime: Long get() = _threadTime.get()
|
||||
override val threadUserTime: Long get() = _threadUserTime.get()
|
||||
override val memory: Long get() = _memory.get()
|
||||
|
||||
override fun addMeasurement(time: Long, thread: Long, threadUser: Long, memory: Long) {
|
||||
_count.incrementAndGet()
|
||||
_time.addAndGet(time)
|
||||
_threadTime.addAndGet(thread)
|
||||
_threadUserTime.addAndGet(threadUser)
|
||||
_memory.addAndGet(memory)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SimplePerfCountersWithTotal(val totalRef: PerfCounters) : SimplePerfCounters() {
|
||||
override fun addMeasurement(time: Long, thread: Long, threadUser: Long, memory: Long) {
|
||||
super.addMeasurement(time, thread, threadUser, memory)
|
||||
totalRef.addMeasurement(time, thread, threadUser, memory)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun ThreadMXBean.threadCpuTime() = if (isCurrentThreadCpuTimeSupported) currentThreadCpuTime else 0L
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun ThreadMXBean.threadUserTime() = if (isCurrentThreadCpuTimeSupported) currentThreadUserTime else 0L
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun usedMemory(withGC: Boolean): Long {
|
||||
if (withGC) {
|
||||
System.gc()
|
||||
}
|
||||
val rt = Runtime.getRuntime()
|
||||
return (rt.totalMemory() - rt.freeMemory())
|
||||
}
|
||||
|
||||
|
||||
inline fun<R> withMeasureWallTime(perfCounters: PerfCounters, body: () -> R): R {
|
||||
val startTime = System.nanoTime()
|
||||
val res = body()
|
||||
perfCounters.addMeasurement(time = System.nanoTime() - startTime) // TODO: add support for time wrapping
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
inline fun<R> withMeasureWallAndThreadTimes(perfCounters: PerfCounters, threadMXBean: ThreadMXBean, body: () -> R): R {
|
||||
val startTime = System.nanoTime()
|
||||
val startThreadTime = threadMXBean.threadCpuTime()
|
||||
val startThreadUserTime = threadMXBean.threadUserTime()
|
||||
|
||||
val res = body()
|
||||
|
||||
// TODO: add support for time wrapping
|
||||
perfCounters.addMeasurement(time = System.nanoTime() - startTime,
|
||||
thread = threadMXBean.threadCpuTime() - startThreadTime,
|
||||
threadUser = threadMXBean.threadUserTime() - startThreadUserTime)
|
||||
return res
|
||||
}
|
||||
|
||||
inline fun<R> withMeasureWallAndThreadTimes(perfCounters: PerfCounters, body: () -> R): R = withMeasureWallAndThreadTimes(perfCounters, ManagementFactory.getThreadMXBean(), body)
|
||||
|
||||
|
||||
inline fun<R> withMeasureWallAndThreadTimesAndMemory(perfCounters: PerfCounters, withGC: Boolean = false, threadMXBean: ThreadMXBean, body: () -> R): R {
|
||||
val startMem = usedMemory(withGC)
|
||||
val startTime = System.nanoTime()
|
||||
val startThreadTime = threadMXBean.threadCpuTime()
|
||||
val startThreadUserTime = threadMXBean.threadUserTime()
|
||||
|
||||
val res = body()
|
||||
|
||||
// TODO: add support for time wrapping
|
||||
perfCounters.addMeasurement(time = System.nanoTime() - startTime,
|
||||
thread = threadMXBean.threadCpuTime() - startThreadTime,
|
||||
threadUser = threadMXBean.threadUserTime() - startThreadUserTime,
|
||||
memory = usedMemory(withGC) - startMem)
|
||||
return res
|
||||
}
|
||||
|
||||
inline fun<R> withMeasureWallAndThreadTimesAndMemory(perfCounters: PerfCounters, withGC: Boolean, body: () -> R): R =
|
||||
withMeasureWallAndThreadTimesAndMemory(perfCounters, withGC, ManagementFactory.getThreadMXBean(), body)
|
||||
|
||||
|
||||
class DummyProfiler : Profiler {
|
||||
override fun getCounters(): Map<Any?,PerfCounters> = mapOf(null to SimplePerfCounters())
|
||||
override fun getTotalCounters(): PerfCounters = SimplePerfCounters()
|
||||
|
||||
override final inline fun <R> withMeasure(obj: Any?, body: () -> R): R = body()
|
||||
}
|
||||
|
||||
|
||||
abstract class TotalProfiler : Profiler {
|
||||
|
||||
val total = SimplePerfCounters()
|
||||
val threadMXBean = ManagementFactory.getThreadMXBean()
|
||||
|
||||
override fun getCounters(): Map<Any?, PerfCounters> = mapOf()
|
||||
override fun getTotalCounters(): PerfCounters = total
|
||||
}
|
||||
|
||||
|
||||
class WallTotalProfiler : TotalProfiler() {
|
||||
override final inline fun <R> withMeasure(obj: Any?, body: () -> R): R = withMeasureWallTime(total, body)
|
||||
}
|
||||
|
||||
|
||||
class WallAndThreadTotalProfiler : TotalProfiler() {
|
||||
override final inline fun <R> withMeasure(obj: Any?, body: () -> R): R = withMeasureWallAndThreadTimes(total, threadMXBean, body)
|
||||
}
|
||||
|
||||
|
||||
class WallAndThreadAndMemoryTotalProfiler(val withGC: Boolean) : TotalProfiler() {
|
||||
override final inline fun <R> withMeasure(obj: Any?, body: () -> R): R = withMeasureWallAndThreadTimesAndMemory(total, withGC, threadMXBean, body)
|
||||
}
|
||||
|
||||
|
||||
class WallAndThreadByClassProfiler() : TotalProfiler() {
|
||||
|
||||
val counters = hashMapOf<Any?, SimplePerfCountersWithTotal>()
|
||||
|
||||
override fun getCounters(): Map<Any?,PerfCounters> = counters
|
||||
|
||||
override final inline fun <R> withMeasure(obj: Any?, body: () -> R): R =
|
||||
withMeasureWallAndThreadTimes(counters.getOrPut(obj?.javaClass?.name, { SimplePerfCountersWithTotal(total) } ), threadMXBean, body)
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public object CompileDaemon {
|
||||
runFile.deleteOnExit()
|
||||
|
||||
val compiler = K2JVMCompiler()
|
||||
val compilerService = CompileServiceImpl(registry, compiler, compilerId, port)
|
||||
val compilerService = CompileServiceImpl(registry, compiler, compilerId, daemonOptions, port)
|
||||
|
||||
if (daemonOptions.runFilesPath.isNotEmpty())
|
||||
println(daemonOptions.runFilesPath)
|
||||
|
||||
+43
-44
@@ -23,8 +23,6 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompil
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.rmi.*
|
||||
import java.io.PrintStream
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.lang.management.ThreadMXBean
|
||||
import java.rmi.NoSuchObjectException
|
||||
import java.rmi.registry.Registry
|
||||
import java.rmi.server.UnicastRemoteObject
|
||||
@@ -35,12 +33,13 @@ import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
|
||||
fun nowSeconds() = System.nanoTime() / 1000000000L
|
||||
fun nowSeconds() = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime())
|
||||
|
||||
class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
val registry: Registry,
|
||||
val compiler: Compiler,
|
||||
val selfCompilerId: CompilerId,
|
||||
val daemonOptions: DaemonOptions,
|
||||
port: Int
|
||||
) : CompileService, UnicastRemoteObject() {
|
||||
|
||||
@@ -48,7 +47,7 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
|
||||
override fun getCompilerId(): CompilerId = ifAlive { selfCompilerId }
|
||||
|
||||
override fun getUsedMemory(): Long = ifAlive { usedMemory() }
|
||||
override fun getUsedMemory(): Long = ifAlive { usedMemory(withGC = true) }
|
||||
|
||||
override fun shutdown() {
|
||||
ifAliveExclusive {
|
||||
@@ -65,10 +64,10 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
outputFormat: CompileService.OutputFormat,
|
||||
serviceOutputStream: RemoteOutputStream
|
||||
): Int =
|
||||
doCompile(args, compilerOutputStream, serviceOutputStream) { printStream ->
|
||||
doCompile(args, compilerOutputStream, serviceOutputStream) { printStream, profiler ->
|
||||
when (outputFormat) {
|
||||
CompileService.OutputFormat.PLAIN -> compiler.exec(printStream, *args)
|
||||
CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStream, Services.EMPTY, *args)
|
||||
CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStream, createCompileServices(services, profiler), *args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +77,10 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
compilerOutputFormat: CompileService.OutputFormat,
|
||||
serviceOutputStream: RemoteOutputStream
|
||||
): Int =
|
||||
doCompile(args, compilerOutputStream, serviceOutputStream) { printStream ->
|
||||
doCompile(args, compilerOutputStream, serviceOutputStream) { printStream, profiler ->
|
||||
when (compilerOutputFormat) {
|
||||
CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation")
|
||||
CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStream, createCompileServices(services), *args)
|
||||
CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStream, createCompileServices(services, profiler), *args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,57 +122,58 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
alive = true
|
||||
}
|
||||
|
||||
private fun doCompile(args: Array<out String>, compilerMessagesStreamProxy: RemoteOutputStream, serviceOutputStreamProxy: RemoteOutputStream, body: (PrintStream) -> ExitCode): Int =
|
||||
private fun doCompile(args: Array<out String>, compilerMessagesStreamProxy: RemoteOutputStream, serviceOutputStreamProxy: RemoteOutputStream, body: (PrintStream, Profiler) -> ExitCode): Int =
|
||||
ifAlive {
|
||||
val compilerMessagesStream = PrintStream(RemoteOutputStreamClient(compilerMessagesStreamProxy))
|
||||
val serviceOutputStream = PrintStream(RemoteOutputStreamClient(serviceOutputStreamProxy))
|
||||
checkedCompile(args, serviceOutputStream) {
|
||||
val res = body( compilerMessagesStream).code
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val compilerMessagesStream = PrintStream(RemoteOutputStreamClient(compilerMessagesStreamProxy, rpcProfiler))
|
||||
val serviceOutputStream = PrintStream(RemoteOutputStreamClient(serviceOutputStreamProxy, rpcProfiler))
|
||||
checkedCompile(args, serviceOutputStream, rpcProfiler) {
|
||||
val res = body( compilerMessagesStream, rpcProfiler).code
|
||||
_lastUsedSeconds = nowSeconds()
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCompileServices(services: CompileService.RemoteCompilationServices): Services {
|
||||
private fun createCompileServices(services: CompileService.RemoteCompilationServices, rpcProfiler: Profiler): Services {
|
||||
val builder = Services.Builder()
|
||||
services.incrementalCompilationComponents?.let { builder.register(IncrementalCompilationComponents::class.java, RemoteIncrementalCompilationComponentsClient(it)) }
|
||||
services.compilationCanceledStatus?.let { builder.register(CompilationCanceledStatus::class.java, RemoteCompilationCanceledStatusClient(it)) }
|
||||
services.incrementalCompilationComponents?.let { builder.register(IncrementalCompilationComponents::class.java, RemoteIncrementalCompilationComponentsClient(it, rpcProfiler)) }
|
||||
services.compilationCanceledStatus?.let { builder.register(CompilationCanceledStatus::class.java, RemoteCompilationCanceledStatusClient(it, rpcProfiler)) }
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
|
||||
fun usedMemory(): Long {
|
||||
System.gc()
|
||||
val rt = Runtime.getRuntime()
|
||||
return (rt.totalMemory() - rt.freeMemory())
|
||||
}
|
||||
|
||||
fun ThreadMXBean.threadCpuTime() = if (isCurrentThreadCpuTimeSupported) currentThreadCpuTime else 0L
|
||||
fun ThreadMXBean.threadUserTime() = if (isCurrentThreadCpuTimeSupported) currentThreadUserTime else 0L
|
||||
|
||||
fun<R> checkedCompile(args: Array<out String>, serviceOut: PrintStream, body: () -> R): R {
|
||||
fun<R> checkedCompile(args: Array<out String>, serviceOut: PrintStream, rpcProfiler: Profiler, body: () -> R): R {
|
||||
try {
|
||||
if (args.none())
|
||||
throw IllegalArgumentException("Error: empty arguments list.")
|
||||
log.info("Starting compilation with args: " + args.joinToString(" "))
|
||||
val threadMXBean: ThreadMXBean = ManagementFactory.getThreadMXBean()
|
||||
val startMem = usedMemory() / 1024
|
||||
val startTime = System.nanoTime()
|
||||
val startThreadTime = threadMXBean.threadCpuTime()
|
||||
val startThreadUserTime = threadMXBean.threadUserTime()
|
||||
val res = body()
|
||||
val endTime = System.nanoTime()
|
||||
val endThreadTime = threadMXBean.threadCpuTime()
|
||||
val endThreadUserTime = threadMXBean.threadUserTime()
|
||||
val endMem = usedMemory() / 1024
|
||||
|
||||
val profiler = if (daemonOptions.reportPerf) WallAndThreadAndMemoryTotalProfiler(withGC = false) else DummyProfiler()
|
||||
|
||||
val res = profiler.withMeasure(null, body)
|
||||
|
||||
val endMem = if (daemonOptions.reportPerf) usedMemory(withGC = false) else 0L
|
||||
|
||||
log.info("Done with result " + res.toString())
|
||||
val elapsed = TimeUnit.NANOSECONDS.toMillis(endTime - startTime)
|
||||
val elapsedThread = TimeUnit.NANOSECONDS.toMillis(endThreadTime - startThreadTime)
|
||||
val elapsedThreadUser = TimeUnit.NANOSECONDS.toMillis(endThreadUserTime - startThreadUserTime)
|
||||
log.info("Elapsed time: $elapsed ms (thread user: $elapsedThreadUser ms sys: ${elapsedThread - elapsedThreadUser} ms)")
|
||||
log.info("Used memory: $endMem kb (${"%+d".format(endMem - startMem)} kb)")
|
||||
System.getProperty(COMPILE_DAEMON_REPORT_PERF_PROPERTY)?.let {
|
||||
serviceOut.println("PERF: Compile on daemon: $elapsed ms (thread user: $elapsedThreadUser ms sys: ${elapsedThread - elapsedThreadUser} ms); memory: $endMem kb (${"%+d".format(endMem - startMem)} kb)")
|
||||
|
||||
if (daemonOptions.reportPerf) {
|
||||
fun Long.ms() = TimeUnit.NANOSECONDS.toMillis(this)
|
||||
fun Long.kb() = this / 1024
|
||||
val pc = profiler.getTotalCounters()
|
||||
val rpc = rpcProfiler.getTotalCounters()
|
||||
|
||||
"PERF: Compile on daemon: ${pc.time.ms()} ms; thread: user ${pc.threadUserTime.ms()} ms, sys ${(pc.threadTime - pc.threadUserTime).ms()} ms; rpc: ${rpc.count} calls, ${rpc.time.ms()} ms, thread ${rpc.threadTime.ms()} ms; memory: ${endMem.kb()} kb (${"%+d".format(pc.memory.kb())} kb)".let {
|
||||
serviceOut.println(it)
|
||||
log.info(it)
|
||||
}
|
||||
|
||||
// this will only be reported if if appropriate (e.g. ByClass) profiler is used
|
||||
for ((obj, counters) in rpcProfiler.getCounters()) {
|
||||
"PERF: rpc by $obj: ${counters.count} calls, ${counters.time.ms()} ms, thread ${counters.threadTime.ms()} ms".let {
|
||||
serviceOut.println(it)
|
||||
log.info(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -200,5 +200,4 @@ class CompileServiceImpl<Compiler: CLICompiler<*>>(
|
||||
log.info(msg + " = " + res.toString())
|
||||
return res
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -18,10 +18,12 @@ package org.jetbrains.kotlin.rmi.service
|
||||
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.rmi.CompileService
|
||||
import org.jetbrains.kotlin.rmi.DummyProfiler
|
||||
import org.jetbrains.kotlin.rmi.Profiler
|
||||
|
||||
|
||||
class RemoteCompilationCanceledStatusClient(val proxy: CompileService.RemoteCompilationCanceledStatus): CompilationCanceledStatus {
|
||||
class RemoteCompilationCanceledStatusClient(val proxy: CompileService.RemoteCompilationCanceledStatus, val profiler: Profiler = DummyProfiler()): CompilationCanceledStatus {
|
||||
override fun checkCanceled() {
|
||||
proxy.checkCanceled()
|
||||
profiler.withMeasure(this) { proxy.checkCanceled() }
|
||||
}
|
||||
}
|
||||
|
||||
+13
-10
@@ -19,25 +19,28 @@ package org.jetbrains.kotlin.rmi.service
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
import org.jetbrains.kotlin.rmi.CompileService
|
||||
import org.jetbrains.kotlin.rmi.DummyProfiler
|
||||
import org.jetbrains.kotlin.rmi.Profiler
|
||||
|
||||
public class RemoteIncrementalCacheClient(val cache: CompileService.RemoteIncrementalCache): IncrementalCache {
|
||||
override fun getObsoleteMultifileClasses(): Collection<String> = cache.getObsoleteMultifileClassFacades()
|
||||
public class RemoteIncrementalCacheClient(val cache: CompileService.RemoteIncrementalCache, val profiler: Profiler = DummyProfiler()): IncrementalCache {
|
||||
|
||||
override fun getStableMultifileFacadeParts(facadeInternalName: String): Collection<String>? = cache.getMultifileFacadeParts(facadeInternalName)
|
||||
override fun getObsoletePackageParts(): Collection<String> = profiler.withMeasure(this) { cache.getObsoletePackageParts() }
|
||||
|
||||
override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts()
|
||||
override fun getObsoleteMultifileClasses(): Collection<String> = profiler.withMeasure(this) { cache.getObsoleteMultifileClassFacades() }
|
||||
|
||||
override fun getMultifileFacade(partInternalName: String): String? = cache.getMultifileFacade(partInternalName)
|
||||
override fun getStableMultifileFacadeParts(facadeInternalName: String): Collection<String>? = profiler.withMeasure(this) { cache.getMultifileFacadeParts(facadeInternalName) }
|
||||
|
||||
override fun getPackagePartData(fqName: String): JvmPackagePartProto? = cache.getPackagePartData(fqName)
|
||||
override fun getPackagePartData(fqName: String): JvmPackagePartProto? = profiler.withMeasure(this) { cache.getPackagePartData(fqName) }
|
||||
|
||||
override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData()
|
||||
override fun getMultifileFacade(partInternalName: String): String? = profiler.withMeasure(this) { cache.getMultifileFacade(partInternalName) }
|
||||
|
||||
override fun getModuleMappingData(): ByteArray? = profiler.withMeasure(this) { cache.getModuleMappingData() }
|
||||
|
||||
override fun registerInline(fromPath: String, jvmSignature: String, toPath: String) {
|
||||
cache.registerInline(fromPath, jvmSignature, toPath)
|
||||
profiler.withMeasure(this) { cache.registerInline(fromPath, jvmSignature, toPath) }
|
||||
}
|
||||
|
||||
override fun getClassFilePath(internalClassName: String): String = cache.getClassFilePath(internalClassName)
|
||||
override fun getClassFilePath(internalClassName: String): String = profiler.withMeasure(this) { cache.getClassFilePath(internalClassName) }
|
||||
|
||||
override fun close(): Unit = cache.close()
|
||||
override fun close(): Unit = profiler.withMeasure(this) { cache.close() }
|
||||
}
|
||||
|
||||
+5
-3
@@ -21,11 +21,13 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.rmi.CompileService
|
||||
import org.jetbrains.kotlin.rmi.DummyProfiler
|
||||
import org.jetbrains.kotlin.rmi.Profiler
|
||||
|
||||
|
||||
class RemoteIncrementalCompilationComponentsClient(val proxy: CompileService.RemoteIncrementalCompilationComponents) : IncrementalCompilationComponents {
|
||||
class RemoteIncrementalCompilationComponentsClient(val proxy: CompileService.RemoteIncrementalCompilationComponents, val profiler: Profiler = DummyProfiler()) : IncrementalCompilationComponents {
|
||||
|
||||
override fun getIncrementalCache(target: TargetId): IncrementalCache = RemoteIncrementalCacheClient(proxy.getIncrementalCache(target))
|
||||
override fun getIncrementalCache(target: TargetId): IncrementalCache = RemoteIncrementalCacheClient(profiler.withMeasure(this) { proxy.getIncrementalCache(target) }, profiler)
|
||||
|
||||
override fun getLookupTracker(): LookupTracker = RemoteLookupTrackerClient(proxy.getLookupTracker())
|
||||
override fun getLookupTracker(): LookupTracker = RemoteLookupTrackerClient(profiler.withMeasure(this) { proxy.getLookupTracker() }, profiler)
|
||||
}
|
||||
|
||||
+9
-4
@@ -19,14 +19,19 @@ package org.jetbrains.kotlin.rmi.service
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.components.ScopeKind
|
||||
import org.jetbrains.kotlin.rmi.CompileService
|
||||
import org.jetbrains.kotlin.rmi.DummyProfiler
|
||||
import org.jetbrains.kotlin.rmi.Profiler
|
||||
|
||||
|
||||
class RemoteLookupTrackerClient(val proxy: CompileService.RemoteLookupTracker) : LookupTracker {
|
||||
class RemoteLookupTrackerClient(val proxy: CompileService.RemoteLookupTracker, val profiler: Profiler = DummyProfiler()) : LookupTracker {
|
||||
|
||||
private val isDoNothing = proxy.isDoNothing()
|
||||
private val isDoNothing = profiler.withMeasure(this) { proxy.isDoNothing() }
|
||||
|
||||
override fun record(lookupContainingFile: String, lookupLine: Int?, lookupColumn: Int?, scopeFqName: String, scopeKind: ScopeKind, name: String) {
|
||||
if (!isDoNothing)
|
||||
proxy.record(lookupContainingFile, lookupLine, lookupColumn, scopeFqName, scopeKind, name)
|
||||
if (!isDoNothing) {
|
||||
profiler.withMeasure(this) {
|
||||
proxy.record(lookupContainingFile, lookupLine, lookupColumn, scopeFqName, scopeKind, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -16,19 +16,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.rmi.service
|
||||
|
||||
import org.jetbrains.kotlin.rmi.DummyProfiler
|
||||
import org.jetbrains.kotlin.rmi.Profiler
|
||||
import org.jetbrains.kotlin.rmi.RemoteOutputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class RemoteOutputStreamClient(val remote: RemoteOutputStream): OutputStream() {
|
||||
class RemoteOutputStreamClient(val remote: RemoteOutputStream, val profiler: Profiler = DummyProfiler()): OutputStream() {
|
||||
override fun write(data: ByteArray) {
|
||||
remote.write(data, 0, data.size())
|
||||
profiler.withMeasure(this) { remote.write(data, 0, data.size()) }
|
||||
}
|
||||
|
||||
override fun write(data: ByteArray, offset: Int, length: Int) {
|
||||
remote.write(data, offset, length)
|
||||
profiler.withMeasure(this) { remote.write(data, offset, length) }
|
||||
}
|
||||
|
||||
override fun write(byte: Int) {
|
||||
remote.write(byte)
|
||||
profiler.withMeasure(this) { remote.write(byte) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,14 +60,15 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
val flagFile = createTempFile(getTestName(true), ".alive")
|
||||
flagFile.deleteOnExit()
|
||||
val daemonOptions = DaemonOptions(runFilesPath = File(tmpdir, getTestName(true)).absolutePath,
|
||||
clientAliveFlagPath = flagFile.absolutePath)
|
||||
clientAliveFlagPath = flagFile.absolutePath,
|
||||
verbose = true,
|
||||
reportPerf = true)
|
||||
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test.", ".log")
|
||||
|
||||
val daemonJVMOptions = configureDaemonJVMOptions(false,
|
||||
"D$COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY",
|
||||
"D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.absolutePath}\"")
|
||||
var daemonShotDown = false
|
||||
|
||||
@@ -83,9 +84,9 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
logFile.reader().useLines {
|
||||
it.ifNotContainsSequence( LinePattern("Kotlin compiler daemon version"),
|
||||
LinePattern("Starting compilation with args: "),
|
||||
LinePattern("Elapsed time: (\\d+) ms", { it.groups.get(1)?.value?.toLong()?.let { compileTime1 = it }; true } ),
|
||||
LinePattern("Compile on daemon: (\\d+) ms", { it.groups.get(1)?.value?.toLong()?.let { compileTime1 = it }; true } ),
|
||||
LinePattern("Starting compilation with args: "),
|
||||
LinePattern("Elapsed time: (\\d+) ms", { it.groups.get(1)?.value?.toLong()?.let { compileTime2 = it }; true } ),
|
||||
LinePattern("Compile on daemon: (\\d+) ms", { it.groups.get(1)?.value?.toLong()?.let { compileTime2 = it }; true } ),
|
||||
LinePattern("Shutdown complete"))
|
||||
{ unmatchedPattern, lineNo ->
|
||||
TestCase.fail("pattern not found in the input: " + unmatchedPattern.regex +
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.ArrayUtil
|
||||
import com.intellij.util.Function
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
@@ -34,16 +30,13 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil
|
||||
import org.jetbrains.kotlin.config.CompilerSettings
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.rmi.CompilerId
|
||||
import org.jetbrains.kotlin.rmi.configureDaemonJVMOptions
|
||||
import org.jetbrains.kotlin.rmi.configureDaemonOptions
|
||||
import org.jetbrains.kotlin.rmi.isDaemonEnabled
|
||||
import org.jetbrains.kotlin.rmi.*
|
||||
import org.jetbrains.kotlin.rmi.kotlinr.*
|
||||
import org.jetbrains.kotlin.utils.rethrow
|
||||
import java.io.*
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
public object KotlinCompilerRunner {
|
||||
private val K2JVM_COMPILER = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler"
|
||||
@@ -150,14 +143,9 @@ public object KotlinCompilerRunner {
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, DaemonReportingTargets(null, daemonReportMessages), true, true)
|
||||
|
||||
for (msg in daemonReportMessages) {
|
||||
if (msg.category === DaemonReportCategory.EXCEPTION && daemon == null) {
|
||||
messageCollector.report(CompilerMessageSeverity.INFO,
|
||||
"Falling back to compilation without daemon due to error: " + msg.message,
|
||||
CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
else {
|
||||
messageCollector.report(CompilerMessageSeverity.INFO, msg.message, CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
messageCollector.report(CompilerMessageSeverity.INFO,
|
||||
(if (msg.category == DaemonReportCategory.EXCEPTION && daemon == null) "Falling back to compilation without daemon due to error: " else "") + msg.message,
|
||||
CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
|
||||
if (daemon != null) {
|
||||
@@ -168,12 +156,21 @@ public object KotlinCompilerRunner {
|
||||
incrementalCompilationComponents = environment.services.get(IncrementalCompilationComponents::class.java),
|
||||
compilationCanceledStatus = environment.services.get(CompilationCanceledStatus::class.java))
|
||||
|
||||
val res = KotlinCompilerClient.incrementalCompile(daemon, argsArray, services, compilerOut, daemonOut)
|
||||
val profiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
|
||||
val res = KotlinCompilerClient.incrementalCompile(daemon, argsArray, services, compilerOut, daemonOut, profiler)
|
||||
|
||||
processCompilerOutput(messageCollector, collector, compilerOut, res.toString())
|
||||
BufferedReader(StringReader(daemonOut.toString())).forEachLine {
|
||||
messageCollector.report(CompilerMessageSeverity.INFO, it, CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
if (daemonOptions.reportPerf) {
|
||||
fun Long.ms() = TimeUnit.NANOSECONDS.toMillis(this)
|
||||
val counters = profiler.getTotalCounters()
|
||||
messageCollector.report(CompilerMessageSeverity.INFO,
|
||||
"PERF: Daemon call total ${counters.time.ms()} ms, thread ${counters.threadTime.ms()}",
|
||||
CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user