Metrics reporting utils

This commit is contained in:
Alexey Tsvetkov
2019-12-16 11:19:59 +03:00
committed by Alexander Likhachev
parent 97a09680d5
commit 5bde6457b1
4 changed files with 82 additions and 2 deletions
@@ -16,4 +16,21 @@ interface ICReporter {
fun reportMarkDirtyClass(affectedFiles: Iterable<File>, classFqName: String)
fun reportMarkDirtyMember(affectedFiles: Iterable<File>, scope: String, name: String)
fun reportMarkDirty(affectedFiles: Iterable<File>, reason: String)
fun startMeasure(metric: String, startNs: Long)
fun endMeasure(metric: String, endNs: Long)
}
fun <T> 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)
}
}
@@ -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) {
}
}
@@ -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<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())
@@ -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<File>, 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 ?: "<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>()
}
@@ -34,6 +34,14 @@ 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() }
}