Add IC metrics reporting

This commit is contained in:
Alexey Tsvetkov
2020-03-02 14:26:49 +03:00
committed by Alexander Likhachev
parent 5bde6457b1
commit 36387d97ad
69 changed files with 1396 additions and 432 deletions
@@ -29,6 +29,7 @@ enum class CompilationResultCategory(val code: Int) {
IC_COMPILE_ITERATION(0),
BUILD_REPORT_LINES(1),
VERBOSE_BUILD_REPORT_LINES(2),
BUILD_METRICS(3)
}
interface CompilationResultsAsync {
@@ -21,6 +21,9 @@ import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.RemoteBuildReporter
import org.jetbrains.kotlin.build.report.RemoteReporter
import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
@@ -286,7 +289,7 @@ abstract class CompileServiceImplBase(
createMessageCollector: (ServicesFacadeT, CompilationOptions) -> MessageCollector,
createReporter: (ServicesFacadeT, CompilationOptions) -> DaemonMessageReporter,
createServices: (JpsServicesFacadeT, EventManager, Profiler) -> Services,
getICReporter: (ServicesFacadeT, CompilationResultsT?, IncrementalCompilationOptions) -> RemoteICReporter
getICReporter: (ServicesFacadeT, CompilationResultsT?, IncrementalCompilationOptions) -> RemoteBuildReporter
) = kotlin.run {
val messageCollector = createMessageCollector(servicesFacade, compilationOptions)
val daemonReporter = createReporter(servicesFacade, compilationOptions)
@@ -514,7 +517,7 @@ abstract class CompileServiceImplBase(
args: K2JSCompilerArguments,
incrementalCompilationOptions: IncrementalCompilationOptions,
compilerMessageCollector: MessageCollector,
reporter: RemoteICReporter
reporter: RemoteBuildReporter
): ExitCode {
val allKotlinFiles = arrayListOf<File>()
val freeArgsWithoutKotlinFiles = arrayListOf<String>()
@@ -554,7 +557,7 @@ abstract class CompileServiceImplBase(
k2jvmArgs: K2JVMCompilerArguments,
incrementalCompilationOptions: IncrementalCompilationOptions,
compilerMessageCollector: MessageCollector,
reporter: RemoteICReporter
reporter: RemoteBuildReporter
): ExitCode {
val allKotlinExtensions = (DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS +
(incrementalCompilationOptions.kotlinScriptExtensions ?: emptyArray())).distinct()
@@ -784,7 +787,7 @@ class CompileServiceImpl(
createMessageCollector = ::CompileServicesFacadeMessageCollector,
createReporter = ::DaemonMessageReporter,
createServices = this::createCompileServices,
getICReporter = { a, b, c -> getICReporter(a, b!!, c)}
getICReporter = { a, b, c -> getBuildReporter(a, b!!, c)}
)
override fun leaseReplSession(
@@ -8,23 +8,19 @@ package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.daemon.common.CompilationResultCategory
import org.jetbrains.kotlin.daemon.common.CompilationResults
import org.jetbrains.kotlin.incremental.ICReporterBase
import org.jetbrains.kotlin.build.report.ICReporterBase
import org.jetbrains.kotlin.build.report.RemoteICReporter
import java.io.File
import java.util.*
import kotlin.collections.ArrayList
// todo: sync BuildReportICReporterAsync
internal class BuildReportICReporter(
private val compilationResults: CompilationResults,
rootDir: File,
private val isVerbose: Boolean = false,
// todo: default value
// todo: sync BuildReportICReporterAsync
private val reportMetrics: Boolean = true
private val isVerbose: Boolean = false
) : ICReporterBase(rootDir), RemoteICReporter {
private val icLogLines = arrayListOf<String>()
private val recompilationReason = HashMap<File, String>()
private val rootMetric = Metric("<root>", 0)
private val metrics = ArrayDeque<Metric>().apply { add(rootMetric) }
override fun report(message: () -> String) {
icLogLines.add(message())
@@ -36,30 +32,6 @@ internal class BuildReportICReporter(
}
}
override fun startMeasure(metric: String, startNs: Long) {
if (!reportMetrics) return
val newMetric = Metric(metric, startNs)
if (metrics.isNotEmpty()) {
metrics.peekLast().children.add(newMetric)
}
metrics.addLast(newMetric)
}
override fun endMeasure(metric: String, endNs: Long) {
if (!reportMetrics) return
while (metrics.isNotEmpty()) {
val lastMetric = metrics.peekLast()
if (lastMetric.name == metric) {
lastMetric.endNs = endNs
break
} else {
metrics.removeLast()
}
}
}
override fun reportCompileIteration(incremental: Boolean, sourceFiles: Collection<File>, exitCode: ExitCode) {
if (!incremental) return
@@ -76,25 +48,6 @@ internal class BuildReportICReporter(
}
override fun flush() {
if (reportMetrics) {
icLogLines.add("Performance metrics:")
reportMetric(rootMetric)
}
compilationResults.add(CompilationResultCategory.BUILD_REPORT_LINES.code, icLogLines)
}
private fun reportMetric(metric: Metric, level: Int = 0) {
if (level > 0) {
val timeMs = metric.endNs?.let { (it - metric.startNs) / 1_000_000L }
icLogLines.add(" ".repeat(level) + "{perf_metric:${metric.name}} ${timeMs ?: "<unknown>"} ms")
}
metric.children.forEach { reportMetric(it, level + 1) }
}
}
private class Metric(val name: String, val startNs: Long) {
var endNs: Long? = null
val children = ArrayList<Metric>()
}
@@ -9,7 +9,8 @@ import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.daemon.common.CompilationResultCategory
import org.jetbrains.kotlin.daemon.common.CompilationResults
import org.jetbrains.kotlin.daemon.common.CompileIterationResult
import org.jetbrains.kotlin.incremental.ICReporterBase
import org.jetbrains.kotlin.build.report.ICReporterBase
import org.jetbrains.kotlin.build.report.RemoteICReporter
import java.io.File
internal class CompileIterationICReporter(
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.build.report.RemoteICReporter
import org.jetbrains.kotlin.cli.common.ExitCode
import java.io.File
internal class CompositeICReporter(private val reporters: Iterable<RemoteICReporter>) :
RemoteICReporter {
internal class CompositeICReporter(private val reporters: Iterable<RemoteICReporter>) : RemoteICReporter {
override fun report(message: () -> String) {
reporters.forEach { it.report(message) }
}
@@ -34,14 +34,6 @@ internal class CompositeICReporter(private val reporters: Iterable<RemoteICRepor
reporters.forEach { it.reportMarkDirty(affectedFiles, reason) }
}
override fun startMeasure(metric: String, startNs: Long) {
reporters.forEach { it.startMeasure(metric, startNs) }
}
override fun endMeasure(metric: String, endNs: Long) {
reporters.forEach { it.endMeasure(metric, endNs) }
}
override fun flush() {
reporters.forEach { it.flush() }
}
@@ -7,7 +7,8 @@ package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.incremental.ICReporterBase
import org.jetbrains.kotlin.build.report.ICReporterBase
import org.jetbrains.kotlin.build.report.RemoteICReporter
import java.io.File
internal class DebugMessagesICReporter(
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.RemoteBuildMetricsReporter
import org.jetbrains.kotlin.daemon.common.CompilationResultCategory
import org.jetbrains.kotlin.daemon.common.CompilationResults
class RemoteBuildMetricsReporterAdapter(
private val delegate: BuildMetricsReporter,
private val shouldReport: Boolean,
private val compilationResults: CompilationResults
) :
BuildMetricsReporter by delegate,
RemoteBuildMetricsReporter {
override fun flush() {
if (shouldReport) {
val metrics = delegate.getMetrics()
compilationResults.add(CompilationResultCategory.BUILD_METRICS.code, metrics)
}
}
}
@@ -1,12 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.incremental.ICReporter
interface RemoteICReporter : ICReporter {
fun flush()
}
@@ -9,8 +9,14 @@ import kotlinx.coroutines.*
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.report.CompositeICReporter
import org.jetbrains.kotlin.daemon.report.RemoteICReporter
import org.jetbrains.kotlin.incremental.ICReporterBase
import org.jetbrains.kotlin.build.report.ICReporterBase
import org.jetbrains.kotlin.build.report.RemoteBuildReporter
import org.jetbrains.kotlin.build.report.RemoteICReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.RemoteBuildMetricsReporter
import org.jetbrains.kotlin.daemon.report.BuildReportICReporter
import org.jetbrains.kotlin.daemon.report.CompileIterationICReporter
import java.io.File
internal class DebugMessagesICReporterAsync(
@@ -106,7 +112,7 @@ fun getICReporterAsync(
servicesFacade: CompilerServicesFacadeBaseAsync,
compilationResults: CompilationResultsAsync?,
compilationOptions: IncrementalCompilationOptions
): RemoteICReporter {
): RemoteBuildReporter {
val root = compilationOptions.modulesInfo.projectRoot
val reporters = ArrayList<RemoteICReporter>()
@@ -120,19 +126,26 @@ fun getICReporterAsync(
.mapNotNullTo(HashSet()) { resultCode ->
CompilationResultCategory.values().getOrNull(resultCode)
}
requestedResults.mapTo(reporters) { requestedResult ->
for (requestedResult in requestedResults) {
when (requestedResult) {
CompilationResultCategory.IC_COMPILE_ITERATION -> {
CompileIterationICReporterAsync(compilationResults)
reporters.add(CompileIterationICReporterAsync(compilationResults))
}
CompilationResultCategory.BUILD_REPORT_LINES -> {
BuildReportICReporterAsync(compilationResults, root)
reporters.add(BuildReportICReporterAsync(compilationResults, root))
}
CompilationResultCategory.VERBOSE_BUILD_REPORT_LINES -> {
BuildReportICReporterAsync(compilationResults, root, isVerbose = true)
reporters.add(BuildReportICReporterAsync(compilationResults, root, isVerbose = true))
}
}
}
return CompositeICReporter(reporters)
val icReporter = CompositeICReporter(reporters)
val metricsReporter = DoNothingRemoteBuildMetricsReporter
return RemoteBuildReporter(icReporter, metricsReporter)
}
object DoNothingRemoteBuildMetricsReporter : BuildMetricsReporter by DoNothingBuildMetricsReporter, RemoteBuildMetricsReporter {
override fun flush() {
}
}
@@ -16,15 +16,18 @@
package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.build.report.RemoteBuildReporter
import org.jetbrains.kotlin.build.report.RemoteICReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl
import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter
import org.jetbrains.kotlin.daemon.common.*
import java.io.File
import java.util.*
fun getICReporter(
fun getBuildReporter(
servicesFacade: CompilerServicesFacadeBase,
compilationResults: CompilationResults,
compilationOptions: IncrementalCompilationOptions
): RemoteICReporter {
): RemoteBuildReporter {
val root = compilationOptions.modulesInfo.projectRoot
val reporters = ArrayList<RemoteICReporter>()
@@ -38,21 +41,25 @@ fun getICReporter(
.mapNotNullTo(HashSet()) { resultCode ->
CompilationResultCategory.values().getOrNull(resultCode)
}
requestedResults.mapTo(reporters) { requestedResult ->
for (requestedResult in requestedResults) {
when (requestedResult) {
CompilationResultCategory.IC_COMPILE_ITERATION -> {
CompileIterationICReporter(compilationResults)
reporters.add(CompileIterationICReporter(compilationResults))
}
CompilationResultCategory.BUILD_REPORT_LINES -> {
BuildReportICReporter(compilationResults, root)
reporters.add(BuildReportICReporter(compilationResults, root))
}
CompilationResultCategory.VERBOSE_BUILD_REPORT_LINES -> {
BuildReportICReporter(compilationResults, root, isVerbose = true)
reporters.add(BuildReportICReporter(compilationResults, root, isVerbose = true))
}
}
}
val areBuildMetricsNeeded = CompilationResultCategory.BUILD_METRICS in requestedResults
val metricsReporter =
(if (areBuildMetricsNeeded) BuildMetricsReporterImpl() else DoNothingBuildMetricsReporter)
.let { RemoteBuildMetricsReporterAdapter(it, areBuildMetricsNeeded, compilationResults) }
return CompositeICReporter(reporters)
return RemoteBuildReporter(CompositeICReporter(reporters), metricsReporter)
}