Skip to content

Commit

Permalink
Metrics reporting utils
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexeyTsvetkov authored and ALikhachev committed Nov 5, 2020
1 parent 97a0968 commit 5bde645
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
17 changes: 17 additions & 0 deletions build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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

Expand All @@ -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>()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
}
Expand Down

0 comments on commit 5bde645

Please sign in to comment.