From 5bde6457b182bbf4aa7e48332fd34b12d1cba07a Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 16 Dec 2019 11:19:59 +0300 Subject: [PATCH] Metrics reporting utils --- .../kotlin/incremental/ICReporter.kt | 17 ++++++ .../kotlin/incremental/ICReporterBase.kt | 6 +++ .../daemon/report/BuildReportICReporter.kt | 53 ++++++++++++++++++- .../daemon/report/CompositeICReporter.kt | 8 +++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt b/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt index 4668f0a83f1..3986e888924 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt @@ -16,4 +16,21 @@ interface ICReporter { fun reportMarkDirtyClass(affectedFiles: Iterable, classFqName: String) fun reportMarkDirtyMember(affectedFiles: Iterable, scope: String, name: String) fun reportMarkDirty(affectedFiles: Iterable, reason: String) + + fun startMeasure(metric: String, startNs: Long) + fun endMeasure(metric: String, endNs: Long) } + +fun ICReporter?.measure(metric: String, fn: () -> T): T { + if (this == null) return fn() + + val start = System.nanoTime() + startMeasure(metric, start) + + try { + return fn() + } finally { + val end = System.nanoTime() + endMeasure(metric, end) + } +} \ No newline at end of file diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ICReporterBase.kt b/build-common/src/org/jetbrains/kotlin/incremental/ICReporterBase.kt index 6449169c62f..dab297b6087 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ICReporterBase.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ICReporterBase.kt @@ -33,4 +33,10 @@ abstract class ICReporterBase(private val pathsBase: File? = null) : ICReporter protected fun File.relativeOrCanonical(): File = pathsBase?.let { relativeToOrNull(it) } ?: canonicalFile + + override fun startMeasure(metric: String, startNs: Long) { + } + + override fun endMeasure(metric: String, endNs: Long) { + } } \ No newline at end of file diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/BuildReportICReporter.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/BuildReportICReporter.kt index e214850647f..9dee507a3f0 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/BuildReportICReporter.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/BuildReportICReporter.kt @@ -10,15 +10,21 @@ import org.jetbrains.kotlin.daemon.common.CompilationResultCategory import org.jetbrains.kotlin.daemon.common.CompilationResults import org.jetbrains.kotlin.incremental.ICReporterBase import java.io.File -import java.util.HashMap +import java.util.* +import kotlin.collections.ArrayList internal class BuildReportICReporter( private val compilationResults: CompilationResults, rootDir: File, - private val isVerbose: Boolean = false + private val isVerbose: Boolean = false, + // todo: default value + // todo: sync BuildReportICReporterAsync + private val reportMetrics: Boolean = true ) : ICReporterBase(rootDir), RemoteICReporter { private val icLogLines = arrayListOf() private val recompilationReason = HashMap() + private val rootMetric = Metric("", 0) + private val metrics = ArrayDeque().apply { add(rootMetric) } override fun report(message: () -> String) { icLogLines.add(message()) @@ -30,6 +36,30 @@ 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, exitCode: ExitCode) { if (!incremental) return @@ -46,6 +76,25 @@ 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 ?: ""} ms") + } + + metric.children.forEach { reportMetric(it, level + 1) } + } +} + +private class Metric(val name: String, val startNs: Long) { + var endNs: Long? = null + val children = ArrayList() } \ No newline at end of file diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/CompositeICReporter.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/CompositeICReporter.kt index 0fb458e9bec..0aeb8c62b83 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/CompositeICReporter.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/CompositeICReporter.kt @@ -34,6 +34,14 @@ internal class CompositeICReporter(private val reporters: Iterable