Split Gradle and JPS metrics

#KT-58026 In progress
This commit is contained in:
Nataliya.Valtman
2023-07-19 12:57:06 +02:00
committed by Space Team
parent 524df83265
commit ed2dd4b2ae
55 changed files with 918 additions and 546 deletions
@@ -5,23 +5,22 @@
package org.jetbrains.kotlin.build.report package org.jetbrains.kotlin.build.report
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.RemoteBuildMetricsReporter
open class BuildReporter( open class BuildReporter<B : BuildTime, P : BuildPerformanceMetric>(
protected open val icReporter: ICReporter, protected open val icReporter: ICReporter,
protected open val buildMetricsReporter: BuildMetricsReporter protected open val buildMetricsReporter: BuildMetricsReporter<B, P>,
) : ICReporter by icReporter, BuildMetricsReporter by buildMetricsReporter ) : ICReporter by icReporter, BuildMetricsReporter<B, P> by buildMetricsReporter
class RemoteBuildReporter( class RemoteBuildReporter<B : BuildTime, P : BuildPerformanceMetric>(
override val icReporter: RemoteICReporter, override val icReporter: RemoteICReporter,
override val buildMetricsReporter: RemoteBuildMetricsReporter override val buildMetricsReporter: RemoteBuildMetricsReporter<B, P>,
) : BuildReporter(icReporter, buildMetricsReporter), RemoteReporter { ) : BuildReporter<B, P>(icReporter, buildMetricsReporter), RemoteReporter {
override fun flush() { override fun flush() {
icReporter.flush() icReporter.flush()
buildMetricsReporter.flush() buildMetricsReporter.flush()
} }
} }
object DoNothingBuildReporter : BuildReporter(DoNothingICReporter, DoNothingBuildMetricsReporter) object DoNothingBuildReporter :
BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>(DoNothingICReporter, DoNothingBuildMetricsReporter)
@@ -7,5 +7,4 @@ package org.jetbrains.kotlin.build.report.metrics
import org.jetbrains.kotlin.build.report.RemoteReporter import org.jetbrains.kotlin.build.report.RemoteReporter
interface RemoteBuildMetricsReporter : BuildMetricsReporter, interface RemoteBuildMetricsReporter<B : BuildTime, P : BuildPerformanceMetric> : BuildMetricsReporter<B, P>, RemoteReporter
RemoteReporter
@@ -7,7 +7,8 @@ package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.build.report.BuildReporter import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.debug import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.build.report.metrics.measure import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollector import org.jetbrains.kotlin.compilerRunner.OutputItemsCollector
import org.jetbrains.kotlin.incremental.storage.InMemoryStorageWrapper import org.jetbrains.kotlin.incremental.storage.InMemoryStorageWrapper
@@ -163,7 +164,7 @@ class NonRecoverableCompilationTransaction : CompilationTransaction, BaseCompila
* In the case of an unsuccessful compilation [stashDir] is also removed, but the backed-up files restored to their origin location. * In the case of an unsuccessful compilation [stashDir] is also removed, but the backed-up files restored to their origin location.
*/ */
class RecoverableCompilationTransaction( class RecoverableCompilationTransaction(
private val reporter: BuildReporter, private val reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
private val stashDir: Path, private val stashDir: Path,
) : CompilationTransaction, BaseCompilationTransaction() { ) : CompilationTransaction, BaseCompilationTransaction() {
private val fileRelocationRegistry = hashMapOf<Path, Path?>() private val fileRelocationRegistry = hashMapOf<Path, Path?>()
@@ -175,7 +176,7 @@ class RecoverableCompilationTransaction(
*/ */
override fun registerAddedOrChangedFile(outputFile: Path) { override fun registerAddedOrChangedFile(outputFile: Path) {
if (isFileRelocationIsAlreadyRegisteredFor(outputFile)) return if (isFileRelocationIsAlreadyRegisteredFor(outputFile)) return
reporter.measure(BuildTime.PRECISE_BACKUP_OUTPUT) { reporter.measure(GradleBuildTime.PRECISE_BACKUP_OUTPUT) {
if (Files.exists(outputFile)) { if (Files.exists(outputFile)) {
stashFile(outputFile) stashFile(outputFile)
} else { } else {
@@ -197,7 +198,7 @@ class RecoverableCompilationTransaction(
Files.delete(outputFile) Files.delete(outputFile)
return return
} }
reporter.measure(BuildTime.PRECISE_BACKUP_OUTPUT) { reporter.measure(GradleBuildTime.PRECISE_BACKUP_OUTPUT) {
stashFile(outputFile) stashFile(outputFile)
} }
} }
@@ -219,7 +220,7 @@ class RecoverableCompilationTransaction(
*/ */
private fun revertChanges() { private fun revertChanges() {
reporter.debug { "Reverting changes" } reporter.debug { "Reverting changes" }
reporter.measure(BuildTime.RESTORE_OUTPUT_FROM_BACKUP) { reporter.measure(GradleBuildTime.RESTORE_OUTPUT_FROM_BACKUP) {
for ((originPath, relocatedPath) in fileRelocationRegistry) { for ((originPath, relocatedPath) in fileRelocationRegistry) {
if (relocatedPath == null) { if (relocatedPath == null) {
if (Files.exists(originPath)) { if (Files.exists(originPath)) {
@@ -237,7 +238,7 @@ class RecoverableCompilationTransaction(
*/ */
private fun cleanupStash() { private fun cleanupStash() {
reporter.debug { "Cleaning up stash" } reporter.debug { "Cleaning up stash" }
reporter.measure(BuildTime.CLEAN_BACKUP_STASH) { reporter.measure(GradleBuildTime.CLEAN_BACKUP_STASH) {
Files.walk(stashDir).use { Files.walk(stashDir).use {
it.sorted(Comparator.reverseOrder()) it.sorted(Comparator.reverseOrder())
.forEach(Files::delete) .forEach(Files::delete)
@@ -7,13 +7,13 @@ package org.jetbrains.kotlin.build.report.metrics
import java.io.Serializable import java.io.Serializable
data class BuildMetrics( data class BuildMetrics<B : BuildTime, P : BuildPerformanceMetric>(
val buildTimes: BuildTimes = BuildTimes(), val buildTimes: BuildTimes<B> = BuildTimes(),
val buildPerformanceMetrics: BuildPerformanceMetrics = BuildPerformanceMetrics(), val buildPerformanceMetrics: BuildPerformanceMetrics<P> = BuildPerformanceMetrics(),
val buildAttributes: BuildAttributes = BuildAttributes(), val buildAttributes: BuildAttributes = BuildAttributes(),
val gcMetrics: GcMetrics = GcMetrics() val gcMetrics: GcMetrics = GcMetrics()
) : Serializable { ) : Serializable {
fun addAll(other: BuildMetrics) { fun addAll(other: BuildMetrics<B, P>) {
buildTimes.addAll(other.buildTimes) buildTimes.addAll(other.buildTimes)
buildPerformanceMetrics.addAll(other.buildPerformanceMetrics) buildPerformanceMetrics.addAll(other.buildPerformanceMetrics)
buildAttributes.addAll(other.buildAttributes) buildAttributes.addAll(other.buildAttributes)
@@ -7,14 +7,14 @@ package org.jetbrains.kotlin.build.report.metrics
import java.lang.management.ManagementFactory import java.lang.management.ManagementFactory
interface BuildMetricsReporter { interface BuildMetricsReporter<B : BuildTime, P : BuildPerformanceMetric> {
fun startMeasure(time: BuildTime) fun startMeasure(time: B)
fun endMeasure(time: BuildTime) fun endMeasure(time: B)
fun addTimeMetricNs(time: BuildTime, durationNs: Long) fun addTimeMetricNs(time: B, durationNs: Long)
fun addTimeMetricMs(time: BuildTime, durationMs: Long) = addTimeMetricNs(time, durationMs * 1_000_000) fun addTimeMetricMs(time: B, durationMs: Long) = addTimeMetricNs(time, durationMs * 1_000_000)
fun addMetric(metric: BuildPerformanceMetric, value: Long) fun addMetric(metric: P, value: Long)
fun addTimeMetric(metric: BuildPerformanceMetric) fun addTimeMetric(metric: P)
//Change metric to enum if possible //Change metric to enum if possible
fun addGcMetric(metric: String, value: GcMetric) fun addGcMetric(metric: String, value: GcMetric)
@@ -23,11 +23,11 @@ interface BuildMetricsReporter {
fun addAttribute(attribute: BuildAttribute) fun addAttribute(attribute: BuildAttribute)
fun getMetrics(): BuildMetrics fun getMetrics(): BuildMetrics<B, P>
fun addMetrics(metrics: BuildMetrics) fun addMetrics(metrics: BuildMetrics<B, P>)
} }
inline fun <T> BuildMetricsReporter.measure(time: BuildTime, fn: () -> T): T { inline fun <B : BuildTime, P : BuildPerformanceMetric, T> BuildMetricsReporter<B, P>.measure(time: B, fn: () -> T): T {
startMeasure(time) startMeasure(time)
try { try {
return fn() return fn()
@@ -37,13 +37,13 @@ inline fun <T> BuildMetricsReporter.measure(time: BuildTime, fn: () -> T): T {
} }
fun BuildMetricsReporter.startMeasureGc() { fun <B : BuildTime, P : BuildPerformanceMetric> BuildMetricsReporter<B, P>.startMeasureGc() {
ManagementFactory.getGarbageCollectorMXBeans().forEach { ManagementFactory.getGarbageCollectorMXBeans().forEach {
startGcMetric(it.name, GcMetric(it.collectionTime, it.collectionCount)) startGcMetric(it.name, GcMetric(it.collectionTime, it.collectionCount))
} }
} }
fun BuildMetricsReporter.endMeasureGc() { fun <B : BuildTime, P : BuildPerformanceMetric> BuildMetricsReporter<B, P>.endMeasureGc() {
ManagementFactory.getGarbageCollectorMXBeans().forEach { ManagementFactory.getGarbageCollectorMXBeans().forEach {
endGcMetric(it.name, GcMetric(it.collectionTime, it.collectionCount)) endGcMetric(it.name, GcMetric(it.collectionTime, it.collectionCount))
} }
@@ -6,27 +6,24 @@
package org.jetbrains.kotlin.build.report.metrics package org.jetbrains.kotlin.build.report.metrics
import java.io.Serializable import java.io.Serializable
import java.util.* import kotlin.collections.HashMap
class BuildMetricsReporterImpl : BuildMetricsReporter, Serializable { open class BuildMetricsReporterImpl<B : BuildTime, P : BuildPerformanceMetric> : BuildMetricsReporter<B, P>, Serializable {
private val myBuildTimeStartNs: EnumMap<BuildTime, Long> = private val myBuildTimeStartNs = HashMap<BuildTime, Long>()
EnumMap(
BuildTime::class.java
)
private val myGcPerformance = HashMap<String, GcMetric>() private val myGcPerformance = HashMap<String, GcMetric>()
private val myBuildTimes = BuildTimes() private val myBuildTimes = BuildTimes<B>()
private val myBuildMetrics = BuildPerformanceMetrics() private val myBuildMetrics = BuildPerformanceMetrics<P>()
private val myBuildAttributes = BuildAttributes() private val myBuildAttributes = BuildAttributes()
private val myGcMetrics = GcMetrics() private val myGcMetrics = GcMetrics()
override fun startMeasure(time: BuildTime) { override fun startMeasure(time: B) {
if (time in myBuildTimeStartNs) { if (time in myBuildTimeStartNs) {
error("$time was restarted before it finished") error("$time was restarted before it finished")
} }
myBuildTimeStartNs[time] = System.nanoTime() myBuildTimeStartNs[time] = System.nanoTime()
} }
override fun endMeasure(time: BuildTime) { override fun endMeasure(time: B) {
val startNs = myBuildTimeStartNs.remove(time) ?: error("$time finished before it started") val startNs = myBuildTimeStartNs.remove(time) ?: error("$time finished before it started")
val durationNs = System.nanoTime() - startNs val durationNs = System.nanoTime() - startNs
myBuildTimes.addTimeNs(time, durationNs) myBuildTimes.addTimeNs(time, durationNs)
@@ -45,20 +42,20 @@ class BuildMetricsReporterImpl : BuildMetricsReporter, Serializable {
myGcMetrics.add(name, diff) myGcMetrics.add(name, diff)
} }
override fun addTimeMetricNs(time: BuildTime, durationNs: Long) { override fun addTimeMetricNs(time: B, durationNs: Long) {
myBuildTimes.addTimeNs(time, durationNs) myBuildTimes.addTimeNs(time, durationNs)
} }
override fun addMetric(metric: BuildPerformanceMetric, value: Long) { override fun addMetric(metric: P, value: Long) {
myBuildMetrics.add(metric, value) myBuildMetrics.add(metric, value)
} }
override fun addTimeMetric(metric: BuildPerformanceMetric) { override fun addTimeMetric(metric: P) {
when (metric.type) { when (metric.getType()) {
ValueType.NANOSECONDS -> myBuildMetrics.add(metric, System.nanoTime()) ValueType.NANOSECONDS -> myBuildMetrics.add(metric, System.nanoTime())
ValueType.MILLISECONDS -> myBuildMetrics.add(metric, System.currentTimeMillis()) ValueType.MILLISECONDS -> myBuildMetrics.add(metric, System.currentTimeMillis())
ValueType.TIME -> myBuildMetrics.add(metric, System.currentTimeMillis()) ValueType.TIME -> myBuildMetrics.add(metric, System.currentTimeMillis())
else -> error("Unable to add time metric for '${metric.type}' type") else -> error("Unable to add time metric for '${metric.getType()}' type")
} }
} }
@@ -71,7 +68,7 @@ class BuildMetricsReporterImpl : BuildMetricsReporter, Serializable {
myBuildAttributes.add(attribute) myBuildAttributes.add(attribute)
} }
override fun getMetrics(): BuildMetrics = override fun getMetrics(): BuildMetrics<B, P> =
BuildMetrics( BuildMetrics(
buildTimes = myBuildTimes, buildTimes = myBuildTimes,
buildPerformanceMetrics = myBuildMetrics, buildPerformanceMetrics = myBuildMetrics,
@@ -79,7 +76,7 @@ class BuildMetricsReporterImpl : BuildMetricsReporter, Serializable {
gcMetrics = myGcMetrics gcMetrics = myGcMetrics
) )
override fun addMetrics(metrics: BuildMetrics) { override fun addMetrics(metrics: BuildMetrics<B, P>) {
myBuildAttributes.addAll(metrics.buildAttributes) myBuildAttributes.addAll(metrics.buildAttributes)
myBuildTimes.addAll(metrics.buildTimes) myBuildTimes.addAll(metrics.buildTimes)
myBuildMetrics.addAll(metrics.buildPerformanceMetrics) myBuildMetrics.addAll(metrics.buildPerformanceMetrics)
@@ -7,11 +7,65 @@ package org.jetbrains.kotlin.build.report.metrics
import java.io.Serializable import java.io.Serializable
interface BuildPerformanceMetric : BuildTime, Serializable {
override fun getParent(): BuildPerformanceMetric?
override fun getAllMetrics(): List<BuildPerformanceMetric>
override fun children(): List<BuildPerformanceMetric>?
fun getType(): ValueType
}
enum class JpsBuildPerformanceMetric(
private val parent: JpsBuildPerformanceMetric? = null,
private val readableString: String,
private val type: ValueType,
) : BuildPerformanceMetric {
DAEMON_GC_TIME(readableString = "Time spent in GC", type = ValueType.NANOSECONDS),
DAEMON_GC_COUNT(readableString = "Count of GC", type = ValueType.NUMBER),
COMPILE_ITERATION(parent = null, "Total compiler iteration", type = ValueType.NUMBER),
ANALYZED_LINES_NUMBER(parent = COMPILE_ITERATION, "Number of lines analyzed", type = ValueType.NUMBER),
CODE_GENERATED_LINES_NUMBER(parent = COMPILE_ITERATION, "Number of lines for code generation", type = ValueType.NUMBER),
ANALYSIS_LPS(parent = COMPILE_ITERATION, "Analysis lines per second", type = ValueType.NUMBER),
CODE_GENERATION_LPS(parent = COMPILE_ITERATION, "Code generation lines per second", type = ValueType.NUMBER),
;
override fun getReadableString(): String = readableString
override fun getType(): ValueType = type
override fun getParent(): BuildPerformanceMetric? = parent
override fun children(): List<BuildPerformanceMetric>? {
return children[this]
}
override fun getName(): String = this.name
override fun getAllMetrics(): List<BuildPerformanceMetric> {
return entries
}
companion object {
const val serialVersionUID = 1L
val children by lazy {
entries.filter { it.parent != null }.groupBy { it.parent }
}
}
}
@Suppress("Reformat") @Suppress("Reformat")
enum class BuildPerformanceMetric(val parent: BuildPerformanceMetric? = null, val readableString: String, val type: ValueType) : Serializable { enum class GradleBuildPerformanceMetric(
private val parent: GradleBuildPerformanceMetric? = null,
private val readableString: String,
private val type: ValueType,
) :
BuildPerformanceMetric {
CACHE_DIRECTORY_SIZE(readableString = "Total size of the cache directory", type = ValueType.BYTES), CACHE_DIRECTORY_SIZE(readableString = "Total size of the cache directory", type = ValueType.BYTES),
LOOKUP_SIZE(CACHE_DIRECTORY_SIZE, "Lookups size", type = ValueType.BYTES), LOOKUP_SIZE(CACHE_DIRECTORY_SIZE, "Lookups size", type = ValueType.BYTES),
SNAPSHOT_SIZE(CACHE_DIRECTORY_SIZE, "ABI snapshot size", type = ValueType.BYTES), SNAPSHOT_SIZE(CACHE_DIRECTORY_SIZE, "ABI snapshot size", type = ValueType.BYTES),
BUNDLE_SIZE(readableString = "Total size of the final bundle", type = ValueType.BYTES), BUNDLE_SIZE(readableString = "Total size of the final bundle", type = ValueType.BYTES),
@@ -22,24 +76,64 @@ enum class BuildPerformanceMetric(val parent: BuildPerformanceMetric? = null, va
DAEMON_GC_COUNT(readableString = "Count of GC", type = ValueType.NUMBER), DAEMON_GC_COUNT(readableString = "Count of GC", type = ValueType.NUMBER),
COMPILE_ITERATION(parent = null, "Total compiler iteration", type = ValueType.NUMBER), COMPILE_ITERATION(parent = null, "Total compiler iteration", type = ValueType.NUMBER),
ANALYZED_LINES_NUMBER(parent = COMPILE_ITERATION, "Number of lines analyzed", type = ValueType.NUMBER), ANALYZED_LINES_NUMBER(parent = COMPILE_ITERATION, "Number of lines analyzed", type = ValueType.NUMBER),
CODE_GENERATED_LINES_NUMBER(parent = COMPILE_ITERATION, "Number of lines for code generation", type = ValueType.NUMBER), CODE_GENERATED_LINES_NUMBER(parent = COMPILE_ITERATION, "Number of lines for code generation", type = ValueType.NUMBER),
ANALYSIS_LPS(parent = COMPILE_ITERATION, "Analysis lines per second", type = ValueType.NUMBER), ANALYSIS_LPS(parent = COMPILE_ITERATION, "Analysis lines per second", type = ValueType.NUMBER),
CODE_GENERATION_LPS(parent = COMPILE_ITERATION, "Code generation lines per second", type = ValueType.NUMBER), CODE_GENERATION_LPS(parent = COMPILE_ITERATION, "Code generation lines per second", type = ValueType.NUMBER),
// Metrics for the `kotlin.incremental.useClasspathSnapshot` feature // Metrics for the `kotlin.incremental.useClasspathSnapshot` feature
CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT(parent = null, "Number of times 'ClasspathEntrySnapshotTransform' ran", type = ValueType.NUMBER), CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT(
JAR_CLASSPATH_ENTRY_SIZE(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT, "Size of jar classpath entry", type = ValueType.BYTES), parent = null,
JAR_CLASSPATH_ENTRY_SNAPSHOT_SIZE(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT, "Size of jar classpath entry's snapshot", type = ValueType.BYTES), "Number of times 'ClasspathEntrySnapshotTransform' ran",
DIRECTORY_CLASSPATH_ENTRY_SNAPSHOT_SIZE(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT, "Size of directory classpath entry's snapshot", type = ValueType.BYTES), type = ValueType.NUMBER
),
JAR_CLASSPATH_ENTRY_SIZE(
parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT,
"Size of jar classpath entry",
type = ValueType.BYTES
),
JAR_CLASSPATH_ENTRY_SNAPSHOT_SIZE(
parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT,
"Size of jar classpath entry's snapshot",
type = ValueType.BYTES
),
DIRECTORY_CLASSPATH_ENTRY_SNAPSHOT_SIZE(
parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT,
"Size of directory classpath entry's snapshot",
type = ValueType.BYTES
),
COMPUTE_CLASSPATH_CHANGES_EXECUTION_COUNT(parent = null, "Number of times classpath changes are computed", type = ValueType.NUMBER), COMPUTE_CLASSPATH_CHANGES_EXECUTION_COUNT(parent = null, "Number of times classpath changes are computed", type = ValueType.NUMBER),
SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT(parent = null, "Number of times classpath snapshot is shrunk and saved after compilation", type = ValueType.NUMBER), SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT(
CLASSPATH_ENTRY_COUNT(parent = SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, "Number of classpath entries", type = ValueType.NUMBER), parent = null,
CLASSPATH_SNAPSHOT_SIZE(parent = SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, "Size of classpath snapshot", type = ValueType.BYTES), "Number of times classpath snapshot is shrunk and saved after compilation",
SHRUNK_CLASSPATH_SNAPSHOT_SIZE(parent = SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, "Size of shrunk classpath snapshot", type = ValueType.BYTES), type = ValueType.NUMBER
),
CLASSPATH_ENTRY_COUNT(
parent = SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT,
"Number of classpath entries",
type = ValueType.NUMBER
),
CLASSPATH_SNAPSHOT_SIZE(
parent = SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT,
"Size of classpath snapshot",
type = ValueType.BYTES
),
SHRUNK_CLASSPATH_SNAPSHOT_SIZE(
parent = SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT,
"Size of shrunk classpath snapshot",
type = ValueType.BYTES
),
LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT(parent = null, "Number of times classpath snapshot is loaded", type = ValueType.NUMBER), LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT(parent = null, "Number of times classpath snapshot is loaded", type = ValueType.NUMBER),
LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_HITS(parent = LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, "Number of cache hits when loading classpath entry snapshots", type = ValueType.NUMBER), LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_HITS(
LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_MISSES(parent = LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, "Number of cache misses when loading classpath entry snapshots", type = ValueType.NUMBER), parent = LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT,
"Number of cache hits when loading classpath entry snapshots",
type = ValueType.NUMBER
),
LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_MISSES(
parent = LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT,
"Number of cache misses when loading classpath entry snapshots",
type = ValueType.NUMBER
),
//time metrics //time metrics
START_TASK_ACTION_EXECUTION(readableString = "Start time of task action", type = ValueType.TIME), START_TASK_ACTION_EXECUTION(readableString = "Start time of task action", type = ValueType.TIME),
@@ -50,11 +144,27 @@ enum class BuildPerformanceMetric(val parent: BuildPerformanceMetric? = null, va
START_WORKER_EXECUTION(readableString = "Start time of worker execution", type = ValueType.NANOSECONDS), START_WORKER_EXECUTION(readableString = "Start time of worker execution", type = ValueType.NANOSECONDS),
START_KOTLIN_DAEMON_EXECUTION(readableString = "Start time of kotlin daemon task execution", type = ValueType.NANOSECONDS), START_KOTLIN_DAEMON_EXECUTION(readableString = "Start time of kotlin daemon task execution", type = ValueType.NANOSECONDS),
; ;
override fun getReadableString(): String = readableString
override fun getParent(): BuildPerformanceMetric? = parent
override fun getType(): ValueType = type
override fun getName(): String = this.name
override fun children(): List<BuildPerformanceMetric>? {
return children[this]
}
override fun getAllMetrics(): List<BuildPerformanceMetric> {
return entries
}
companion object { companion object {
const val serialVersionUID = 0L const val serialVersionUID = 1L
val children by lazy { val children by lazy {
values().filter { it.parent != null }.groupBy { it.parent } entries.filter { it.parent != null }.groupBy { it.parent }
} }
} }
} }
@@ -7,24 +7,25 @@ package org.jetbrains.kotlin.build.report.metrics
import java.io.Serializable import java.io.Serializable
import java.util.* import java.util.*
import kotlin.collections.HashMap
class BuildPerformanceMetrics : Serializable { class BuildPerformanceMetrics<T: BuildPerformanceMetric> : Serializable {
companion object { companion object {
const val serialVersionUID = 0L const val serialVersionUID = 0L
} }
private val myBuildMetrics = EnumMap<BuildPerformanceMetric, Long>(BuildPerformanceMetric::class.java) private val myBuildMetrics = HashMap<T, Long>()
fun addAll(other: BuildPerformanceMetrics) { fun addAll(other: BuildPerformanceMetrics<T>) {
for ((bt, timeNs) in other.myBuildMetrics) { for ((bt, timeNs) in other.myBuildMetrics) {
add(bt, timeNs) add(bt, timeNs)
} }
} }
fun add(metric: BuildPerformanceMetric, value: Long = 1) { fun add(metric: T, value: Long = 1) {
myBuildMetrics[metric] = myBuildMetrics.getOrDefault(metric, 0) + value myBuildMetrics[metric] = myBuildMetrics.getOrDefault(metric, 0) + value
} }
fun asMap(): Map<BuildPerformanceMetric, Long> = myBuildMetrics fun asMap(): Map<T, Long> = myBuildMetrics
} }
@@ -7,82 +7,151 @@ package org.jetbrains.kotlin.build.report.metrics
import java.io.Serializable import java.io.Serializable
interface BuildTime : Serializable {
fun getReadableString(): String
fun getParent(): BuildTime?
fun getAllMetrics(): List<BuildTime>
fun children(): List<BuildTime>?
fun getName(): String
}
enum class JpsBuildTime(private val parent: JpsBuildTime? = null, private val readableString: String) : BuildTime {
JPS_ITERATION(readableString = "Jps iteration")
;
override fun getReadableString(): String = readableString
override fun getParent(): BuildTime? = parent
override fun getAllMetrics(): List<BuildTime> {
return entries
}
override fun children(): List<BuildTime>? {
return children[this]
}
override fun getName(): String = this.name
companion object {
const val serialVersionUID = 1L
val children by lazy {
entries.filter { it.parent != null }.groupBy { it.parent }
}
}
}
@Suppress("Reformat") @Suppress("Reformat")
enum class BuildTime(val parent: BuildTime? = null, val readableString: String) : Serializable { enum class GradleBuildTime(private val parent: GradleBuildTime? = null, private val readableString: String) : BuildTime {
GRADLE_TASK(readableString = "Total Gradle task time"), GRADLE_TASK(readableString = "Total Gradle task time"),
GRADLE_TASK_PREPARATION(readableString = "Spent time before task action"), GRADLE_TASK_PREPARATION(readableString = "Spent time before task action"),
GRADLE_TASK_ACTION(readableString = "Task action"), GRADLE_TASK_ACTION(readableString = "Task action"),
OUT_OF_WORKER_TASK_ACTION(GRADLE_TASK_ACTION, "Task action before worker execution"), OUT_OF_WORKER_TASK_ACTION(GRADLE_TASK_ACTION, "Task action before worker execution"),
BACKUP_OUTPUT(OUT_OF_WORKER_TASK_ACTION, "Backup output"), BACKUP_OUTPUT(OUT_OF_WORKER_TASK_ACTION, "Backup output"),
RUN_WORKER_DELAY(readableString = "Start gradle worker"), RUN_WORKER_DELAY(readableString = "Start gradle worker"),
RUN_COMPILATION_IN_WORKER(GRADLE_TASK_ACTION, "Run compilation in Gradle worker"), RUN_COMPILATION_IN_WORKER(GRADLE_TASK_ACTION, "Run compilation in Gradle worker"),
CLEAR_JAR_CACHE(RUN_COMPILATION_IN_WORKER, "Clear jar cache"), CLEAR_JAR_CACHE(RUN_COMPILATION_IN_WORKER, "Clear jar cache"),
CLEAR_OUTPUT(RUN_COMPILATION_IN_WORKER, "Clear output"), CLEAR_OUTPUT(RUN_COMPILATION_IN_WORKER, "Clear output"),
PRECISE_BACKUP_OUTPUT(RUN_COMPILATION_IN_WORKER, "Precise backup output"), PRECISE_BACKUP_OUTPUT(RUN_COMPILATION_IN_WORKER, "Precise backup output"),
RESTORE_OUTPUT_FROM_BACKUP(RUN_COMPILATION_IN_WORKER, "Restore output"), RESTORE_OUTPUT_FROM_BACKUP(RUN_COMPILATION_IN_WORKER, "Restore output"),
CLEAN_BACKUP_STASH(RUN_COMPILATION_IN_WORKER, "Cleaning up the backup stash"), CLEAN_BACKUP_STASH(RUN_COMPILATION_IN_WORKER, "Cleaning up the backup stash"),
CONNECT_TO_DAEMON(RUN_COMPILATION_IN_WORKER, "Connect to Kotlin daemon"), CONNECT_TO_DAEMON(RUN_COMPILATION_IN_WORKER, "Connect to Kotlin daemon"),
CALCULATE_OUTPUT_SIZE(RUN_COMPILATION_IN_WORKER, "Calculate output size"), CALCULATE_OUTPUT_SIZE(RUN_COMPILATION_IN_WORKER, "Calculate output size"),
RUN_COMPILATION(RUN_COMPILATION_IN_WORKER, "Run compilation"), RUN_COMPILATION(RUN_COMPILATION_IN_WORKER, "Run compilation"),
NON_INCREMENTAL_COMPILATION_IN_PROCESS(RUN_COMPILATION, "Non incremental inprocess compilation"), NON_INCREMENTAL_COMPILATION_IN_PROCESS(RUN_COMPILATION, "Non incremental inprocess compilation"),
NON_INCREMENTAL_COMPILATION_OUT_OF_PROCESS(RUN_COMPILATION, "Non incremental out of process compilation"), NON_INCREMENTAL_COMPILATION_OUT_OF_PROCESS(RUN_COMPILATION, "Non incremental out of process compilation"),
NON_INCREMENTAL_COMPILATION_DAEMON(RUN_COMPILATION, "Non incremental compilation in daemon"), NON_INCREMENTAL_COMPILATION_DAEMON(RUN_COMPILATION, "Non incremental compilation in daemon"),
INCREMENTAL_COMPILATION_DAEMON(RUN_COMPILATION, "Incremental compilation in daemon"), INCREMENTAL_COMPILATION_DAEMON(RUN_COMPILATION, "Incremental compilation in daemon"),
STORE_BUILD_INFO(INCREMENTAL_COMPILATION_DAEMON, "Store build info"), STORE_BUILD_INFO(INCREMENTAL_COMPILATION_DAEMON, "Store build info"),
JAR_SNAPSHOT(INCREMENTAL_COMPILATION_DAEMON, "ABI JAR Snapshot support"), JAR_SNAPSHOT(INCREMENTAL_COMPILATION_DAEMON, "ABI JAR Snapshot support"),
SET_UP_ABI_SNAPSHOTS(JAR_SNAPSHOT, "Set up ABI snapshot"), SET_UP_ABI_SNAPSHOTS(JAR_SNAPSHOT, "Set up ABI snapshot"),
IC_ANALYZE_JAR_FILES(JAR_SNAPSHOT, "Analyze jar files"), IC_ANALYZE_JAR_FILES(JAR_SNAPSHOT, "Analyze jar files"),
IC_CALCULATE_INITIAL_DIRTY_SET(INCREMENTAL_COMPILATION_DAEMON, "Calculate initial dirty sources set"), //TODO IC_CALCULATE_INITIAL_DIRTY_SET(INCREMENTAL_COMPILATION_DAEMON, "Calculate initial dirty sources set"), //TODO
COMPUTE_CLASSPATH_CHANGES(IC_CALCULATE_INITIAL_DIRTY_SET, "Compute classpath changes"), COMPUTE_CLASSPATH_CHANGES(IC_CALCULATE_INITIAL_DIRTY_SET, "Compute classpath changes"),
LOAD_CURRENT_CLASSPATH_SNAPSHOT(COMPUTE_CLASSPATH_CHANGES, "Load current classpath snapshot"), LOAD_CURRENT_CLASSPATH_SNAPSHOT(COMPUTE_CLASSPATH_CHANGES, "Load current classpath snapshot"),
REMOVE_DUPLICATE_CLASSES(LOAD_CURRENT_CLASSPATH_SNAPSHOT, "Remove duplicate classes"), REMOVE_DUPLICATE_CLASSES(LOAD_CURRENT_CLASSPATH_SNAPSHOT, "Remove duplicate classes"),
SHRINK_CURRENT_CLASSPATH_SNAPSHOT(COMPUTE_CLASSPATH_CHANGES, "Shrink current classpath snapshot"), SHRINK_CURRENT_CLASSPATH_SNAPSHOT(COMPUTE_CLASSPATH_CHANGES, "Shrink current classpath snapshot"),
GET_LOOKUP_SYMBOLS(SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Get lookup symbols"), GET_LOOKUP_SYMBOLS(SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Get lookup symbols"),
FIND_REFERENCED_CLASSES(SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Find referenced classes"), FIND_REFERENCED_CLASSES(SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Find referenced classes"),
FIND_TRANSITIVELY_REFERENCED_CLASSES(SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Find transitively referenced classes"), FIND_TRANSITIVELY_REFERENCED_CLASSES(SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Find transitively referenced classes"),
LOAD_SHRUNK_PREVIOUS_CLASSPATH_SNAPSHOT(COMPUTE_CLASSPATH_CHANGES, "Load shrunk previous classpath snapshot"), LOAD_SHRUNK_PREVIOUS_CLASSPATH_SNAPSHOT(COMPUTE_CLASSPATH_CHANGES, "Load shrunk previous classpath snapshot"),
COMPUTE_CHANGED_AND_IMPACTED_SET(COMPUTE_CLASSPATH_CHANGES, "Compute changed and impacted set"), COMPUTE_CHANGED_AND_IMPACTED_SET(COMPUTE_CLASSPATH_CHANGES, "Compute changed and impacted set"),
COMPUTE_CLASS_CHANGES(COMPUTE_CHANGED_AND_IMPACTED_SET, "Compute class changes"), COMPUTE_CLASS_CHANGES(COMPUTE_CHANGED_AND_IMPACTED_SET, "Compute class changes"),
COMPUTE_KOTLIN_CLASS_CHANGES(COMPUTE_CLASS_CHANGES, "Compute Kotlin class changes"), COMPUTE_KOTLIN_CLASS_CHANGES(COMPUTE_CLASS_CHANGES, "Compute Kotlin class changes"),
COMPUTE_JAVA_CLASS_CHANGES(COMPUTE_CLASS_CHANGES, "Compute Java class changes"), COMPUTE_JAVA_CLASS_CHANGES(COMPUTE_CLASS_CHANGES, "Compute Java class changes"),
COMPUTE_IMPACTED_SET(COMPUTE_CHANGED_AND_IMPACTED_SET, "Compute impacted set"), COMPUTE_IMPACTED_SET(COMPUTE_CHANGED_AND_IMPACTED_SET, "Compute impacted set"),
IC_ANALYZE_CHANGES_IN_DEPENDENCIES(IC_CALCULATE_INITIAL_DIRTY_SET, "Analyze dependency changes"), IC_ANALYZE_CHANGES_IN_DEPENDENCIES(IC_CALCULATE_INITIAL_DIRTY_SET, "Analyze dependency changes"),
IC_FIND_HISTORY_FILES(IC_ANALYZE_CHANGES_IN_DEPENDENCIES, "Find history files"), IC_FIND_HISTORY_FILES(IC_ANALYZE_CHANGES_IN_DEPENDENCIES, "Find history files"),
IC_ANALYZE_HISTORY_FILES(IC_ANALYZE_CHANGES_IN_DEPENDENCIES, "Analyze history files"), IC_ANALYZE_HISTORY_FILES(IC_ANALYZE_CHANGES_IN_DEPENDENCIES, "Analyze history files"),
IC_ANALYZE_CHANGES_IN_JAVA_SOURCES(IC_CALCULATE_INITIAL_DIRTY_SET, "Analyze Java file changes"), IC_ANALYZE_CHANGES_IN_JAVA_SOURCES(IC_CALCULATE_INITIAL_DIRTY_SET, "Analyze Java file changes"),
IC_ANALYZE_CHANGES_IN_ANDROID_LAYOUTS(IC_CALCULATE_INITIAL_DIRTY_SET, "Analyze Android layouts"), IC_ANALYZE_CHANGES_IN_ANDROID_LAYOUTS(IC_CALCULATE_INITIAL_DIRTY_SET, "Analyze Android layouts"),
IC_DETECT_REMOVED_CLASSES(IC_CALCULATE_INITIAL_DIRTY_SET, "Detect removed classes"), IC_DETECT_REMOVED_CLASSES(IC_CALCULATE_INITIAL_DIRTY_SET, "Detect removed classes"),
CLEAR_OUTPUT_ON_REBUILD(INCREMENTAL_COMPILATION_DAEMON, "Clear outputs on rebuild"), CLEAR_OUTPUT_ON_REBUILD(INCREMENTAL_COMPILATION_DAEMON, "Clear outputs on rebuild"),
IC_UPDATE_CACHES(INCREMENTAL_COMPILATION_DAEMON, "Update caches"), IC_UPDATE_CACHES(INCREMENTAL_COMPILATION_DAEMON, "Update caches"),
COMPILATION_ROUND(INCREMENTAL_COMPILATION_DAEMON, "Sources compilation round"), COMPILATION_ROUND(INCREMENTAL_COMPILATION_DAEMON, "Sources compilation round"),
COMPILER_PERFORMANCE(COMPILATION_ROUND, readableString = "Compiler time"), COMPILER_PERFORMANCE(COMPILATION_ROUND, readableString = "Compiler time"),
COMPILER_INITIALIZATION(COMPILER_PERFORMANCE, "Compiler initialization time"), COMPILER_INITIALIZATION(COMPILER_PERFORMANCE, "Compiler initialization time"),
CODE_ANALYSIS(COMPILER_PERFORMANCE, "Compiler code analysis"), CODE_ANALYSIS(COMPILER_PERFORMANCE, "Compiler code analysis"),
CODE_GENERATION(COMPILER_PERFORMANCE, "Compiler code generation"), CODE_GENERATION(COMPILER_PERFORMANCE, "Compiler code generation"),
IC_WRITE_HISTORY_FILE(INCREMENTAL_COMPILATION_DAEMON, "Write history file"), IC_WRITE_HISTORY_FILE(INCREMENTAL_COMPILATION_DAEMON, "Write history file"),
SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION(INCREMENTAL_COMPILATION_DAEMON, "Shrink and save current classpath snapshot after compilation"), SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION(
INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT(SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION, "Shrink current classpath snapshot incrementally"), INCREMENTAL_COMPILATION_DAEMON,
INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT(INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"), "Shrink and save current classpath snapshot after compilation"
INCREMENTAL_LOAD_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT_AGAINST_PREVIOUS_LOOKUPS(INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load shrunk current classpath snapshot against previous lookups"), ),
NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT(SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION, "Shrink current classpath snapshot non-incrementally"), INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT(
NON_INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT(NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"), SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION,
SAVE_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT(SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION, "Save shrunk current classpath snapshot"), "Shrink current classpath snapshot incrementally"
),
INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT(INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"),
INCREMENTAL_LOAD_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT_AGAINST_PREVIOUS_LOOKUPS(
INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT,
"Load shrunk current classpath snapshot against previous lookups"
),
NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT(
SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION,
"Shrink current classpath snapshot non-incrementally"
),
NON_INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT(NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"),
SAVE_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT(
SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION,
"Save shrunk current classpath snapshot"
),
TASK_FINISH_LISTENER_NOTIFICATION(readableString = "Task finish event notification"), TASK_FINISH_LISTENER_NOTIFICATION(readableString = "Task finish event notification"),
CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM(readableString = "Classpath entry snapshot transform"), CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM(readableString = "Classpath entry snapshot transform"),
LOAD_CLASSES_PATHS_ONLY(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM, "Load classes (paths only)"), LOAD_CLASSES_PATHS_ONLY(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM, "Load classes (paths only)"),
SNAPSHOT_CLASSES(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM, "Snapshot classes"), SNAPSHOT_CLASSES(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM, "Snapshot classes"),
LOAD_CONTENTS_OF_CLASSES(parent = SNAPSHOT_CLASSES, "Load contents of classes"), LOAD_CONTENTS_OF_CLASSES(parent = SNAPSHOT_CLASSES, "Load contents of classes"),
SNAPSHOT_KOTLIN_CLASSES(parent = SNAPSHOT_CLASSES, "Snapshot Kotlin classes"), SNAPSHOT_KOTLIN_CLASSES(parent = SNAPSHOT_CLASSES, "Snapshot Kotlin classes"),
SNAPSHOT_JAVA_CLASSES(parent = SNAPSHOT_CLASSES, "Snapshot Java classes"), SNAPSHOT_JAVA_CLASSES(parent = SNAPSHOT_CLASSES, "Snapshot Java classes"),
SAVE_CLASSPATH_ENTRY_SNAPSHOT(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM, "Save classpath entry snapshot"), SAVE_CLASSPATH_ENTRY_SNAPSHOT(parent = CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM, "Save classpath entry snapshot"),
; ;
override fun getReadableString(): String = readableString
override fun getParent(): BuildTime? = parent
override fun children(): List<BuildTime>? {
return children[this]
}
override fun getAllMetrics(): List<BuildTime> {
return entries
}
override fun getName(): String = this.name
companion object { companion object {
const val serialVersionUID = 0L const val serialVersionUID = 1L
val children by lazy { val children by lazy {
values().filter { it.parent != null }.groupBy { it.parent } entries.filter { it.parent != null }.groupBy { it.parent }
} }
} }
} }
@@ -7,23 +7,24 @@ package org.jetbrains.kotlin.build.report.metrics
import java.io.Serializable import java.io.Serializable
import java.util.* import java.util.*
import kotlin.collections.HashMap
class BuildTimes : Serializable { class BuildTimes<T : BuildTime> : Serializable {
private val buildTimesNs = EnumMap<BuildTime, Long>(BuildTime::class.java) private val buildTimesNs = HashMap<T, Long>()
fun addAll(other: BuildTimes) { fun addAll(other: BuildTimes<T>) {
for ((buildTime, timeNs) in other.buildTimesNs) { for ((buildTime, timeNs) in other.buildTimesNs) {
addTimeNs(buildTime, timeNs) addTimeNs(buildTime, timeNs)
} }
} }
fun addTimeNs(buildTime: BuildTime, timeNs: Long) { fun addTimeNs(buildTime: T, timeNs: Long) {
buildTimesNs[buildTime] = buildTimesNs.getOrDefault(buildTime, 0) + timeNs buildTimesNs[buildTime] = buildTimesNs.getOrDefault(buildTime, 0) + timeNs
} }
fun addTimeMs(buildTime: BuildTime, timeMs: Long) = addTimeNs(buildTime, timeMs * 1_000_000) fun addTimeMs(buildTime: T, timeMs: Long) = addTimeNs(buildTime, timeMs * 1_000_000)
fun asMapMs(): Map<BuildTime, Long> = buildTimesNs.mapValues { it.value / 1_000_000 } fun asMapMs(): Map<T, Long> = buildTimesNs.mapValues { it.value / 1_000_000 }
companion object { companion object {
const val serialVersionUID = 0L const val serialVersionUID = 0L
@@ -5,20 +5,20 @@
package org.jetbrains.kotlin.build.report.metrics package org.jetbrains.kotlin.build.report.metrics
object DoNothingBuildMetricsReporter : BuildMetricsReporter { object DoNothingBuildMetricsReporter : BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric> {
override fun startMeasure(time: BuildTime) { override fun startMeasure(time: GradleBuildTime) {
} }
override fun endMeasure(time: BuildTime) { override fun endMeasure(time: GradleBuildTime) {
} }
override fun addTimeMetricNs(time: BuildTime, durationNs: Long) { override fun addTimeMetricNs(time: GradleBuildTime, durationNs: Long) {
} }
override fun addMetric(metric: BuildPerformanceMetric, value: Long) { override fun addMetric(metric: GradleBuildPerformanceMetric, value: Long) {
} }
override fun addTimeMetric(metric: BuildPerformanceMetric) { override fun addTimeMetric(metric: GradleBuildPerformanceMetric) {
} }
override fun addAttribute(attribute: BuildAttribute) { override fun addAttribute(attribute: BuildAttribute) {
@@ -33,12 +33,12 @@ object DoNothingBuildMetricsReporter : BuildMetricsReporter {
override fun endGcMetric(name: String, value: GcMetric) { override fun endGcMetric(name: String, value: GcMetric) {
} }
override fun getMetrics(): BuildMetrics = override fun getMetrics(): BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric> =
BuildMetrics( BuildMetrics(
BuildTimes(), BuildTimes(),
BuildPerformanceMetrics(), BuildPerformanceMetrics(),
BuildAttributes() BuildAttributes()
) )
override fun addMetrics(metrics: BuildMetrics) {} override fun addMetrics(metrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>) {}
} }
@@ -5,44 +5,43 @@
package org.jetbrains.kotlin.build.report.statistics package org.jetbrains.kotlin.build.report.statistics
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
//Sensitive data. This object is used directly for statistic via http //Sensitive data. This object is used directly for statistic via http
private val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").also { it.timeZone = TimeZone.getTimeZone("UTC")} private val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").also { it.timeZone = TimeZone.getTimeZone("UTC") }
data class CompileStatisticsData(
val version: Int = 3,
val projectName: String?,
val label: String?,
val taskName: String,
val taskResult: String?,
val startTimeMs: Long,
val durationMs: Long,
val tags: Set<StatTag>,
val changes: List<String>,
val buildUuid: String = "Unset",
val kotlinVersion: String,
val kotlinLanguageVersion: String?,
val hostName: String? = "Unset",
val finishTime: Long,
val timestamp: String = formatter.format(finishTime),
val compilerArguments: List<String>,
val nonIncrementalAttributes: Set<BuildAttribute>,
//TODO think about it,time in milliseconds
val buildTimesMetrics: Map<BuildTime, Long>,
val performanceMetrics: Map<BuildPerformanceMetric, Long>,
val gcTimeMetrics: Map<String, Long>?,
val gcCountMetrics: Map<String, Long>?,
val type: String = BuildDataType.TASK_DATA.name,
val fromKotlinPlugin: Boolean?,
val compiledSources: List<String> = emptyList(),
val skipMessage: String?,
val icLogLines: List<String>,
)
interface CompileStatisticsData<B : BuildTime, P : BuildPerformanceMetric> {
fun getVersion(): Int = 4
fun getProjectName(): String?
fun getLabel(): String?
fun getTaskName(): String
fun getTaskResult(): String?
fun getStartTimeMs(): Long
fun getDurationMs(): Long
fun getTags(): Set<StatTag>
fun getChanges(): List<String>
fun getBuildUuid(): String = "Unset"
fun getKotlinVersion(): String
fun getKotlinLanguageVersion(): String?
fun getHostName(): String? = "Unset"
fun getFinishTime(): Long
fun getTimestamp(): String = formatter.format(getFinishTime())
fun getCompilerArguments(): List<String>
fun getNonIncrementalAttributes(): Set<BuildAttribute>
//TODO think about it,time in milliseconds
fun getBuildTimesMetrics(): Map<B, Long>
fun getPerformanceMetrics(): Map<P, Long>
fun getGcTimeMetrics(): Map<String, Long>?
fun getGcCountMetrics(): Map<String, Long>?
fun getType(): String = BuildDataType.TASK_DATA.name
fun getFromKotlinPlugin(): Boolean?
fun getCompiledSources(): List<String> = emptyList()
fun getSkipMessage(): String?
fun getIcLogLines(): List<String>
}
enum class StatTag(val readableString: String) { enum class StatTag(val readableString: String) {
ABI_SNAPSHOT("ABI Snapshot"), ABI_SNAPSHOT("ABI Snapshot"),
@@ -86,7 +85,7 @@ data class BuildFinishStatisticsData(
val timestamp: String = formatter.format(finishTime), val timestamp: String = formatter.format(finishTime),
val hostName: String? = "Unset", val hostName: String? = "Unset",
val tags: Set<StatTag>, val tags: Set<StatTag>,
val gitBranch: String = "Unset" val gitBranch: String = "Unset",
) )
@@ -15,26 +15,26 @@ import java.io.Serializable
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class FileReportService( class FileReportService<B : BuildTime, P : BuildPerformanceMetric>(
private val outputFile: File, private val outputFile: File,
private val printMetrics: Boolean, private val printMetrics: Boolean,
private val logger: KotlinLogger private val logger: KotlinLogger,
) : Serializable { ) : Serializable {
companion object { companion object {
private val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").also { it.timeZone = TimeZone.getTimeZone("UTC")} private val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").also { it.timeZone = TimeZone.getTimeZone("UTC") }
fun reportBuildStatInFile( fun <B : BuildTime, P : BuildPerformanceMetric> reportBuildStatInFile(
buildReportDir: File, buildReportDir: File,
projectName: String, projectName: String,
includeMetricsInReport: Boolean, includeMetricsInReport: Boolean,
buildData: List<CompileStatisticsData>, buildData: List<CompileStatisticsData<B, P>>,
startParameters: BuildStartParameters, startParameters: BuildStartParameters,
failureMessages: List<String>, failureMessages: List<String>,
logger: KotlinLogger logger: KotlinLogger,
) { ) {
val ts = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Calendar.getInstance().time) val ts = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Calendar.getInstance().time)
val reportFile = buildReportDir.resolve("$projectName-build-$ts.txt") val reportFile = buildReportDir.resolve("$projectName-build-$ts.txt")
FileReportService( FileReportService<B, P>(
outputFile = reportFile, outputFile = reportFile,
printMetrics = includeMetricsInReport, printMetrics = includeMetricsInReport,
logger = logger logger = logger
@@ -45,9 +45,9 @@ class FileReportService(
private lateinit var p: Printer private lateinit var p: Printer
fun process( fun process(
statisticsData: List<CompileStatisticsData>, statisticsData: List<CompileStatisticsData<B, P>>,
startParameters: BuildStartParameters, startParameters: BuildStartParameters,
failureMessages: List<String> = emptyList() failureMessages: List<String> = emptyList(),
) { ) {
val buildReportPath = outputFile.toPath().toUri().toString() val buildReportPath = outputFile.toPath().toUri().toString()
try { try {
@@ -69,9 +69,9 @@ class FileReportService(
} }
private fun printBuildReport( private fun printBuildReport(
statisticsData: List<CompileStatisticsData>, statisticsData: List<CompileStatisticsData<B, P>>,
startParameters: BuildStartParameters, startParameters: BuildStartParameters,
failureMessages: List<String> failureMessages: List<String>,
) { ) {
// NOTE: BuildExecutionData / BuildOperationRecord contains data for both tasks and transforms. // NOTE: BuildExecutionData / BuildOperationRecord contains data for both tasks and transforms.
// Where possible, we still use the term "tasks" because saying "tasks/transforms" is a bit verbose and "build operations" may sound // Where possible, we still use the term "tasks" because saying "tasks/transforms" is a bit verbose and "build operations" may sound
@@ -80,13 +80,13 @@ class FileReportService(
printBuildInfo(startParameters, failureMessages) printBuildInfo(startParameters, failureMessages)
if (printMetrics && statisticsData.isNotEmpty()) { if (printMetrics && statisticsData.isNotEmpty()) {
printMetrics( printMetrics(
statisticsData.map { it.buildTimesMetrics }.reduce { agg, value -> statisticsData.map { it.getBuildTimesMetrics() }.reduce { agg, value ->
(agg.keys + value.keys).associateWith { (agg[it] ?: 0) + (value[it] ?: 0) } (agg.keys + value.keys).associateWith { (agg[it] ?: 0) + (value[it] ?: 0) }
}, },
statisticsData.map { it.performanceMetrics }.reduce { agg, value -> statisticsData.map { it.getPerformanceMetrics() }.reduce { agg, value ->
(agg.keys + value.keys).associateWith { (agg[it] ?: 0) + (value[it] ?: 0) } (agg.keys + value.keys).associateWith { (agg[it] ?: 0) + (value[it] ?: 0) }
}, },
statisticsData.map { it.nonIncrementalAttributes.asSequence() }.reduce { agg, value -> agg + value }.toList(), statisticsData.map { it.getNonIncrementalAttributes().asSequence() }.reduce { agg, value -> agg + value }.toList(),
aggregatedMetric = true aggregatedMetric = true
) )
p.println() p.println()
@@ -114,12 +114,12 @@ class FileReportService(
} }
private fun printMetrics( private fun printMetrics(
buildTimesMetrics: Map<BuildTime, Long>, buildTimesMetrics: Map<out BuildTime, Long>,
performanceMetrics: Map<BuildPerformanceMetric, Long>, performanceMetrics: Map<out BuildPerformanceMetric, Long>,
nonIncrementalAttributes: Collection<BuildAttribute>, nonIncrementalAttributes: Collection<BuildAttribute>,
gcTimeMetrics: Map<String, Long>? = emptyMap(), gcTimeMetrics: Map<String, Long>? = emptyMap(),
gcCountMetrics: Map<String, Long>? = emptyMap(), gcCountMetrics: Map<String, Long>? = emptyMap(),
aggregatedMetric: Boolean = false aggregatedMetric: Boolean = false,
) { ) {
printBuildTimes(buildTimesMetrics) printBuildTimes(buildTimesMetrics)
if (aggregatedMetric) p.println() if (aggregatedMetric) p.println()
@@ -129,7 +129,7 @@ class FileReportService(
printBuildAttributes(nonIncrementalAttributes) printBuildAttributes(nonIncrementalAttributes)
//TODO: KT-57310 Implement build GC metric in //TODO: KT-57310 Implement build GC metric in
if (!aggregatedMetric) { if (!aggregatedMetric) {
printGcMetrics(gcTimeMetrics, gcCountMetrics) printGcMetrics(gcTimeMetrics, gcCountMetrics)
} }
@@ -137,7 +137,7 @@ class FileReportService(
private fun printGcMetrics( private fun printGcMetrics(
gcTimeMetrics: Map<String, Long>?, gcTimeMetrics: Map<String, Long>?,
gcCountMetrics: Map<String, Long>? gcCountMetrics: Map<String, Long>?,
) { ) {
val keys = HashSet<String>() val keys = HashSet<String>()
gcCountMetrics?.keys?.also { keys.addAll(it) } gcCountMetrics?.keys?.also { keys.addAll(it) }
@@ -155,7 +155,7 @@ class FileReportService(
} }
} }
private fun printBuildTimes(buildTimes: Map<BuildTime, Long>) { private fun printBuildTimes(buildTimes: Map<out BuildTime, Long>) {
if (buildTimes.isEmpty()) return if (buildTimes.isEmpty()) return
p.println("Time metrics:") p.println("Time metrics:")
@@ -166,29 +166,29 @@ class FileReportService(
val timeMs = buildTimes[buildTime] val timeMs = buildTimes[buildTime]
if (timeMs != null) { if (timeMs != null) {
p.println("${buildTime.readableString}: ${formatTime(timeMs)}") p.println("${buildTime.getReadableString()}: ${formatTime(timeMs)}")
p.withIndent { p.withIndent {
BuildTime.children[buildTime]?.forEach { printBuildTime(it) } buildTime.children()?.forEach { printBuildTime(it) }
} }
} else { } else {
//Skip formatting if parent metric does not set //Skip formatting if parent metric does not set
BuildTime.children[buildTime]?.forEach { printBuildTime(it) } buildTime.children()?.forEach { printBuildTime(it) }
} }
} }
for (buildTime in BuildTime.values()) { for (buildTime in buildTimes.keys.first().getAllMetrics()) {
if (buildTime.parent != null) continue if (buildTime.getParent() != null) continue
printBuildTime(buildTime) printBuildTime(buildTime)
} }
} }
} }
private fun printBuildPerformanceMetrics(buildMetrics: Map<BuildPerformanceMetric, Long>) { private fun printBuildPerformanceMetrics(buildMetrics: Map<out BuildPerformanceMetric, Long>) {
if (buildMetrics.isEmpty()) return if (buildMetrics.isEmpty()) return
p.withIndent("Size metrics:") { p.withIndent("Size metrics:") {
for (metric in BuildPerformanceMetric.values()) { for (metric in buildMetrics.keys.first().getAllMetrics()) {
buildMetrics[metric]?.let { printSizeMetric(metric, it) } buildMetrics[metric]?.let { printSizeMetric(metric, it) }
} }
} }
@@ -197,10 +197,10 @@ class FileReportService(
private fun printSizeMetric(sizeMetric: BuildPerformanceMetric, value: Long) { private fun printSizeMetric(sizeMetric: BuildPerformanceMetric, value: Long) {
fun BuildPerformanceMetric.numberOfAncestors(): Int { fun BuildPerformanceMetric.numberOfAncestors(): Int {
var count = 0 var count = 0
var parent: BuildPerformanceMetric? = parent var parent: BuildPerformanceMetric? = getParent()
while (parent != null) { while (parent != null) {
count++ count++
parent = parent.parent parent = parent.getParent()
} }
return count return count
} }
@@ -208,12 +208,12 @@ class FileReportService(
val indentLevel = sizeMetric.numberOfAncestors() val indentLevel = sizeMetric.numberOfAncestors()
repeat(indentLevel) { p.pushIndent() } repeat(indentLevel) { p.pushIndent() }
when (sizeMetric.type) { when (sizeMetric.getType()) {
ValueType.BYTES -> p.println("${sizeMetric.readableString}: ${formatSize(value)}") ValueType.BYTES -> p.println("${sizeMetric.getReadableString()}: ${formatSize(value)}")
ValueType.NUMBER -> p.println("${sizeMetric.readableString}: $value") ValueType.NUMBER -> p.println("${sizeMetric.getReadableString()}: $value")
ValueType.NANOSECONDS -> p.println("${sizeMetric.readableString}: $value") ValueType.NANOSECONDS -> p.println("${sizeMetric.getReadableString()}: $value")
ValueType.MILLISECONDS -> p.println("${sizeMetric.readableString}: ${formatTime(value)}") ValueType.MILLISECONDS -> p.println("${sizeMetric.getReadableString()}: ${formatTime(value)}")
ValueType.TIME -> p.println("${sizeMetric.readableString}: ${formatter.format(value)}") ValueType.TIME -> p.println("${sizeMetric.getReadableString()}: ${formatter.format(value)}")
} }
repeat(indentLevel) { p.popIndent() } repeat(indentLevel) { p.popIndent() }
} }
@@ -230,16 +230,16 @@ class FileReportService(
} }
} }
private fun printTaskOverview(statisticsData: Collection<CompileStatisticsData>) { private fun printTaskOverview(statisticsData: Collection<CompileStatisticsData<B, P>>) {
var allTasksTimeMs = 0L var allTasksTimeMs = 0L
var kotlinTotalTimeMs = 0L var kotlinTotalTimeMs = 0L
val kotlinTasks = ArrayList<CompileStatisticsData>() val kotlinTasks = ArrayList<CompileStatisticsData<B, P>>()
for (task in statisticsData) { for (task in statisticsData) {
val taskTimeMs = task.durationMs val taskTimeMs = task.getDurationMs()
allTasksTimeMs += taskTimeMs allTasksTimeMs += taskTimeMs
if (task.fromKotlinPlugin == true) { if (task.getFromKotlinPlugin() == true) {
kotlinTotalTimeMs += taskTimeMs kotlinTotalTimeMs += taskTimeMs
kotlinTasks.add(task) kotlinTasks.add(task)
} }
@@ -254,45 +254,47 @@ class FileReportService(
p.println("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeMs)} ($ktTaskPercent % of all tasks time)") p.println("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeMs)} ($ktTaskPercent % of all tasks time)")
val table = TextTable("Time", "% of Kotlin time", "Task") val table = TextTable("Time", "% of Kotlin time", "Task")
for (task in kotlinTasks.sortedWith(compareBy({ -it.durationMs }, { it.startTimeMs }))) { for (task in kotlinTasks.sortedWith(compareBy({ -it.getDurationMs() }, { it.getStartTimeMs() }))) {
val timeMs = task.durationMs val timeMs = task.getDurationMs()
val percent = (timeMs.toDouble() / kotlinTotalTimeMs * 100).asString(1) val percent = (timeMs.toDouble() / kotlinTotalTimeMs * 100).asString(1)
table.addRow(formatTime(timeMs), "$percent %", task.taskName) table.addRow(formatTime(timeMs), "$percent %", task.getTaskName())
} }
table.printTo(p) table.printTo(p)
p.println() p.println()
} }
private fun printTasksLog(statisticsData: List<CompileStatisticsData>) { private fun printTasksLog(statisticsData: List<CompileStatisticsData<B, P>>) {
for (task in statisticsData.sortedWith(compareBy({ -it.durationMs }, { it.startTimeMs }))) { for (task in statisticsData.sortedWith(compareBy({ -it.getDurationMs() }, { it.getStartTimeMs() }))) {
printTaskLog(task) printTaskLog(task)
p.println() p.println()
} }
} }
private fun printTaskLog(statisticsData: CompileStatisticsData) { private fun <B : BuildTime, P : BuildPerformanceMetric> printTaskLog(statisticsData: CompileStatisticsData<B, P>) {
val skipMessage = statisticsData.skipMessage val skipMessage = statisticsData.getSkipMessage()
if (skipMessage != null) { if (skipMessage != null) {
p.println("Task '${statisticsData.taskName}' was skipped: $skipMessage") p.println("Task '${statisticsData.getTaskName()}' was skipped: $skipMessage")
} else { } else {
p.println("Task '${statisticsData.taskName}' finished in ${formatTime(statisticsData.durationMs)}") p.println("Task '${statisticsData.getTaskName()}' finished in ${formatTime(statisticsData.getDurationMs())}")
} }
statisticsData.kotlinLanguageVersion?.also { statisticsData.getKotlinLanguageVersion()?.also {
p.withIndent("Task info:") { p.withIndent("Task info:") {
p.println("Kotlin language version: $it") p.println("Kotlin language version: $it")
} }
} }
if (statisticsData.icLogLines.isNotEmpty()) { if (statisticsData.getIcLogLines().isNotEmpty()) {
p.withIndent("Compilation log for task '${statisticsData.taskName}':") { p.withIndent("Compilation log for task '${statisticsData.getTaskName()}':") {
statisticsData.icLogLines.forEach { p.println(it) } statisticsData.getIcLogLines().forEach { p.println(it) }
} }
} }
if (printMetrics) { if (printMetrics) {
printMetrics(statisticsData.buildTimesMetrics, statisticsData.performanceMetrics, statisticsData.nonIncrementalAttributes, printMetrics(
statisticsData.gcTimeMetrics, statisticsData.gcCountMetrics) statisticsData.getBuildTimesMetrics(), statisticsData.getPerformanceMetrics(), statisticsData.getNonIncrementalAttributes(),
statisticsData.getGcTimeMetrics(), statisticsData.getGcCountMetrics()
)
} }
} }
} }
@@ -23,6 +23,8 @@ import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.report.RemoteBuildReporter import org.jetbrains.kotlin.build.report.RemoteBuildReporter
import org.jetbrains.kotlin.build.report.info import org.jetbrains.kotlin.build.report.info
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.build.report.metrics.endMeasureGc import org.jetbrains.kotlin.build.report.metrics.endMeasureGc
import org.jetbrains.kotlin.build.report.metrics.startMeasureGc import org.jetbrains.kotlin.build.report.metrics.startMeasureGc
import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.CLICompiler
@@ -294,7 +296,7 @@ abstract class CompileServiceImplBase(
createMessageCollector: (ServicesFacadeT, CompilationOptions) -> MessageCollector, createMessageCollector: (ServicesFacadeT, CompilationOptions) -> MessageCollector,
createReporter: (ServicesFacadeT, CompilationOptions) -> DaemonMessageReporter, createReporter: (ServicesFacadeT, CompilationOptions) -> DaemonMessageReporter,
createServices: (JpsServicesFacadeT, EventManager, Profiler) -> Services, createServices: (JpsServicesFacadeT, EventManager, Profiler) -> Services,
getICReporter: (ServicesFacadeT, CompilationResultsT?, IncrementalCompilationOptions) -> RemoteBuildReporter getICReporter: (ServicesFacadeT, CompilationResultsT?, IncrementalCompilationOptions) -> RemoteBuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>
) = kotlin.run { ) = kotlin.run {
val messageCollector = createMessageCollector(servicesFacade, compilationOptions) val messageCollector = createMessageCollector(servicesFacade, compilationOptions)
val daemonReporter = createReporter(servicesFacade, compilationOptions) val daemonReporter = createReporter(servicesFacade, compilationOptions)
@@ -532,7 +534,7 @@ abstract class CompileServiceImplBase(
args: K2JSCompilerArguments, args: K2JSCompilerArguments,
incrementalCompilationOptions: IncrementalCompilationOptions, incrementalCompilationOptions: IncrementalCompilationOptions,
compilerMessageCollector: MessageCollector, compilerMessageCollector: MessageCollector,
reporter: RemoteBuildReporter reporter: RemoteBuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>
): ExitCode { ): ExitCode {
reporter.startMeasureGc() reporter.startMeasureGc()
val allKotlinFiles = arrayListOf<File>() val allKotlinFiles = arrayListOf<File>()
@@ -577,7 +579,7 @@ abstract class CompileServiceImplBase(
k2jvmArgs: K2JVMCompilerArguments, k2jvmArgs: K2JVMCompilerArguments,
incrementalCompilationOptions: IncrementalCompilationOptions, incrementalCompilationOptions: IncrementalCompilationOptions,
compilerMessageCollector: MessageCollector, compilerMessageCollector: MessageCollector,
reporter: RemoteBuildReporter reporter: RemoteBuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>
): ExitCode { ): ExitCode {
reporter.startMeasureGc() reporter.startMeasureGc()
val allKotlinExtensions = (DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS + val allKotlinExtensions = (DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS +
@@ -6,17 +6,19 @@
package org.jetbrains.kotlin.daemon.report package org.jetbrains.kotlin.daemon.report
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.build.report.metrics.RemoteBuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.RemoteBuildMetricsReporter
import org.jetbrains.kotlin.daemon.common.CompilationResultCategory import org.jetbrains.kotlin.daemon.common.CompilationResultCategory
import org.jetbrains.kotlin.daemon.common.CompilationResults import org.jetbrains.kotlin.daemon.common.CompilationResults
class RemoteBuildMetricsReporterAdapter( class RemoteBuildMetricsReporterAdapter(
private val delegate: BuildMetricsReporter, private val delegate: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
private val shouldReport: Boolean, private val shouldReport: Boolean,
private val compilationResults: CompilationResults private val compilationResults: CompilationResults
) : ) :
BuildMetricsReporter by delegate, BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric> by delegate,
RemoteBuildMetricsReporter { RemoteBuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric> {
override fun flush() { override fun flush() {
if (shouldReport) { if (shouldReport) {
@@ -21,13 +21,15 @@ import org.jetbrains.kotlin.build.report.RemoteBuildReporter
import org.jetbrains.kotlin.build.report.RemoteICReporter import org.jetbrains.kotlin.build.report.RemoteICReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl
import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.daemon.common.* import org.jetbrains.kotlin.daemon.common.*
fun getBuildReporter( fun getBuildReporter(
servicesFacade: CompilerServicesFacadeBase, servicesFacade: CompilerServicesFacadeBase,
compilationResults: CompilationResults, compilationResults: CompilationResults,
compilationOptions: IncrementalCompilationOptions compilationOptions: IncrementalCompilationOptions
): RemoteBuildReporter { ): RemoteBuildReporter<GradleBuildTime, GradleBuildPerformanceMetric> {
val root = compilationOptions.modulesInfo.projectRoot val root = compilationOptions.modulesInfo.projectRoot
val reporters = ArrayList<RemoteICReporter>() val reporters = ArrayList<RemoteICReporter>()
@@ -21,11 +21,8 @@ import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.build.report.BuildReporter import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.debug import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.info import org.jetbrains.kotlin.build.report.info
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute.* import org.jetbrains.kotlin.build.report.metrics.BuildAttribute.*
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.build.report.warn import org.jetbrains.kotlin.build.report.warn
import org.jetbrains.kotlin.cli.common.* import org.jetbrains.kotlin.cli.common.*
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
@@ -48,6 +45,7 @@ import org.jetbrains.kotlin.util.removeSuffixIfPresent
import org.jetbrains.kotlin.utils.toMetadataVersion import org.jetbrains.kotlin.utils.toMetadataVersion
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
import java.util.*
abstract class IncrementalCompilerRunner< abstract class IncrementalCompilerRunner<
Args : CommonCompilerArguments, Args : CommonCompilerArguments,
@@ -55,7 +53,7 @@ abstract class IncrementalCompilerRunner<
>( >(
private val workingDir: File, private val workingDir: File,
cacheDirName: String, cacheDirName: String,
protected val reporter: BuildReporter, protected val reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
protected val buildHistoryFile: File, protected val buildHistoryFile: File,
/** /**
@@ -111,7 +109,7 @@ abstract class IncrementalCompilerRunner<
// otherwise we track source files changes ourselves. // otherwise we track source files changes ourselves.
changedFiles: ChangedFiles?, changedFiles: ChangedFiles?,
projectDir: File? = null projectDir: File? = null
): ExitCode = reporter.measure(BuildTime.INCREMENTAL_COMPILATION_DAEMON) { ): ExitCode = reporter.measure(GradleBuildTime.INCREMENTAL_COMPILATION_DAEMON) {
return when (val result = tryCompileIncrementally(allSourceFiles, changedFiles, args, projectDir, messageCollector)) { return when (val result = tryCompileIncrementally(allSourceFiles, changedFiles, args, projectDir, messageCollector)) {
is ICResult.Completed -> { is ICResult.Completed -> {
reporter.debug { "Incremental compilation completed" } reporter.debug { "Incremental compilation completed" }
@@ -202,7 +200,7 @@ abstract class IncrementalCompilerRunner<
// Step 2: Compute files to recompile // Step 2: Compute files to recompile
val compilationMode = try { val compilationMode = try {
reporter.measure(BuildTime.IC_CALCULATE_INITIAL_DIRTY_SET) { reporter.measure(GradleBuildTime.IC_CALCULATE_INITIAL_DIRTY_SET) {
calculateSourcesToCompile(caches, knownChangedFiles, args, messageCollector, classpathAbiSnapshot ?: emptyMap()) calculateSourcesToCompile(caches, knownChangedFiles, args, messageCollector, classpathAbiSnapshot ?: emptyMap())
} }
} catch (e: Throwable) { } catch (e: Throwable) {
@@ -259,7 +257,7 @@ abstract class IncrementalCompilerRunner<
trackChangedFiles: Boolean, // Whether we need to track changes to the source files or the build system already handles it trackChangedFiles: Boolean, // Whether we need to track changes to the source files or the build system already handles it
messageCollector: MessageCollector, messageCollector: MessageCollector,
): ExitCode { ): ExitCode {
reporter.measure(BuildTime.CLEAR_OUTPUT_ON_REBUILD) { reporter.measure(GradleBuildTime.CLEAR_OUTPUT_ON_REBUILD) {
val mainOutputDirs = setOf(destinationDir(args), workingDir) val mainOutputDirs = setOf(destinationDir(args), workingDir)
val outputDirsToClean = outputDirs?.also { val outputDirsToClean = outputDirs?.also {
check(it.containsAll(mainOutputDirs)) { "outputDirs is missing classesDir and workingDir: $it" } check(it.containsAll(mainOutputDirs)) { "outputDirs is missing classesDir and workingDir: $it" }
@@ -284,7 +282,7 @@ abstract class IncrementalCompilerRunner<
private class AbiSnapshotData(val snapshot: AbiSnapshot, val classpathAbiSnapshot: Map<String, AbiSnapshot>) private class AbiSnapshotData(val snapshot: AbiSnapshot, val classpathAbiSnapshot: Map<String, AbiSnapshot>)
private fun getClasspathAbiSnapshot(args: Args): Map<String, AbiSnapshot> { private fun getClasspathAbiSnapshot(args: Args): Map<String, AbiSnapshot> {
return reporter.measure(BuildTime.SET_UP_ABI_SNAPSHOTS) { return reporter.measure(GradleBuildTime.SET_UP_ABI_SNAPSHOTS) {
setupJarDependencies(args, reporter) setupJarDependencies(args, reporter)
} }
} }
@@ -330,7 +328,7 @@ abstract class IncrementalCompilerRunner<
classpathAbiSnapshots: Map<String, AbiSnapshot> classpathAbiSnapshots: Map<String, AbiSnapshot>
): CompilationMode ): CompilationMode
protected open fun setupJarDependencies(args: Args, reporter: BuildReporter): Map<String, AbiSnapshot> = emptyMap() protected open fun setupJarDependencies(args: Args, reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>): Map<String, AbiSnapshot> = emptyMap()
protected fun initDirtyFiles(dirtyFiles: DirtyFilesContainer, changedFiles: ChangedFiles.Known) { protected fun initDirtyFiles(dirtyFiles: DirtyFilesContainer, changedFiles: ChangedFiles.Known) {
dirtyFiles.add(changedFiles.modified, "was modified since last time") dirtyFiles.add(changedFiles.modified, "was modified since last time")
@@ -415,12 +413,12 @@ abstract class IncrementalCompilerRunner<
} }
private fun collectMetrics() { private fun collectMetrics() {
reporter.measure(BuildTime.CALCULATE_OUTPUT_SIZE) { reporter.measure(GradleBuildTime.CALCULATE_OUTPUT_SIZE) {
reporter.addMetric( reporter.addMetric(
BuildPerformanceMetric.SNAPSHOT_SIZE, GradleBuildPerformanceMetric.SNAPSHOT_SIZE,
buildHistoryFile.length() + lastBuildInfoFile.length() + abiSnapshotFile.length() buildHistoryFile.length() + lastBuildInfoFile.length() + abiSnapshotFile.length()
) )
reporter.addMetric(BuildPerformanceMetric.CACHE_DIRECTORY_SIZE, cacheDirectory.walk().sumOf { it.length() }) reporter.addMetric(GradleBuildPerformanceMetric.CACHE_DIRECTORY_SIZE, cacheDirectory.walk().sumOf { it.length() })
} }
} }
@@ -472,7 +470,7 @@ abstract class IncrementalCompilerRunner<
val bufferingMessageCollector = BufferingMessageCollector() val bufferingMessageCollector = BufferingMessageCollector()
val messageCollectorAdapter = MessageCollectorToOutputItemsCollectorAdapter(bufferingMessageCollector, transactionOutputsRegistrar) val messageCollectorAdapter = MessageCollectorToOutputItemsCollectorAdapter(bufferingMessageCollector, transactionOutputsRegistrar)
val compiledSources = reporter.measure(BuildTime.COMPILATION_ROUND) { val compiledSources = reporter.measure(GradleBuildTime.COMPILATION_ROUND) {
runCompiler( runCompiler(
sourcesToCompile, args, caches, services, messageCollectorAdapter, sourcesToCompile, args, caches, services, messageCollectorAdapter,
allKotlinSources, compilationMode is CompilationMode.Incremental allKotlinSources, compilationMode is CompilationMode.Incremental
@@ -509,7 +507,7 @@ abstract class IncrementalCompilerRunner<
transaction.deleteFile(dirtySourcesSinceLastTimeFile.toPath()) transaction.deleteFile(dirtySourcesSinceLastTimeFile.toPath())
val changesCollector = ChangesCollector() val changesCollector = ChangesCollector()
reporter.measure(BuildTime.IC_UPDATE_CACHES) { reporter.measure(GradleBuildTime.IC_UPDATE_CACHES) {
caches.platformCache.updateComplementaryFiles(dirtySources, expectActualTracker) caches.platformCache.updateComplementaryFiles(dirtySources, expectActualTracker)
caches.inputsCache.registerOutputForSourceFiles(generatedFiles) caches.inputsCache.registerOutputForSourceFiles(generatedFiles)
caches.lookupCache.update(lookupTracker, sourcesToCompile, removedKotlinSources) caches.lookupCache.update(lookupTracker, sourcesToCompile, removedKotlinSources)
@@ -557,7 +555,7 @@ abstract class IncrementalCompilerRunner<
} }
if (exitCode == ExitCode.OK) { if (exitCode == ExitCode.OK) {
reporter.measure(BuildTime.STORE_BUILD_INFO) { reporter.measure(GradleBuildTime.STORE_BUILD_INFO) {
BuildInfo.write(icContext, currentBuildInfo, lastBuildInfoFile) BuildInfo.write(icContext, currentBuildInfo, lastBuildInfoFile)
//write abi snapshot //write abi snapshot
@@ -610,7 +608,7 @@ abstract class IncrementalCompilerRunner<
compilationMode: CompilationMode, compilationMode: CompilationMode,
currentBuildInfo: BuildInfo, currentBuildInfo: BuildInfo,
dirtyData: DirtyData, dirtyData: DirtyData,
) = reporter.measure(BuildTime.IC_WRITE_HISTORY_FILE) { ) = reporter.measure(GradleBuildTime.IC_WRITE_HISTORY_FILE) {
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList() val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
val newDiff = if (compilationMode is CompilationMode.Incremental) { val newDiff = if (compilationMode is CompilationMode.Incremental) {
BuildDifference(currentBuildInfo.startTS, true, dirtyData) BuildDifference(currentBuildInfo.startTS, true, dirtyData)
@@ -636,22 +634,22 @@ abstract class IncrementalCompilerRunner<
protected fun reportPerformanceData(defaultPerformanceManager: CommonCompilerPerformanceManager) { protected fun reportPerformanceData(defaultPerformanceManager: CommonCompilerPerformanceManager) {
defaultPerformanceManager.getMeasurementResults().forEach { defaultPerformanceManager.getMeasurementResults().forEach {
when (it) { when (it) {
is CompilerInitializationMeasurement -> reporter.addTimeMetricMs(BuildTime.COMPILER_INITIALIZATION, it.milliseconds) is CompilerInitializationMeasurement -> reporter.addTimeMetricMs(GradleBuildTime.COMPILER_INITIALIZATION, it.milliseconds)
is CodeAnalysisMeasurement -> { is CodeAnalysisMeasurement -> {
reporter.addTimeMetricMs(BuildTime.CODE_ANALYSIS, it.milliseconds) reporter.addTimeMetricMs(GradleBuildTime.CODE_ANALYSIS, it.milliseconds)
it.lines?.apply { it.lines?.apply {
reporter.addMetric(BuildPerformanceMetric.ANALYZED_LINES_NUMBER, this.toLong()) reporter.addMetric(GradleBuildPerformanceMetric.ANALYZED_LINES_NUMBER, this.toLong())
if (it.milliseconds > 0) { if (it.milliseconds > 0) {
reporter.addMetric(BuildPerformanceMetric.ANALYSIS_LPS, this * 1000 / it.milliseconds) reporter.addMetric(GradleBuildPerformanceMetric.ANALYSIS_LPS, this * 1000 / it.milliseconds)
} }
} }
} }
is CodeGenerationMeasurement -> { is CodeGenerationMeasurement -> {
reporter.addTimeMetricMs(BuildTime.CODE_GENERATION, it.milliseconds) reporter.addTimeMetricMs(GradleBuildTime.CODE_GENERATION, it.milliseconds)
it.lines?.apply { it.lines?.apply {
reporter.addMetric(BuildPerformanceMetric.CODE_GENERATED_LINES_NUMBER, this.toLong()) reporter.addMetric(GradleBuildPerformanceMetric.CODE_GENERATED_LINES_NUMBER, this.toLong())
if (it.milliseconds > 0) { if (it.milliseconds > 0) {
reporter.addMetric(BuildPerformanceMetric.CODE_GENERATION_LPS, this * 1000 / it.milliseconds) reporter.addMetric(GradleBuildPerformanceMetric.CODE_GENERATION_LPS, this * 1000 / it.milliseconds)
} }
} }
} }
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.report.BuildReporter import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.cli.common.* import org.jetbrains.kotlin.cli.common.*
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
@@ -61,7 +63,7 @@ import java.io.File
open class IncrementalFirJvmCompilerRunner( open class IncrementalFirJvmCompilerRunner(
workingDir: File, workingDir: File,
reporter: BuildReporter, reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
buildHistoryFile: File, buildHistoryFile: File,
outputDirs: Collection<File>?, outputDirs: Collection<File>?,
modulesApiHistory: ModulesApiHistory, modulesApiHistory: ModulesApiHistory,
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.build.report.ICReporter
import org.jetbrains.kotlin.build.report.info import org.jetbrains.kotlin.build.report.info
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
@@ -83,7 +85,7 @@ inline fun <R> withJsIC(args: CommonCompilerArguments, enabled: Boolean = true,
class IncrementalJsCompilerRunner( class IncrementalJsCompilerRunner(
workingDir: File, workingDir: File,
reporter: BuildReporter, reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
buildHistoryFile: File, buildHistoryFile: File,
private val modulesApiHistory: ModulesApiHistory, private val modulesApiHistory: ModulesApiHistory,
private val scopeExpansion: CompileScopeExpansionMode = CompileScopeExpansionMode.NEVER, private val scopeExpansion: CompileScopeExpansionMode = CompileScopeExpansionMode.NEVER,
@@ -61,7 +61,7 @@ import java.io.File
open class IncrementalJvmCompilerRunner( open class IncrementalJvmCompilerRunner(
workingDir: File, workingDir: File,
reporter: BuildReporter, reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
private val usePreciseJavaTracking: Boolean, private val usePreciseJavaTracking: Boolean,
buildHistoryFile: File, buildHistoryFile: File,
outputDirs: Collection<File>?, outputDirs: Collection<File>?,
@@ -142,7 +142,7 @@ open class IncrementalJvmCompilerRunner(
//TODO can't use the same way as for build-history files because abi-snapshot for all dependencies should be stored into last-build //TODO can't use the same way as for build-history files because abi-snapshot for all dependencies should be stored into last-build
// and not only changed one // and not only changed one
// (but possibly we dont need to read it all and may be it is possible to update only those who was changed) // (but possibly we dont need to read it all and may be it is possible to update only those who was changed)
override fun setupJarDependencies(args: K2JVMCompilerArguments, reporter: BuildReporter): Map<String, AbiSnapshot> { override fun setupJarDependencies(args: K2JVMCompilerArguments, reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>): Map<String, AbiSnapshot> {
//fill abiSnapshots //fill abiSnapshots
val abiSnapshots = HashMap<String, AbiSnapshot>() val abiSnapshots = HashMap<String, AbiSnapshot>()
args.classpathAsList args.classpathAsList
@@ -186,8 +186,8 @@ open class IncrementalJvmCompilerRunner(
val changedAndImpactedSymbols = when (classpathChanges) { val changedAndImpactedSymbols = when (classpathChanges) {
// Note: classpathChanges is deserialized, so they are no longer singleton objects and need to be compared using `is` (not `==`) // Note: classpathChanges is deserialized, so they are no longer singleton objects and need to be compared using `is` (not `==`)
is NoChanges -> ChangesEither.Known(emptySet(), emptySet()) is NoChanges -> ChangesEither.Known(emptySet(), emptySet())
is ToBeComputedByIncrementalCompiler -> reporter.measure(BuildTime.COMPUTE_CLASSPATH_CHANGES) { is ToBeComputedByIncrementalCompiler -> reporter.measure(GradleBuildTime.COMPUTE_CLASSPATH_CHANGES) {
reporter.addMetric(BuildPerformanceMetric.COMPUTE_CLASSPATH_CHANGES_EXECUTION_COUNT, 1) reporter.addMetric(GradleBuildPerformanceMetric.COMPUTE_CLASSPATH_CHANGES_EXECUTION_COUNT, 1)
val storeCurrentClasspathSnapshotForReuse = val storeCurrentClasspathSnapshotForReuse =
{ currentClasspathSnapshotArg: List<AccessibleClassSnapshot>, { currentClasspathSnapshotArg: List<AccessibleClassSnapshot>,
shrunkCurrentClasspathAgainstPreviousLookupsArg: List<AccessibleClassSnapshot> -> shrunkCurrentClasspathAgainstPreviousLookupsArg: List<AccessibleClassSnapshot> ->
@@ -206,7 +206,7 @@ open class IncrementalJvmCompilerRunner(
} }
is NotAvailableDueToMissingClasspathSnapshot -> ChangesEither.Unknown(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND) is NotAvailableDueToMissingClasspathSnapshot -> ChangesEither.Unknown(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND)
is NotAvailableForNonIncrementalRun -> ChangesEither.Unknown(BuildAttribute.UNKNOWN_CHANGES_IN_GRADLE_INPUTS) is NotAvailableForNonIncrementalRun -> ChangesEither.Unknown(BuildAttribute.UNKNOWN_CHANGES_IN_GRADLE_INPUTS)
is ClasspathSnapshotDisabled -> reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) { is ClasspathSnapshotDisabled -> reporter.measure(GradleBuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) {
if (!withAbiSnapshot && !buildHistoryFile.isFile) { if (!withAbiSnapshot && !buildHistoryFile.isFile) {
// If the previous build was a Gradle cache hit, the build history file must have been deleted as it is marked as // If the previous build was a Gradle cache hit, the build history file must have been deleted as it is marked as
// @LocalState in the Gradle task. Therefore, this compilation will need to run non-incrementally. // @LocalState in the Gradle task. Therefore, this compilation will need to run non-incrementally.
@@ -242,7 +242,7 @@ open class IncrementalJvmCompilerRunner(
dirtyFiles.addByDirtySymbols(changedAndImpactedSymbols.lookupSymbols) dirtyFiles.addByDirtySymbols(changedAndImpactedSymbols.lookupSymbols)
dirtyFiles.addByDirtyClasses(changedAndImpactedSymbols.fqNames) dirtyFiles.addByDirtyClasses(changedAndImpactedSymbols.fqNames)
reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_JAVA_SOURCES) { reporter.measure(GradleBuildTime.IC_ANALYZE_CHANGES_IN_JAVA_SOURCES) {
if (!usePreciseJavaTracking) { if (!usePreciseJavaTracking) {
val javaFilesChanges = javaFilesProcessor!!.process(changedFiles) val javaFilesChanges = javaFilesProcessor!!.process(changedFiles)
val affectedJavaSymbols = when (javaFilesChanges) { val affectedJavaSymbols = when (javaFilesChanges) {
@@ -256,10 +256,10 @@ open class IncrementalJvmCompilerRunner(
} }
} }
val androidLayoutChanges = reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_ANDROID_LAYOUTS) { val androidLayoutChanges = reporter.measure(GradleBuildTime.IC_ANALYZE_CHANGES_IN_ANDROID_LAYOUTS) {
processLookupSymbolsForAndroidLayouts(changedFiles) processLookupSymbolsForAndroidLayouts(changedFiles)
} }
val removedClassesChanges = reporter.measure(BuildTime.IC_DETECT_REMOVED_CLASSES) { val removedClassesChanges = reporter.measure(GradleBuildTime.IC_DETECT_REMOVED_CLASSES) {
getRemovedClassesChanges(caches, changedFiles) getRemovedClassesChanges(caches, changedFiles)
} }
@@ -468,7 +468,7 @@ open class IncrementalJvmCompilerRunner(
// No need to shrink and save classpath snapshot if exitCode != ExitCode.OK as the task will fail anyway // No need to shrink and save classpath snapshot if exitCode != ExitCode.OK as the task will fail anyway
if (classpathChanges is ClasspathChanges.ClasspathSnapshotEnabled && exitCode == ExitCode.OK) { if (classpathChanges is ClasspathChanges.ClasspathSnapshotEnabled && exitCode == ExitCode.OK) {
reporter.measure(BuildTime.SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION) { reporter.measure(GradleBuildTime.SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION) {
shrinkAndSaveClasspathSnapshot( shrinkAndSaveClasspathSnapshot(
compilationWasIncremental = compilationMode is CompilationMode.Incremental, classpathChanges, caches.lookupCache, compilationWasIncremental = compilationMode is CompilationMode.Incremental, classpathChanges, caches.lookupCache,
currentClasspathSnapshot, shrunkCurrentClasspathAgainstPreviousLookups, ClasspathSnapshotBuildReporter(reporter) currentClasspathSnapshot, shrunkCurrentClasspathAgainstPreviousLookups, ClasspathSnapshotBuildReporter(reporter)
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.build.report.BuildReporter import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.info import org.jetbrains.kotlin.build.report.info
import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
import org.jetbrains.kotlin.incremental.util.Either import org.jetbrains.kotlin.incremental.util.Either
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -20,7 +18,7 @@ internal fun getClasspathChanges(
changedFiles: ChangedFiles.Known, changedFiles: ChangedFiles.Known,
lastBuildInfo: BuildInfo, lastBuildInfo: BuildInfo,
modulesApiHistory: ModulesApiHistory, modulesApiHistory: ModulesApiHistory,
reporter: BuildReporter, reporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
abiSnapshots: Map<String, AbiSnapshot>, abiSnapshots: Map<String, AbiSnapshot>,
withSnapshot: Boolean, withSnapshot: Boolean,
caches: IncrementalCacheCommon, caches: IncrementalCacheCommon,
@@ -64,7 +62,7 @@ internal fun getClasspathChanges(
} }
return ChangesEither.Known(symbols, fqNames) return ChangesEither.Known(symbols, fqNames)
} }
return reporter.measure(BuildTime.IC_ANALYZE_JAR_FILES) { return reporter.measure(GradleBuildTime.IC_ANALYZE_JAR_FILES) {
analyzeJarFiles() analyzeJarFiles()
} }
} else { } else {
@@ -74,7 +72,7 @@ internal fun getClasspathChanges(
val fqNames = HashSet<FqName>() val fqNames = HashSet<FqName>()
val historyFilesEither = val historyFilesEither =
reporter.measure(BuildTime.IC_FIND_HISTORY_FILES) { reporter.measure(GradleBuildTime.IC_FIND_HISTORY_FILES) {
modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath) modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
} }
@@ -116,7 +114,7 @@ internal fun getClasspathChanges(
return ChangesEither.Known(symbols, fqNames) return ChangesEither.Known(symbols, fqNames)
} }
return reporter.measure(BuildTime.IC_ANALYZE_HISTORY_FILES) { return reporter.measure(GradleBuildTime.IC_ANALYZE_HISTORY_FILES) {
analyzeHistoryFiles() analyzeHistoryFiles()
} }
} }
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.incremental.classpathDiff
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.build.report.DoNothingICReporter import org.jetbrains.kotlin.build.report.DoNothingICReporter
import org.jetbrains.kotlin.build.report.debug import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.classpathDiff.BreadthFirstSearch.findReachableNodes import org.jetbrains.kotlin.incremental.classpathDiff.BreadthFirstSearch.findReachableNodes
import org.jetbrains.kotlin.incremental.classpathDiff.ClasspathSnapshotShrinker.shrinkClasspath import org.jetbrains.kotlin.incremental.classpathDiff.ClasspathSnapshotShrinker.shrinkClasspath
@@ -39,19 +37,19 @@ object ClasspathChangesComputer {
storeCurrentClasspathSnapshotForReuse: (currentClasspathSnapshot: List<AccessibleClassSnapshot>, shrunkCurrentClasspathAgainstPreviousLookups: List<AccessibleClassSnapshot>) -> Unit, storeCurrentClasspathSnapshotForReuse: (currentClasspathSnapshot: List<AccessibleClassSnapshot>, shrunkCurrentClasspathAgainstPreviousLookups: List<AccessibleClassSnapshot>) -> Unit,
reporter: ClasspathSnapshotBuildReporter reporter: ClasspathSnapshotBuildReporter
): ProgramSymbolSet { ): ProgramSymbolSet {
val currentClasspathSnapshot = reporter.measure(BuildTime.LOAD_CURRENT_CLASSPATH_SNAPSHOT) { val currentClasspathSnapshot = reporter.measure(GradleBuildTime.LOAD_CURRENT_CLASSPATH_SNAPSHOT) {
val classpathSnapshot = val classpathSnapshot =
CachedClasspathSnapshotSerializer.load(classpathSnapshotFiles.currentClasspathEntrySnapshotFiles, reporter) CachedClasspathSnapshotSerializer.load(classpathSnapshotFiles.currentClasspathEntrySnapshotFiles, reporter)
reporter.measure(BuildTime.REMOVE_DUPLICATE_CLASSES) { reporter.measure(GradleBuildTime.REMOVE_DUPLICATE_CLASSES) {
classpathSnapshot.removeDuplicateAndInaccessibleClasses() classpathSnapshot.removeDuplicateAndInaccessibleClasses()
} }
} }
val shrunkCurrentClasspathAgainstPreviousLookups = reporter.measure(BuildTime.SHRINK_CURRENT_CLASSPATH_SNAPSHOT) { val shrunkCurrentClasspathAgainstPreviousLookups = reporter.measure(GradleBuildTime.SHRINK_CURRENT_CLASSPATH_SNAPSHOT) {
shrinkClasspath( shrinkClasspath(
currentClasspathSnapshot, lookupStorage, currentClasspathSnapshot, lookupStorage,
ClasspathSnapshotShrinker.MetricsReporter( ClasspathSnapshotShrinker.MetricsReporter(
reporter, reporter,
BuildTime.GET_LOOKUP_SYMBOLS, BuildTime.FIND_REFERENCED_CLASSES, BuildTime.FIND_TRANSITIVELY_REFERENCED_CLASSES GradleBuildTime.GET_LOOKUP_SYMBOLS, GradleBuildTime.FIND_REFERENCED_CLASSES, GradleBuildTime.FIND_TRANSITIVELY_REFERENCED_CLASSES
) )
) )
} }
@@ -61,14 +59,14 @@ object ClasspathChangesComputer {
} }
storeCurrentClasspathSnapshotForReuse(currentClasspathSnapshot, shrunkCurrentClasspathAgainstPreviousLookups) storeCurrentClasspathSnapshotForReuse(currentClasspathSnapshot, shrunkCurrentClasspathAgainstPreviousLookups)
val shrunkPreviousClasspathSnapshot = reporter.measure(BuildTime.LOAD_SHRUNK_PREVIOUS_CLASSPATH_SNAPSHOT) { val shrunkPreviousClasspathSnapshot = reporter.measure(GradleBuildTime.LOAD_SHRUNK_PREVIOUS_CLASSPATH_SNAPSHOT) {
ListExternalizer(AccessibleClassSnapshotExternalizer).loadFromFile(classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile) ListExternalizer(AccessibleClassSnapshotExternalizer).loadFromFile(classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile)
} }
reporter.debug { reporter.debug {
"Loaded shrunk previous classpath snapshot for diffing, found ${shrunkPreviousClasspathSnapshot.size} classes" "Loaded shrunk previous classpath snapshot for diffing, found ${shrunkPreviousClasspathSnapshot.size} classes"
} }
return reporter.measure(BuildTime.COMPUTE_CHANGED_AND_IMPACTED_SET) { return reporter.measure(GradleBuildTime.COMPUTE_CHANGED_AND_IMPACTED_SET) {
computeChangedAndImpactedSet(shrunkCurrentClasspathAgainstPreviousLookups, shrunkPreviousClasspathSnapshot, reporter) computeChangedAndImpactedSet(shrunkCurrentClasspathAgainstPreviousLookups, shrunkPreviousClasspathSnapshot, reporter)
} }
} }
@@ -100,7 +98,7 @@ object ClasspathChangesComputer {
} else null } else null
} }
val changedSet = reporter.measure(BuildTime.COMPUTE_CLASS_CHANGES) { val changedSet = reporter.measure(GradleBuildTime.COMPUTE_CLASS_CHANGES) {
computeClassChanges(changedCurrentClasses, changedPreviousClasses, reporter) computeClassChanges(changedCurrentClasses, changedPreviousClasses, reporter)
} }
reporter.reportVerboseWithLimit { "Changed set = ${changedSet.toDebugString()}" } reporter.reportVerboseWithLimit { "Changed set = ${changedSet.toDebugString()}" }
@@ -109,7 +107,7 @@ object ClasspathChangesComputer {
return changedSet return changedSet
} }
val changedAndImpactedSet = reporter.measure(BuildTime.COMPUTE_IMPACTED_SET) { val changedAndImpactedSet = reporter.measure(GradleBuildTime.COMPUTE_IMPACTED_SET) {
// Note that changes may contain added symbols (they can also impact recompilation -- see examples in JavaClassChangesComputer). // Note that changes may contain added symbols (they can also impact recompilation -- see examples in JavaClassChangesComputer).
// So ideally, the result should be: // So ideally, the result should be:
// computeImpactedSymbols(changes = changesOnPreviousClasspath, allClasses = classesOnPreviousClasspath) + // computeImpactedSymbols(changes = changesOnPreviousClasspath, allClasses = classesOnPreviousClasspath) +
@@ -144,13 +142,13 @@ object ClasspathChangesComputer {
private fun computeClassChanges( private fun computeClassChanges(
currentClassSnapshots: List<AccessibleClassSnapshot>, currentClassSnapshots: List<AccessibleClassSnapshot>,
previousClassSnapshots: List<AccessibleClassSnapshot>, previousClassSnapshots: List<AccessibleClassSnapshot>,
metrics: BuildMetricsReporter metrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>
): ProgramSymbolSet { ): ProgramSymbolSet {
val (currentKotlinClassSnapshots, currentJavaClassSnapshots) = currentClassSnapshots.partition { it is KotlinClassSnapshot } val (currentKotlinClassSnapshots, currentJavaClassSnapshots) = currentClassSnapshots.partition { it is KotlinClassSnapshot }
val (previousKotlinClassSnapshots, previousJavaClassSnapshots) = previousClassSnapshots.partition { it is KotlinClassSnapshot } val (previousKotlinClassSnapshots, previousJavaClassSnapshots) = previousClassSnapshots.partition { it is KotlinClassSnapshot }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val kotlinClassChanges = metrics.measure(BuildTime.COMPUTE_KOTLIN_CLASS_CHANGES) { val kotlinClassChanges = metrics.measure(GradleBuildTime.COMPUTE_KOTLIN_CLASS_CHANGES) {
computeKotlinClassChanges( computeKotlinClassChanges(
currentKotlinClassSnapshots as List<KotlinClassSnapshot>, currentKotlinClassSnapshots as List<KotlinClassSnapshot>,
previousKotlinClassSnapshots as List<KotlinClassSnapshot> previousKotlinClassSnapshots as List<KotlinClassSnapshot>
@@ -158,7 +156,7 @@ object ClasspathChangesComputer {
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val javaClassChanges = metrics.measure(BuildTime.COMPUTE_JAVA_CLASS_CHANGES) { val javaClassChanges = metrics.measure(GradleBuildTime.COMPUTE_JAVA_CLASS_CHANGES) {
JavaClassChangesComputer.compute( JavaClassChangesComputer.compute(
currentJavaClassSnapshots as List<JavaClassSnapshot>, currentJavaClassSnapshots as List<JavaClassSnapshot>,
previousJavaClassSnapshots as List<JavaClassSnapshot> previousJavaClassSnapshots as List<JavaClassSnapshot>
@@ -9,9 +9,11 @@ import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.ICReporter import org.jetbrains.kotlin.build.report.ICReporter
import org.jetbrains.kotlin.build.report.debug import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
class ClasspathSnapshotBuildReporter(private val buildReporter: BuildReporter) : class ClasspathSnapshotBuildReporter(private val buildReporter: BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>) :
ICReporter by buildReporter, BuildMetricsReporter by buildReporter { ICReporter by buildReporter, BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric> by buildReporter {
override fun report(message: () -> String, severity: ICReporter.ReportSeverity) { override fun report(message: () -> String, severity: ICReporter.ReportSeverity) {
buildReporter.report({ "[ClasspathSnapshot] ${message()}" }, severity) buildReporter.report({ "[ClasspathSnapshot] ${message()}" }, severity)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.incremental.classpathDiff
import com.intellij.util.containers.Interner import com.intellij.util.containers.Interner
import com.intellij.util.io.DataExternalizer import com.intellij.util.io.DataExternalizer
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.incremental.KotlinClassInfo import org.jetbrains.kotlin.incremental.KotlinClassInfo
import org.jetbrains.kotlin.incremental.storage.* import org.jetbrains.kotlin.incremental.storage.*
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -45,9 +46,9 @@ object CachedClasspathSnapshotSerializer {
}) })
cache.evictEntries() cache.evictEntries()
reporter.addMetric(BuildPerformanceMetric.LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, 1) reporter.addMetric(GradleBuildPerformanceMetric.LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, 1)
reporter.addMetric(BuildPerformanceMetric.LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_HITS, classpathEntrySnapshotFiles.size - cacheMisses) reporter.addMetric(GradleBuildPerformanceMetric.LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_HITS, classpathEntrySnapshotFiles.size - cacheMisses)
reporter.addMetric(BuildPerformanceMetric.LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_MISSES, cacheMisses) reporter.addMetric(GradleBuildPerformanceMetric.LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_MISSES, cacheMisses)
return classpathSnapshot return classpathSnapshot
} }
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.incremental.classpathDiff package org.jetbrains.kotlin.incremental.classpathDiff
import org.jetbrains.kotlin.build.report.debug import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.incremental.ClasspathChanges import org.jetbrains.kotlin.incremental.ClasspathChanges
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.NoChanges import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.NoChanges
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.ToBeComputedByIncrementalCompiler import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.ToBeComputedByIncrementalCompiler
@@ -117,10 +114,10 @@ object ClasspathSnapshotShrinker {
* record different [BuildTime]s (because the [BuildTime.parent]s are different). * record different [BuildTime]s (because the [BuildTime.parent]s are different).
*/ */
class MetricsReporter( class MetricsReporter(
private val metrics: BuildMetricsReporter? = null, private val metrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>? = null,
private val getLookupSymbols: BuildTime? = null, private val getLookupSymbols: GradleBuildTime? = null,
private val findReferencedClasses: BuildTime? = null, private val findReferencedClasses: GradleBuildTime? = null,
private val findTransitivelyReferencedClasses: BuildTime? = null private val findTransitivelyReferencedClasses: GradleBuildTime? = null
) { ) {
fun <T> getLookupSymbols(fn: () -> T) = metrics?.measure(getLookupSymbols!!, fn) ?: fn() fun <T> getLookupSymbols(fn: () -> T) = metrics?.measure(getLookupSymbols!!, fn) ?: fn()
fun <T> findReferencedClasses(fn: () -> T) = metrics?.measure(findReferencedClasses!!, fn) ?: fn() fun <T> findReferencedClasses(fn: () -> T) = metrics?.measure(findReferencedClasses!!, fn) ?: fn()
@@ -246,9 +243,9 @@ internal fun shrinkAndSaveClasspathSnapshot(
// shrunkCurrentClasspathAgainst[*Current*]Lookups == shrunkCurrentClasspathAgainst[*Previous*]Lookups // shrunkCurrentClasspathAgainst[*Current*]Lookups == shrunkCurrentClasspathAgainst[*Previous*]Lookups
shrinkMode.currentClasspathSnapshot to shrinkMode.shrunkCurrentClasspathAgainstPreviousLookups shrinkMode.currentClasspathSnapshot to shrinkMode.shrunkCurrentClasspathAgainstPreviousLookups
} }
is ShrinkMode.ChangedLookups -> reporter.measure(BuildTime.INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT) { is ShrinkMode.ChangedLookups -> reporter.measure(GradleBuildTime.INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT) {
// There are changes in the lookups, so we will shrink incrementally. // There are changes in the lookups, so we will shrink incrementally.
val currentClasspath = reporter.measure(BuildTime.INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT) { val currentClasspath = reporter.measure(GradleBuildTime.INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT) {
when (shrinkMode) { when (shrinkMode) {
is ShrinkMode.ChangedLookupsUnchangedClasspath -> is ShrinkMode.ChangedLookupsUnchangedClasspath ->
CachedClasspathSnapshotSerializer CachedClasspathSnapshotSerializer
@@ -258,7 +255,7 @@ internal fun shrinkAndSaveClasspathSnapshot(
} }
} }
val shrunkCurrentClasspathAgainstPrevLookups = val shrunkCurrentClasspathAgainstPrevLookups =
reporter.measure(BuildTime.INCREMENTAL_LOAD_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT_AGAINST_PREVIOUS_LOOKUPS) { reporter.measure(GradleBuildTime.INCREMENTAL_LOAD_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT_AGAINST_PREVIOUS_LOOKUPS) {
when (shrinkMode) { when (shrinkMode) {
is ShrinkMode.ChangedLookupsUnchangedClasspath -> { is ShrinkMode.ChangedLookupsUnchangedClasspath -> {
// There are no changes in the classpath, so // There are no changes in the classpath, so
@@ -279,8 +276,8 @@ internal fun shrinkAndSaveClasspathSnapshot(
} }
is ShrinkMode.NonIncremental -> { is ShrinkMode.NonIncremental -> {
// Changes in the lookups and classpath are not available, so we will shrink non-incrementally. // Changes in the lookups and classpath are not available, so we will shrink non-incrementally.
reporter.measure(BuildTime.NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT) { reporter.measure(GradleBuildTime.NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT) {
val currentClasspath = reporter.measure(BuildTime.NON_INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT) { val currentClasspath = reporter.measure(GradleBuildTime.NON_INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT) {
CachedClasspathSnapshotSerializer CachedClasspathSnapshotSerializer
.load(classpathChanges.classpathSnapshotFiles.currentClasspathEntrySnapshotFiles, reporter) .load(classpathChanges.classpathSnapshotFiles.currentClasspathEntrySnapshotFiles, reporter)
.removeDuplicateAndInaccessibleClasses() .removeDuplicateAndInaccessibleClasses()
@@ -298,7 +295,7 @@ internal fun shrinkAndSaveClasspathSnapshot(
"File '${classpathChanges.classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile.path}' does not exist" "File '${classpathChanges.classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile.path}' does not exist"
} }
} else { } else {
reporter.measure(BuildTime.SAVE_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT) { reporter.measure(GradleBuildTime.SAVE_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT) {
ListExternalizer(AccessibleClassSnapshotExternalizer).saveToFile( ListExternalizer(AccessibleClassSnapshotExternalizer).saveToFile(
classpathChanges.classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile, classpathChanges.classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile,
shrunkCurrentClasspath!! shrunkCurrentClasspath!!
@@ -313,17 +310,17 @@ internal fun shrinkAndSaveClasspathSnapshot(
} }
} }
reporter.addMetric(BuildPerformanceMetric.SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, 1) reporter.addMetric(GradleBuildPerformanceMetric.SHRINK_AND_SAVE_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, 1)
reporter.addMetric( reporter.addMetric(
BuildPerformanceMetric.CLASSPATH_ENTRY_COUNT, GradleBuildPerformanceMetric.CLASSPATH_ENTRY_COUNT,
classpathChanges.classpathSnapshotFiles.currentClasspathEntrySnapshotFiles.size.toLong() classpathChanges.classpathSnapshotFiles.currentClasspathEntrySnapshotFiles.size.toLong()
) )
reporter.addMetric( reporter.addMetric(
BuildPerformanceMetric.CLASSPATH_SNAPSHOT_SIZE, GradleBuildPerformanceMetric.CLASSPATH_SNAPSHOT_SIZE,
classpathChanges.classpathSnapshotFiles.currentClasspathEntrySnapshotFiles.sumOf { it.length() } classpathChanges.classpathSnapshotFiles.currentClasspathEntrySnapshotFiles.sumOf { it.length() }
) )
reporter.addMetric( reporter.addMetric(
BuildPerformanceMetric.SHRUNK_CLASSPATH_SNAPSHOT_SIZE, GradleBuildPerformanceMetric.SHRUNK_CLASSPATH_SNAPSHOT_SIZE,
classpathChanges.classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile.length() classpathChanges.classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile.length()
) )
} }
@@ -5,10 +5,7 @@
package org.jetbrains.kotlin.incremental.classpathDiff package org.jetbrains.kotlin.incremental.classpathDiff
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.snapshotClass import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.snapshotClass
import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.snapshotClassExcludingMembers import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.snapshotClassExcludingMembers
import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.snapshotField import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.snapshotField
@@ -44,10 +41,10 @@ object ClasspathEntrySnapshotter {
fun snapshot( fun snapshot(
classpathEntry: File, classpathEntry: File,
granularity: ClassSnapshotGranularity, granularity: ClassSnapshotGranularity,
metrics: BuildMetricsReporter = DoNothingBuildMetricsReporter metrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric> = DoNothingBuildMetricsReporter
): ClasspathEntrySnapshot { ): ClasspathEntrySnapshot {
DirectoryOrJarReader.create(classpathEntry).use { directoryOrJarReader -> DirectoryOrJarReader.create(classpathEntry).use { directoryOrJarReader ->
val classes = metrics.measure(BuildTime.LOAD_CLASSES_PATHS_ONLY) { val classes = metrics.measure(GradleBuildTime.LOAD_CLASSES_PATHS_ONLY) {
directoryOrJarReader.getUnixStyleRelativePaths(DEFAULT_CLASS_FILTER).map { unixStyleRelativePath -> directoryOrJarReader.getUnixStyleRelativePaths(DEFAULT_CLASS_FILTER).map { unixStyleRelativePath ->
ClassFileWithContentsProvider( ClassFileWithContentsProvider(
classFile = ClassFile(classpathEntry, unixStyleRelativePath), classFile = ClassFile(classpathEntry, unixStyleRelativePath),
@@ -55,7 +52,7 @@ object ClasspathEntrySnapshotter {
) )
} }
} }
val snapshots = metrics.measure(BuildTime.SNAPSHOT_CLASSES) { val snapshots = metrics.measure(GradleBuildTime.SNAPSHOT_CLASSES) {
ClassSnapshotter.snapshot(classes, granularity, metrics) ClassSnapshotter.snapshot(classes, granularity, metrics)
} }
return ClasspathEntrySnapshot( return ClasspathEntrySnapshot(
@@ -71,7 +68,7 @@ object ClassSnapshotter {
fun snapshot( fun snapshot(
classes: List<ClassFileWithContentsProvider>, classes: List<ClassFileWithContentsProvider>,
granularity: ClassSnapshotGranularity, granularity: ClassSnapshotGranularity,
metrics: BuildMetricsReporter = DoNothingBuildMetricsReporter metrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric> = DoNothingBuildMetricsReporter
): List<ClassSnapshot> { ): List<ClassSnapshot> {
fun ClassFile.getClassName(): JvmClassName { fun ClassFile.getClassName(): JvmClassName {
check(unixStyleRelativePath.endsWith(".class", ignoreCase = true)) check(unixStyleRelativePath.endsWith(".class", ignoreCase = true))
@@ -83,7 +80,7 @@ object ClassSnapshotter {
fun snapshotClass(classFile: ClassFileWithContentsProvider): ClassSnapshot { fun snapshotClass(classFile: ClassFileWithContentsProvider): ClassSnapshot {
return classFileToSnapshotMap.getOrPut(classFile) { return classFileToSnapshotMap.getOrPut(classFile) {
val clazz = metrics.measure(BuildTime.LOAD_CONTENTS_OF_CLASSES) { val clazz = metrics.measure(GradleBuildTime.LOAD_CONTENTS_OF_CLASSES) {
classFile.loadContents() classFile.loadContents()
} }
// Snapshot outer class first as we need this info to determine whether a class is transitively inaccessible (see below) // Snapshot outer class first as we need this info to determine whether a class is transitively inaccessible (see below)
@@ -98,10 +95,10 @@ object ClassSnapshotter {
clazz.classInfo.isInaccessible() || outerClassSnapshot is InaccessibleClassSnapshot -> { clazz.classInfo.isInaccessible() || outerClassSnapshot is InaccessibleClassSnapshot -> {
InaccessibleClassSnapshot InaccessibleClassSnapshot
} }
clazz.classInfo.isKotlinClass -> metrics.measure(BuildTime.SNAPSHOT_KOTLIN_CLASSES) { clazz.classInfo.isKotlinClass -> metrics.measure(GradleBuildTime.SNAPSHOT_KOTLIN_CLASSES) {
snapshotKotlinClass(clazz, granularity) snapshotKotlinClass(clazz, granularity)
} }
else -> metrics.measure(BuildTime.SNAPSHOT_JAVA_CLASSES) { else -> metrics.measure(GradleBuildTime.SNAPSHOT_JAVA_CLASSES) {
snapshotJavaClass(clazz, granularity) snapshotJavaClass(clazz, granularity)
} }
} }
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.incremental.utils
import org.jetbrains.kotlin.build.report.BuildReporter import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
class TestBuildReporter( class TestBuildReporter(
val testICReporter: TestICReporter, val testICReporter: TestICReporter,
buildMetricsReporter: BuildMetricsReporter buildMetricsReporter: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>
) : BuildReporter(testICReporter, buildMetricsReporter) { ) : BuildReporter<GradleBuildTime, GradleBuildPerformanceMetric>(testICReporter, buildMetricsReporter) {
fun reportCachesDump(cachesDump: String) { fun reportCachesDump(cachesDump: String) {
testICReporter.cachesDump = cachesDump testICReporter.cachesDump = cachesDump
} }
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.build.GeneratedJvmClass
import org.jetbrains.kotlin.build.report.ICReporter.ReportSeverity import org.jetbrains.kotlin.build.report.ICReporter.ReportSeverity
import org.jetbrains.kotlin.build.report.ICReporterBase import org.jetbrains.kotlin.build.report.ICReporterBase
import org.jetbrains.kotlin.build.report.debug import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.JpsBuildTime
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
@@ -323,12 +325,12 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val proposedExitCode = val proposedExitCode =
doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations) doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations)
val actualExitCode = if (proposedExitCode == OK && fsOperations.hasMarkedDirty) ADDITIONAL_PASS_REQUIRED else proposedExitCode val actualExitCode =
if (proposedExitCode == OK && fsOperations.hasMarkedDirty) ADDITIONAL_PASS_REQUIRED else proposedExitCode
LOG.debug("Build result: $actualExitCode") LOG.debug("Build result: $actualExitCode")
context.testingContext?.buildLogger?.buildFinished(actualExitCode) context.testingContext?.buildLogger?.buildFinished(actualExitCode)
return actualExitCode return actualExitCode
} catch (e: StopBuildException) { } catch (e: StopBuildException) {
LOG.info("Caught exception: $e") LOG.info("Caught exception: $e")
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2023 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.jps.statistic
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
import org.jetbrains.kotlin.build.report.metrics.JpsBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.JpsBuildTime
import org.jetbrains.kotlin.build.report.statistics.CompileStatisticsData
import org.jetbrains.kotlin.build.report.statistics.StatTag
class JpsCompileStatisticsData(
private val projectName: String?,
private val label: String?,
private val taskName: String,
private val taskResult: String?,
private val startTimeMs: Long,
private val durationMs: Long,
private val tags: Set<StatTag>,
private val changes: List<String>,
private val buildUuid: String = "Unset",
private val kotlinVersion: String,
private val kotlinLanguageVersion: String?,
private val hostName: String? = "Unset",
private val finishTime: Long,
private val compilerArguments: List<String>,
private val nonIncrementalAttributes: Set<BuildAttribute>,
private val buildTimesMetrics: Map<JpsBuildTime, Long>,
private val performanceMetrics: Map<JpsBuildPerformanceMetric, Long>,
private val gcTimeMetrics: Map<String, Long>?,
private val gcCountMetrics: Map<String, Long>?,
private val type: String,
private val fromKotlinPlugin: Boolean?,
private val compiledSources: List<String> = emptyList(),
private val skipMessage: String?,
private val icLogLines: List<String>,
) : CompileStatisticsData<JpsBuildTime, JpsBuildPerformanceMetric> {
override fun getProjectName(): String? = projectName
override fun getLabel(): String? = label
override fun getTaskName(): String = taskName
override fun getTaskResult(): String? = taskResult
override fun getStartTimeMs(): Long = startTimeMs
override fun getDurationMs(): Long = durationMs
override fun getTags(): Set<StatTag> = tags
override fun getChanges(): List<String> = changes
override fun getKotlinVersion(): String = kotlinVersion
override fun getKotlinLanguageVersion(): String? = kotlinLanguageVersion
override fun getFinishTime(): Long = finishTime
override fun getCompilerArguments(): List<String> = compilerArguments
override fun getNonIncrementalAttributes(): Set<BuildAttribute> = nonIncrementalAttributes
override fun getBuildTimesMetrics(): Map<JpsBuildTime, Long> = buildTimesMetrics
override fun getPerformanceMetrics(): Map<JpsBuildPerformanceMetric, Long> = performanceMetrics
override fun getGcTimeMetrics(): Map<String, Long>? = gcTimeMetrics
override fun getGcCountMetrics(): Map<String, Long>? = gcCountMetrics
override fun getFromKotlinPlugin(): Boolean? = fromKotlinPlugin
override fun getSkipMessage(): String? = skipMessage
override fun getIcLogLines(): List<String> = icLogLines
}
@@ -17,13 +17,13 @@ import java.io.File
import java.util.* import java.util.*
import java.net.InetAddress import java.net.InetAddress
interface JpsBuilderMetricReporter : BuildMetricsReporter { interface JpsBuilderMetricReporter : BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> {
fun flush(context: CompileContext): CompileStatisticsData fun flush(context: CompileContext): JpsCompileStatisticsData
} }
private const val jpsBuildTaskName = "JPS build" private const val jpsBuildTaskName = "JPS build"
class JpsBuilderMetricReporterImpl(private val reporter: BuildMetricsReporterImpl) : JpsBuilderMetricReporter, BuildMetricsReporter by reporter { class JpsBuilderMetricReporterImpl(private val reporter: BuildMetricsReporterImpl<JpsBuildTime, JpsBuildPerformanceMetric>) : JpsBuilderMetricReporter, BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> by reporter {
companion object { companion object {
private val hostName: String? = try { private val hostName: String? = try {
@@ -37,9 +37,10 @@ class JpsBuilderMetricReporterImpl(private val reporter: BuildMetricsReporterImp
private val uuid = UUID.randomUUID() private val uuid = UUID.randomUUID()
private val startTime = System.currentTimeMillis() private val startTime = System.currentTimeMillis()
override fun flush(context: CompileContext): CompileStatisticsData { @Suppress("UNCHECKED_CAST")
override fun flush(context: CompileContext): JpsCompileStatisticsData {
val buildMetrics = reporter.getMetrics() val buildMetrics = reporter.getMetrics()
return CompileStatisticsData( return JpsCompileStatisticsData(
projectName = context.projectDescriptor.project.name, projectName = context.projectDescriptor.project.name,
label = "JPS build", //TODO will be updated in KT-58026 label = "JPS build", //TODO will be updated in KT-58026
taskName = jpsBuildTaskName, taskName = jpsBuildTaskName,
@@ -98,7 +99,7 @@ class JpsStatisticsReportService {
if (contextMetrics[context] != null) { if (contextMetrics[context] != null) {
log.error("Service already initialized for context") log.error("Service already initialized for context")
} }
contextMetrics[context] = JpsBuilderMetricReporterImpl(BuildMetricsReporterImpl()) contextMetrics[context] = JpsBuilderMetricReporterImpl(BuildMetricsReporterImpl<JpsBuildTime, JpsBuildPerformanceMetric>())
} }
fun buildFinished(context: CompileContext) { fun buildFinished(context: CompileContext) {
@@ -111,11 +112,23 @@ class JpsStatisticsReportService {
val compileStatisticsData = metrics.flush(context) val compileStatisticsData = metrics.flush(context)
httpService?.sendData(compileStatisticsData, loggerAdapter) httpService?.sendData(compileStatisticsData, loggerAdapter)
fileReportSettings?.also { fileReportSettings?.also {
FileReportService(it.buildReportDir, true, loggerAdapter) FileReportService<JpsBuildTime, JpsBuildPerformanceMetric>(it.buildReportDir, true, loggerAdapter)
.process(listOf(compileStatisticsData), .process(
BuildStartParameters(tasks = listOf(jpsBuildTaskName))) listOf(compileStatisticsData),
BuildStartParameters(tasks = listOf(jpsBuildTaskName))
)
} }
} }
fun <T> reportMetrics(context: CompileContext, metric: JpsBuildTime, action: () -> T): T {
val metrics = contextMetrics.remove(context)
if (metrics == null) {
log.error("Service hasn't initialized for context")
return action.invoke()
}
return metrics.measure(metric, action)
}
} }
@@ -20,6 +20,7 @@ import io.ktor.util.collections.*
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.build.report.statistics.* import org.jetbrains.kotlin.build.report.statistics.*
import org.jetbrains.kotlin.gradle.report.BuildReportType import org.jetbrains.kotlin.gradle.report.BuildReportType
import org.jetbrains.kotlin.gradle.report.data.GradleCompileStatisticsData
import org.jetbrains.kotlin.gradle.testbase.* import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import java.io.IOException import java.io.IOException
@@ -129,11 +130,11 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
} }
} }
fun validateTaskData(port: Int, validate: (CompileStatisticsData) -> Unit) { fun validateTaskData(port: Int, validate: (GradleCompileStatisticsData) -> Unit) {
validateCall(port) { jsonObject -> validateCall(port) { jsonObject ->
val type = jsonObject["type"].asString val type = jsonObject["type"].asString
assertEquals(BuildDataType.TASK_DATA, BuildDataType.valueOf(type)) assertEquals(BuildDataType.TASK_DATA, BuildDataType.valueOf(type))
val taskData = Gson().fromJson(jsonObject, CompileStatisticsData::class.java) val taskData = Gson().fromJson(jsonObject, GradleCompileStatisticsData::class.java)
validate(taskData) validate(taskData)
} }
} }
@@ -165,7 +166,7 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
private fun simpleTestHttpReport( private fun simpleTestHttpReport(
gradleVersion: GradleVersion, gradleVersion: GradleVersion,
additionalProjectSetup: (TestProject) -> Unit = {}, additionalProjectSetup: (TestProject) -> Unit = {},
compileTaskAssertions: (CompileStatisticsData) -> Unit, compileTaskAssertions: (GradleCompileStatisticsData) -> Unit,
) { ) {
runWithKtorService { port -> runWithKtorService { port ->
project("incrementalMultiproject", gradleVersion) { project("incrementalMultiproject", gradleVersion) {
@@ -176,11 +177,11 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
} }
} }
validateTaskData(port) { taskData -> validateTaskData(port) { taskData ->
assertEquals(":lib:compileKotlin", taskData.taskName) assertEquals(":lib:compileKotlin", taskData.getTaskName())
compileTaskAssertions(taskData) compileTaskAssertions(taskData)
} }
validateTaskData(port) { taskData -> validateTaskData(port) { taskData ->
assertEquals(":app:compileKotlin", taskData.taskName) assertEquals(":app:compileKotlin", taskData.getTaskName())
compileTaskAssertions(taskData) compileTaskAssertions(taskData)
} }
validateBuildData(port) { buildData -> validateBuildData(port) { buildData ->
@@ -193,14 +194,14 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
@GradleTest @GradleTest
fun testHttpRequest(gradleVersion: GradleVersion) { fun testHttpRequest(gradleVersion: GradleVersion) {
simpleTestHttpReport(gradleVersion) { taskData -> simpleTestHttpReport(gradleVersion) { taskData ->
assertContains(taskData.tags, StatTag.NON_INCREMENTAL) assertContains(taskData.getTags(), StatTag.NON_INCREMENTAL)
assertContains(taskData.nonIncrementalAttributes.map { it.name }, "UNKNOWN_CHANGES_IN_GRADLE_INPUTS") assertContains(taskData.getNonIncrementalAttributes().map { it.name }, "UNKNOWN_CHANGES_IN_GRADLE_INPUTS")
assertFalse(taskData.performanceMetrics.keys.isEmpty()) assertFalse(taskData.getPerformanceMetrics().keys.isEmpty())
assertFalse(taskData.buildTimesMetrics.keys.isEmpty()) assertFalse(taskData.getBuildTimesMetrics().keys.isEmpty())
assertFalse(taskData.compilerArguments.isEmpty()) assertFalse(taskData.getCompilerArguments().isEmpty())
assertEquals( assertEquals(
defaultBuildOptions.kotlinVersion, taskData.kotlinVersion, defaultBuildOptions.kotlinVersion, taskData.getKotlinVersion(),
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}" "Unexpected kotlinVersion: ${taskData.getKotlinVersion()} instead of ${defaultBuildOptions.kotlinVersion}"
) )
} }
} }
@@ -216,14 +217,14 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
""".trimMargin() """.trimMargin()
) )
}) { taskData -> }) { taskData ->
assertContains(taskData.tags, StatTag.NON_INCREMENTAL) assertContains(taskData.getTags(), StatTag.NON_INCREMENTAL)
assertContains(taskData.nonIncrementalAttributes.map { it.name }, "UNKNOWN_CHANGES_IN_GRADLE_INPUTS") assertContains(taskData.getNonIncrementalAttributes().map { it.name }, "UNKNOWN_CHANGES_IN_GRADLE_INPUTS")
assertFalse(taskData.performanceMetrics.keys.isEmpty()) assertFalse(taskData.getPerformanceMetrics().keys.isEmpty())
assertFalse(taskData.buildTimesMetrics.keys.isEmpty()) assertFalse(taskData.getBuildTimesMetrics().keys.isEmpty())
assertTrue(taskData.compilerArguments.isEmpty()) assertTrue(taskData.getCompilerArguments().isEmpty())
assertEquals( assertEquals(
defaultBuildOptions.kotlinVersion, taskData.kotlinVersion, defaultBuildOptions.kotlinVersion, taskData.getKotlinVersion(),
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}" "Unexpected kotlinVersion: ${taskData.getKotlinVersion()} instead of ${defaultBuildOptions.kotlinVersion}"
) )
} }
} }
@@ -245,26 +246,26 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
} }
} }
validateTaskData(port) { taskData -> validateTaskData(port) { taskData ->
assertEquals(":lib:compileKotlin", taskData.taskName) assertEquals(":lib:compileKotlin", taskData.getTaskName())
assertContentEquals( assertContentEquals(
listOf( listOf(
StatTag.ARTIFACT_TRANSFORM, StatTag.ARTIFACT_TRANSFORM,
StatTag.NON_INCREMENTAL, StatTag.NON_INCREMENTAL,
StatTag.CONFIGURATION_CACHE, StatTag.CONFIGURATION_CACHE,
StatTag.KOTLIN_1, StatTag.KOTLIN_1,
), taskData.tags.sorted(), ), taskData.getTags().sorted(),
) )
assertEquals( assertEquals(
defaultBuildOptions.kotlinVersion, taskData.kotlinVersion, defaultBuildOptions.kotlinVersion, taskData.getKotlinVersion(),
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}" "Unexpected kotlinVersion: ${taskData.getKotlinVersion()} instead of ${defaultBuildOptions.kotlinVersion}"
) )
} }
validateTaskData(port) { taskData -> validateTaskData(port) { taskData ->
assertEquals(":app:compileKotlin", taskData.taskName) assertEquals(":app:compileKotlin", taskData.getTaskName())
assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.NON_INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.tags.sorted()) assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.NON_INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.getTags().sorted())
assertEquals( assertEquals(
defaultBuildOptions.kotlinVersion, taskData.kotlinVersion, defaultBuildOptions.kotlinVersion, taskData.getKotlinVersion(),
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}" "Unexpected kotlinVersion: ${taskData.getKotlinVersion()} instead of ${defaultBuildOptions.kotlinVersion}"
) )
} }
validateBuildData(port) { buildData -> validateBuildData(port) { buildData ->
@@ -272,12 +273,12 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
} }
//second build //second build
validateTaskData(port) { taskData -> validateTaskData(port) { taskData ->
assertEquals(":lib:compileKotlin", taskData.taskName) assertEquals(":lib:compileKotlin", taskData.getTaskName())
assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.tags.sorted()) assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.getTags().sorted())
} }
validateTaskData(port) { taskData -> validateTaskData(port) { taskData ->
assertEquals(":app:compileKotlin", taskData.taskName) assertEquals(":app:compileKotlin", taskData.getTaskName())
assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.tags.sorted()) assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.getTags().sorted())
} }
} }
} }
@@ -1,8 +1,6 @@
package org.jetbrains.kotlin.compilerRunner package org.jetbrains.kotlin.compilerRunner
import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.buildtools.api.KotlinLogger import org.jetbrains.kotlin.buildtools.api.KotlinLogger
import org.jetbrains.kotlin.daemon.common.* import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.kotlinDebug
@@ -23,8 +21,8 @@ internal class GradleCompilationResults(
) { ) {
var icLogLines: List<String> = emptyList() var icLogLines: List<String> = emptyList()
private val buildMetricsReporter = BuildMetricsReporterImpl() private val buildMetricsReporter = BuildMetricsReporterImpl<GradleBuildTime, GradleBuildPerformanceMetric>()
val buildMetrics: BuildMetrics val buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>
get() = buildMetricsReporter.getMetrics() get() = buildMetricsReporter.getMetrics()
@Throws(RemoteException::class) @Throws(RemoteException::class)
@@ -37,7 +35,7 @@ internal class GradleCompilationResults(
val sourceFiles = compileIterationResult.sourceFiles val sourceFiles = compileIterationResult.sourceFiles
if (sourceFiles.any()) { if (sourceFiles.any()) {
log.kotlinDebug { "compile iteration: ${sourceFiles.pathsAsStringRelativeTo(projectRootFile)}" } log.kotlinDebug { "compile iteration: ${sourceFiles.pathsAsStringRelativeTo(projectRootFile)}" }
buildMetrics.buildPerformanceMetrics.add(BuildPerformanceMetric.COMPILE_ITERATION) buildMetrics.buildPerformanceMetrics.add(GradleBuildPerformanceMetric.COMPILE_ITERATION)
} }
val exitCode = compileIterationResult.exitCode val exitCode = compileIterationResult.exitCode
log.kotlinDebug { "compiler exit code: $exitCode" } log.kotlinDebug { "compiler exit code: $exitCode" }
@@ -49,7 +47,7 @@ internal class GradleCompilationResults(
(value as? List<String>)?.let { icLogLines = it } (value as? List<String>)?.let { icLogLines = it }
} }
CompilationResultCategory.BUILD_METRICS.code -> { CompilationResultCategory.BUILD_METRICS.code -> {
(value as? BuildMetrics)?.let { buildMetricsReporter.addMetrics(it) } (value as? BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>)?.let { buildMetricsReporter.addMetrics(it) }
} }
} }
} }
@@ -14,10 +14,7 @@ import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkQueue import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
@@ -29,7 +26,7 @@ internal class GradleCompilerRunnerWithWorkers(
taskProvider: GradleCompileTaskProvider, taskProvider: GradleCompileTaskProvider,
jdkToolsJar: File?, jdkToolsJar: File?,
compilerExecutionSettings: CompilerExecutionSettings, compilerExecutionSettings: CompilerExecutionSettings,
buildMetrics: BuildMetricsReporter, buildMetrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
private val workerExecutor: WorkerExecutor private val workerExecutor: WorkerExecutor
) : GradleCompilerRunner(taskProvider, jdkToolsJar, compilerExecutionSettings, buildMetrics) { ) : GradleCompilerRunner(taskProvider, jdkToolsJar, compilerExecutionSettings, buildMetrics) {
override fun runCompilerAsync( override fun runCompilerAsync(
@@ -37,7 +34,7 @@ internal class GradleCompilerRunnerWithWorkers(
taskOutputsBackup: TaskOutputsBackup? taskOutputsBackup: TaskOutputsBackup?
): WorkQueue { ): WorkQueue {
buildMetrics.addTimeMetric(BuildPerformanceMetric.CALL_WORKER) buildMetrics.addTimeMetric(GradleBuildPerformanceMetric.CALL_WORKER)
val workQueue = workerExecutor.noIsolation() val workQueue = workerExecutor.noIsolation()
workQueue.submit(GradleKotlinCompilerWorkAction::class.java) { params -> workQueue.submit(GradleKotlinCompilerWorkAction::class.java) { params ->
params.compilerWorkArguments.set(workArgs) params.compilerWorkArguments.set(workArgs)
@@ -82,7 +79,7 @@ internal class GradleCompilerRunnerWithWorkers(
// Otherwise, the next build(s) will likely fail in exactly the same way as this build because their inputs and outputs are // Otherwise, the next build(s) will likely fail in exactly the same way as this build because their inputs and outputs are
// the same. // the same.
if (taskOutputsBackup != null && (e is CompilationErrorException || e is OOMErrorException)) { if (taskOutputsBackup != null && (e is CompilationErrorException || e is OOMErrorException)) {
parameters.metricsReporter.get().measure(BuildTime.RESTORE_OUTPUT_FROM_BACKUP) { parameters.metricsReporter.get().measure(GradleBuildTime.RESTORE_OUTPUT_FROM_BACKUP) {
logger.info("Restoring task outputs to pre-compilation state") logger.info("Restoring task outputs to pre-compilation state")
taskOutputsBackup.restoreOutputs() taskOutputsBackup.restoreOutputs()
} }
@@ -100,6 +97,6 @@ internal class GradleCompilerRunnerWithWorkers(
val taskOutputsToRestore: ListProperty<File> val taskOutputsToRestore: ListProperty<File>
val snapshotsDir: DirectoryProperty val snapshotsDir: DirectoryProperty
val buildDir: DirectoryProperty val buildDir: DirectoryProperty
val metricsReporter: Property<BuildMetricsReporter> val metricsReporter: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>>
} }
} }
@@ -14,10 +14,7 @@ import org.gradle.api.tasks.bundling.Zip
import org.gradle.jvm.tasks.Jar import org.gradle.jvm.tasks.Jar
import org.gradle.workers.WorkQueue import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.compilerRunner.btapi.GradleBuildToolsApiCompilerRunner import org.jetbrains.kotlin.compilerRunner.btapi.GradleBuildToolsApiCompilerRunner
@@ -60,7 +57,7 @@ internal fun createGradleCompilerRunner(
taskProvider: GradleCompileTaskProvider, taskProvider: GradleCompileTaskProvider,
toolsJar: File?, toolsJar: File?,
compilerExecutionSettings: CompilerExecutionSettings, compilerExecutionSettings: CompilerExecutionSettings,
buildMetricsReporter: BuildMetricsReporter, buildMetricsReporter: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
workerExecutor: WorkerExecutor, workerExecutor: WorkerExecutor,
runViaBuildToolsApi: Boolean, runViaBuildToolsApi: Boolean,
cachedClassLoadersService: Property<ClassLoadersCachingBuildService> cachedClassLoadersService: Property<ClassLoadersCachingBuildService>
@@ -94,7 +91,7 @@ internal open class GradleCompilerRunner(
protected val taskProvider: GradleCompileTaskProvider, protected val taskProvider: GradleCompileTaskProvider,
protected val jdkToolsJar: File?, protected val jdkToolsJar: File?,
protected val compilerExecutionSettings: CompilerExecutionSettings, protected val compilerExecutionSettings: CompilerExecutionSettings,
protected val buildMetrics: BuildMetricsReporter, protected val buildMetrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
) { ) {
internal val pathProvider = taskProvider.path.get() internal val pathProvider = taskProvider.path.get()
@@ -250,13 +247,13 @@ internal open class GradleCompilerRunner(
taskOutputsBackup: TaskOutputsBackup? taskOutputsBackup: TaskOutputsBackup?
): WorkQueue? { ): WorkQueue? {
try { try {
buildMetrics.addTimeMetric(BuildPerformanceMetric.CALL_WORKER) buildMetrics.addTimeMetric(GradleBuildPerformanceMetric.CALL_WORKER)
val kotlinCompilerRunnable = GradleKotlinCompilerWork(workArgs) val kotlinCompilerRunnable = GradleKotlinCompilerWork(workArgs)
kotlinCompilerRunnable.run() kotlinCompilerRunnable.run()
} catch (e: FailedCompilationException) { } catch (e: FailedCompilationException) {
// Restore outputs only for CompilationErrorException or OOMErrorException (see GradleKotlinCompilerWorkAction.execute) // Restore outputs only for CompilationErrorException or OOMErrorException (see GradleKotlinCompilerWorkAction.execute)
if (taskOutputsBackup != null && (e is CompilationErrorException || e is OOMErrorException)) { if (taskOutputsBackup != null && (e is CompilationErrorException || e is OOMErrorException)) {
buildMetrics.measure(BuildTime.RESTORE_OUTPUT_FROM_BACKUP) { buildMetrics.measure(GradleBuildTime.RESTORE_OUTPUT_FROM_BACKUP) {
taskOutputsBackup.restoreOutputs() taskOutputsBackup.restoreOutputs()
} }
} }
@@ -131,8 +131,8 @@ internal class GradleKotlinCompilerWork @Inject constructor(
get() = incrementalCompilationEnvironment != null get() = incrementalCompilationEnvironment != null
override fun run() { override fun run() {
metrics.addTimeMetric(BuildPerformanceMetric.START_WORKER_EXECUTION) metrics.addTimeMetric(GradleBuildPerformanceMetric.START_WORKER_EXECUTION)
metrics.startMeasure(BuildTime.RUN_COMPILATION_IN_WORKER) metrics.startMeasure(GradleBuildTime.RUN_COMPILATION_IN_WORKER)
try { try {
val gradlePrintingMessageCollector = GradlePrintingMessageCollector(log, allWarningsAsErrors) val gradlePrintingMessageCollector = GradlePrintingMessageCollector(log, allWarningsAsErrors)
val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector, kotlinPluginVersion = kotlinPluginVersion) val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector, kotlinPluginVersion = kotlinPluginVersion)
@@ -150,7 +150,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
compilerArguments = if (reportingSettings.includeCompilerArguments) compilerArgs else emptyArray(), compilerArguments = if (reportingSettings.includeCompilerArguments) compilerArgs else emptyArray(),
tags = collectStatTags(), tags = collectStatTags(),
) )
metrics.endMeasure(BuildTime.RUN_COMPILATION_IN_WORKER) metrics.endMeasure(GradleBuildTime.RUN_COMPILATION_IN_WORKER)
val result = TaskExecutionResult(buildMetrics = metrics.getMetrics(), icLogLines = icLogLines, taskInfo = taskInfo) val result = TaskExecutionResult(buildMetrics = metrics.getMetrics(), icLogLines = icLogLines, taskInfo = taskInfo)
TaskExecutionResults[taskPath] = result TaskExecutionResults[taskPath] = result
} }
@@ -210,7 +210,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
val daemonMessageCollector = val daemonMessageCollector =
if (isDebugEnabled) messageCollector else MessageCollector.NONE if (isDebugEnabled) messageCollector else MessageCollector.NONE
val connection = val connection =
metrics.measure(BuildTime.CONNECT_TO_DAEMON) { metrics.measure(GradleBuildTime.CONNECT_TO_DAEMON) {
GradleCompilerRunner.getDaemonConnectionImpl( GradleCompilerRunner.getDaemonConnectionImpl(
clientIsAliveFlagFile, clientIsAliveFlagFile,
sessionFlagFile, sessionFlagFile,
@@ -261,8 +261,8 @@ internal class GradleKotlinCompilerWork @Inject constructor(
if (memoryUsageAfterBuild == null || memoryUsageBeforeBuild == null) { if (memoryUsageAfterBuild == null || memoryUsageBeforeBuild == null) {
log.debug("Unable to calculate memory usage") log.debug("Unable to calculate memory usage")
} else { } else {
metrics.addMetric(BuildPerformanceMetric.DAEMON_INCREASED_MEMORY, memoryUsageAfterBuild - memoryUsageBeforeBuild) metrics.addMetric(GradleBuildPerformanceMetric.DAEMON_INCREASED_MEMORY, memoryUsageAfterBuild - memoryUsageBeforeBuild)
metrics.addMetric(BuildPerformanceMetric.DAEMON_MEMORY_USAGE, memoryUsageAfterBuild) metrics.addMetric(GradleBuildPerformanceMetric.DAEMON_MEMORY_USAGE, memoryUsageAfterBuild)
} }
@@ -270,7 +270,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
// often source of the NoSuchObjectException and UnmarshalException, probably caused by the failed/crashed/exited daemon // often source of the NoSuchObjectException and UnmarshalException, probably caused by the failed/crashed/exited daemon
// TODO: implement a proper logic to avoid remote calls in such cases // TODO: implement a proper logic to avoid remote calls in such cases
try { try {
metrics.measure(BuildTime.CLEAR_JAR_CACHE) { metrics.measure(GradleBuildTime.CLEAR_JAR_CACHE) {
daemon.clearJarCache() daemon.clearJarCache()
} }
} catch (e: RemoteException) { } catch (e: RemoteException) {
@@ -298,7 +298,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
) )
val servicesFacade = GradleCompilerServicesFacadeImpl(log, bufferingMessageCollector) val servicesFacade = GradleCompilerServicesFacadeImpl(log, bufferingMessageCollector)
val compilationResults = GradleCompilationResults(log, projectRootFile) val compilationResults = GradleCompilationResults(log, projectRootFile)
return metrics.measure(BuildTime.NON_INCREMENTAL_COMPILATION_DAEMON) { return metrics.measure(GradleBuildTime.NON_INCREMENTAL_COMPILATION_DAEMON) {
daemon.compile(sessionId, compilerArgs, compilationOptions, servicesFacade, compilationResults) daemon.compile(sessionId, compilerArgs, compilationOptions, servicesFacade, compilationResults)
}.also { }.also {
metrics.addMetrics(compilationResults.buildMetrics) metrics.addMetrics(compilationResults.buildMetrics)
@@ -339,8 +339,8 @@ internal class GradleKotlinCompilerWork @Inject constructor(
log.info("Options for KOTLIN DAEMON: $compilationOptions") log.info("Options for KOTLIN DAEMON: $compilationOptions")
val servicesFacade = GradleIncrementalCompilerServicesFacadeImpl(log, bufferingMessageCollector) val servicesFacade = GradleIncrementalCompilerServicesFacadeImpl(log, bufferingMessageCollector)
val compilationResults = GradleCompilationResults(log, projectRootFile) val compilationResults = GradleCompilationResults(log, projectRootFile)
metrics.addTimeMetric(BuildPerformanceMetric.CALL_KOTLIN_DAEMON) metrics.addTimeMetric(GradleBuildPerformanceMetric.CALL_KOTLIN_DAEMON)
return metrics.measure(BuildTime.RUN_COMPILATION) { return metrics.measure(GradleBuildTime.RUN_COMPILATION) {
daemon.compile(sessionId, compilerArgs, compilationOptions, servicesFacade, compilationResults) daemon.compile(sessionId, compilerArgs, compilationOptions, servicesFacade, compilationResults)
}.also { }.also {
metrics.addMetrics(compilationResults.buildMetrics) metrics.addMetrics(compilationResults.buildMetrics)
@@ -352,7 +352,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
metrics.addAttribute(BuildAttribute.OUT_OF_PROCESS_EXECUTION) metrics.addAttribute(BuildAttribute.OUT_OF_PROCESS_EXECUTION)
cleanOutputsAndLocalState(outputFiles, log, metrics, reason = "out-of-process execution strategy is non-incremental") cleanOutputsAndLocalState(outputFiles, log, metrics, reason = "out-of-process execution strategy is non-incremental")
return metrics.measure(BuildTime.NON_INCREMENTAL_COMPILATION_OUT_OF_PROCESS) { return metrics.measure(GradleBuildTime.NON_INCREMENTAL_COMPILATION_OUT_OF_PROCESS) {
runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log, buildDir) runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log, buildDir)
} }
} }
@@ -361,7 +361,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
metrics.addAttribute(BuildAttribute.IN_PROCESS_EXECUTION) metrics.addAttribute(BuildAttribute.IN_PROCESS_EXECUTION)
cleanOutputsAndLocalState(outputFiles, log, metrics, reason = "in-process execution strategy is non-incremental") cleanOutputsAndLocalState(outputFiles, log, metrics, reason = "in-process execution strategy is non-incremental")
metrics.startMeasure(BuildTime.NON_INCREMENTAL_COMPILATION_IN_PROCESS) metrics.startMeasure(GradleBuildTime.NON_INCREMENTAL_COMPILATION_IN_PROCESS)
// in-process compiler should always be run in a different thread // in-process compiler should always be run in a different thread
// to avoid leaking thread locals from compiler (see KT-28037) // to avoid leaking thread locals from compiler (see KT-28037)
val threadPool = Executors.newSingleThreadExecutor() val threadPool = Executors.newSingleThreadExecutor()
@@ -375,7 +375,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
bufferingMessageCollector.flush(messageCollector) bufferingMessageCollector.flush(messageCollector)
threadPool.shutdown() threadPool.shutdown()
metrics.endMeasure(BuildTime.NON_INCREMENTAL_COMPILATION_IN_PROCESS) metrics.endMeasure(GradleBuildTime.NON_INCREMENTAL_COMPILATION_IN_PROCESS)
} }
} }
@@ -404,7 +404,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
exitCode exitCode
) )
try { try {
metrics.measure(BuildTime.CLEAR_JAR_CACHE) { metrics.measure(GradleBuildTime.CLEAR_JAR_CACHE) {
val coreEnvironment = Class.forName("org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment", true, classLoader) val coreEnvironment = Class.forName("org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment", true, classLoader)
val dispose = coreEnvironment.getMethod("disposeApplicationEnvironment") val dispose = coreEnvironment.getMethod("disposeApplicationEnvironment")
dispose.invoke(null) dispose.invoke(null)
@@ -11,6 +11,8 @@ import org.gradle.api.provider.Property
import org.gradle.workers.WorkAction import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters import org.gradle.workers.WorkParameters
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.buildtools.api.CompilationService import org.jetbrains.kotlin.buildtools.api.CompilationService
import org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi import org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi
import org.jetbrains.kotlin.buildtools.api.SharedApiClassesClassLoader import org.jetbrains.kotlin.buildtools.api.SharedApiClassesClassLoader
@@ -27,7 +29,7 @@ internal abstract class BuildToolsApiCompilationWork : WorkAction<BuildToolsApiC
val taskOutputsToRestore: ListProperty<File> val taskOutputsToRestore: ListProperty<File>
val snapshotsDir: DirectoryProperty val snapshotsDir: DirectoryProperty
val buildDir: DirectoryProperty val buildDir: DirectoryProperty
val metricsReporter: Property<BuildMetricsReporter> val metricsReporter: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>>
} }
private val workArguments private val workArguments
@@ -10,6 +10,8 @@ import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.compilerRunner.CompilerExecutionSettings import org.jetbrains.kotlin.compilerRunner.CompilerExecutionSettings
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
import org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWorkArguments import org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWorkArguments
@@ -22,7 +24,7 @@ internal class GradleBuildToolsApiCompilerRunner(
taskProvider: GradleCompileTaskProvider, taskProvider: GradleCompileTaskProvider,
jdkToolsJar: File?, jdkToolsJar: File?,
compilerExecutionSettings: CompilerExecutionSettings, compilerExecutionSettings: CompilerExecutionSettings,
buildMetrics: BuildMetricsReporter, buildMetrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
private val workerExecutor: WorkerExecutor, private val workerExecutor: WorkerExecutor,
private val cachedClassLoadersService: Provider<ClassLoadersCachingBuildService> private val cachedClassLoadersService: Provider<ClassLoadersCachingBuildService>
) : GradleCompilerRunner(taskProvider, jdkToolsJar, compilerExecutionSettings, buildMetrics) { ) : GradleCompilerRunner(taskProvider, jdkToolsJar, compilerExecutionSettings, buildMetrics) {
@@ -32,7 +34,7 @@ internal class GradleBuildToolsApiCompilerRunner(
workArgs: GradleKotlinCompilerWorkArguments, workArgs: GradleKotlinCompilerWorkArguments,
taskOutputsBackup: TaskOutputsBackup? taskOutputsBackup: TaskOutputsBackup?
): WorkQueue { ): WorkQueue {
buildMetrics.addTimeMetric(BuildPerformanceMetric.CALL_WORKER) buildMetrics.addTimeMetric(GradleBuildPerformanceMetric.CALL_WORKER)
val workQueue = workerExecutor.noIsolation() val workQueue = workerExecutor.noIsolation()
workQueue.submit(BuildToolsApiCompilationWork::class.java) { params -> workQueue.submit(BuildToolsApiCompilationWork::class.java) { params ->
params.compilerWorkArguments.set(workArgs) params.compilerWorkArguments.set(workArgs)
@@ -13,7 +13,8 @@ import org.gradle.work.Incremental
import org.gradle.work.InputChanges import org.gradle.work.InputChanges
import org.gradle.work.NormalizeLineEndings import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.plugin.CompilerPluginConfig import org.jetbrains.kotlin.gradle.plugin.CompilerPluginConfig
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime
import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
@@ -101,8 +103,8 @@ abstract class KaptTask @Inject constructor(
var useBuildCache: Boolean = false var useBuildCache: Boolean = false
@get:Internal @get:Internal
override val metrics: Property<BuildMetricsReporter> = objectFactory override val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>> = project.objects
.property(BuildMetricsReporterImpl()) .property(GradleBuildMetricsReporter())
@get:Input @get:Input
abstract val verbose: Property<Boolean> abstract val verbose: Property<Boolean>
@@ -10,6 +10,8 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Internal
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import java.io.File import java.io.File
internal interface TaskWithLocalState : Task { internal interface TaskWithLocalState : Task {
@@ -17,7 +19,7 @@ internal interface TaskWithLocalState : Task {
val localStateDirectories: ConfigurableFileCollection val localStateDirectories: ConfigurableFileCollection
@get:Internal @get:Internal
val metrics: Property<BuildMetricsReporter> val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>>
} }
internal fun TaskWithLocalState.allOutputFiles(): List<File> = internal fun TaskWithLocalState.allOutputFiles(): List<File> =
@@ -84,22 +84,22 @@ abstract class ClasspathEntrySnapshotTransform : TransformAction<ClasspathEntryS
private fun doTransform( private fun doTransform(
classpathEntryInputDirOrJar: File, snapshotOutputFile: File, classpathEntryInputDirOrJar: File, snapshotOutputFile: File,
granularity: ClassSnapshotGranularity, metrics: BuildMetricsReporter granularity: ClassSnapshotGranularity, metrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>
) { ) {
metrics.measure(BuildTime.CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM) { metrics.measure(GradleBuildTime.CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM) {
val snapshot = ClasspathEntrySnapshotter.snapshot(classpathEntryInputDirOrJar, granularity, metrics) val snapshot = ClasspathEntrySnapshotter.snapshot(classpathEntryInputDirOrJar, granularity, metrics)
metrics.measure(BuildTime.SAVE_CLASSPATH_ENTRY_SNAPSHOT) { metrics.measure(GradleBuildTime.SAVE_CLASSPATH_ENTRY_SNAPSHOT) {
ClasspathEntrySnapshotExternalizer.saveToFile(snapshotOutputFile, snapshot) ClasspathEntrySnapshotExternalizer.saveToFile(snapshotOutputFile, snapshot)
} }
} }
metrics.addMetric(BuildPerformanceMetric.CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT, 1) metrics.addMetric(GradleBuildPerformanceMetric.CLASSPATH_ENTRY_SNAPSHOT_TRANSFORM_EXECUTION_COUNT, 1)
if (classpathEntryInputDirOrJar.extension.equals("jar", ignoreCase = true)) { if (classpathEntryInputDirOrJar.extension.equals("jar", ignoreCase = true)) {
metrics.addMetric(BuildPerformanceMetric.JAR_CLASSPATH_ENTRY_SIZE, classpathEntryInputDirOrJar.length()) metrics.addMetric(GradleBuildPerformanceMetric.JAR_CLASSPATH_ENTRY_SIZE, classpathEntryInputDirOrJar.length())
metrics.addMetric(BuildPerformanceMetric.JAR_CLASSPATH_ENTRY_SNAPSHOT_SIZE, snapshotOutputFile.length()) metrics.addMetric(GradleBuildPerformanceMetric.JAR_CLASSPATH_ENTRY_SNAPSHOT_SIZE, snapshotOutputFile.length())
} else { } else {
// Only compute the size of the snapshot, not the size of the input directory as walking the file tree has a small overhead // Only compute the size of the snapshot, not the size of the input directory as walking the file tree has a small overhead
metrics.addMetric(BuildPerformanceMetric.DIRECTORY_CLASSPATH_ENTRY_SNAPSHOT_SIZE, snapshotOutputFile.length()) metrics.addMetric(GradleBuildPerformanceMetric.DIRECTORY_CLASSPATH_ENTRY_SNAPSHOT_SIZE, snapshotOutputFile.length())
} }
} }
} }
@@ -24,10 +24,7 @@ import org.gradle.tooling.events.task.TaskFailureResult
import org.gradle.tooling.events.task.TaskFinishEvent import org.gradle.tooling.events.task.TaskFinishEvent
import org.gradle.tooling.events.task.TaskSkippedResult import org.gradle.tooling.events.task.TaskSkippedResult
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.statistics.HttpReportService import org.jetbrains.kotlin.build.report.statistics.HttpReportService
import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
@@ -76,10 +73,10 @@ abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters
private val failureMessages = ConcurrentLinkedQueue<String>() private val failureMessages = ConcurrentLinkedQueue<String>()
// Info for tasks only // Info for tasks only
private val taskPathToMetricsReporter = ConcurrentHashMap<String, BuildMetricsReporter>() private val taskPathToMetricsReporter = ConcurrentHashMap<String, BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>>()
private val taskPathToTaskClass = ConcurrentHashMap<String, String>() private val taskPathToTaskClass = ConcurrentHashMap<String, String>()
open fun addTask(taskPath: String, taskClass: Class<*>, metricsReporter: BuildMetricsReporter) { open fun addTask(taskPath: String, taskClass: Class<*>, metricsReporter: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>) {
taskPathToMetricsReporter.put(taskPath, metricsReporter).also { taskPathToMetricsReporter.put(taskPath, metricsReporter).also {
if (it != null) log.warn("Duplicate task path: $taskPath") // Should never happen but log it just in case if (it != null) log.warn("Duplicate task path: $taskPath") // Should never happen but log it just in case
} }
@@ -94,7 +91,7 @@ abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters
isKotlinTransform: Boolean, isKotlinTransform: Boolean,
startTimeMs: Long, startTimeMs: Long,
totalTimeMs: Long, totalTimeMs: Long,
buildMetrics: BuildMetrics, buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>,
failureMessage: String? failureMessage: String?
) { ) {
buildOperationRecords.add( buildOperationRecords.add(
@@ -108,8 +105,8 @@ abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters
val taskPath = event.descriptor.taskPath val taskPath = event.descriptor.taskPath
val totalTimeMs = result.endTime - result.startTime val totalTimeMs = result.endTime - result.startTime
val buildMetrics = BuildMetrics() val buildMetrics = BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>()
buildMetrics.buildTimes.addTimeMs(BuildTime.GRADLE_TASK, totalTimeMs) buildMetrics.buildTimes.addTimeMs(GradleBuildTime.GRADLE_TASK, totalTimeMs)
taskPathToMetricsReporter[taskPath]?.let { taskPathToMetricsReporter[taskPath]?.let {
buildMetrics.addAll(it.getMetrics()) buildMetrics.addAll(it.getMetrics())
} }
@@ -122,14 +119,14 @@ abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters
collector.report(BooleanMetrics.KOTLIN_COMPILATION_FAILED, event.result is FailureResult) collector.report(BooleanMetrics.KOTLIN_COMPILATION_FAILED, event.result is FailureResult)
val metricsMap = buildMetrics.buildPerformanceMetrics.asMap() val metricsMap = buildMetrics.buildPerformanceMetrics.asMap()
val linesOfCode = metricsMap[BuildPerformanceMetric.ANALYZED_LINES_NUMBER] val linesOfCode = metricsMap[GradleBuildPerformanceMetric.ANALYZED_LINES_NUMBER]
if (linesOfCode != null && linesOfCode > 0 && totalTimeMs > 0) { if (linesOfCode != null && linesOfCode > 0 && totalTimeMs > 0) {
collector.report(NumericalMetrics.COMPILED_LINES_OF_CODE, linesOfCode) collector.report(NumericalMetrics.COMPILED_LINES_OF_CODE, linesOfCode)
collector.report(NumericalMetrics.COMPILATION_LINES_PER_SECOND, linesOfCode * 1000 / totalTimeMs, null, linesOfCode) collector.report(NumericalMetrics.COMPILATION_LINES_PER_SECOND, linesOfCode * 1000 / totalTimeMs, null, linesOfCode)
metricsMap[BuildPerformanceMetric.ANALYSIS_LPS]?.also { value -> metricsMap[GradleBuildPerformanceMetric.ANALYSIS_LPS]?.also { value ->
collector.report(NumericalMetrics.ANALYSIS_LINES_PER_SECOND, value, null, linesOfCode) collector.report(NumericalMetrics.ANALYSIS_LINES_PER_SECOND, value, null, linesOfCode)
} }
metricsMap[BuildPerformanceMetric.CODE_GENERATION_LPS]?.also { value -> metricsMap[GradleBuildPerformanceMetric.CODE_GENERATION_LPS]?.also { value ->
collector.report(NumericalMetrics.CODE_GENERATION_LINES_PER_SECOND, value, null, linesOfCode) collector.report(NumericalMetrics.CODE_GENERATION_LINES_PER_SECOND, value, null, linesOfCode)
} }
} }
@@ -326,7 +323,7 @@ internal class TaskRecord(
override val classFqName: String, override val classFqName: String,
override val startTimeMs: Long, override val startTimeMs: Long,
override val totalTimeMs: Long, override val totalTimeMs: Long,
override val buildMetrics: BuildMetrics, override val buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>,
override val didWork: Boolean, override val didWork: Boolean,
override val skipMessage: String?, override val skipMessage: String?,
override val icLogLines: List<String>, override val icLogLines: List<String>,
@@ -344,7 +341,7 @@ private class TransformRecord(
override val isFromKotlinPlugin: Boolean, override val isFromKotlinPlugin: Boolean,
override val startTimeMs: Long, override val startTimeMs: Long,
override val totalTimeMs: Long, override val totalTimeMs: Long,
override val buildMetrics: BuildMetrics override val buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>
) : BuildOperationRecord { ) : BuildOperationRecord {
override val didWork: Boolean = true override val didWork: Boolean = true
override val skipMessage: String? = null override val skipMessage: String? = null
@@ -13,12 +13,12 @@ import org.jetbrains.kotlin.build.report.statistics.HttpReportService
import org.jetbrains.kotlin.build.report.statistics.file.FileReportService import org.jetbrains.kotlin.build.report.statistics.file.FileReportService
import org.jetbrains.kotlin.build.report.statistics.formatSize import org.jetbrains.kotlin.build.report.statistics.formatSize
import org.jetbrains.kotlin.build.report.statistics.BuildFinishStatisticsData import org.jetbrains.kotlin.build.report.statistics.BuildFinishStatisticsData
import org.jetbrains.kotlin.build.report.statistics.CompileStatisticsData
import org.jetbrains.kotlin.build.report.statistics.BuildStartParameters import org.jetbrains.kotlin.build.report.statistics.BuildStartParameters
import org.jetbrains.kotlin.build.report.statistics.StatTag import org.jetbrains.kotlin.build.report.statistics.StatTag
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.report.data.BuildExecutionData import org.jetbrains.kotlin.gradle.report.data.BuildExecutionData
import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord
import org.jetbrains.kotlin.gradle.report.data.GradleCompileStatisticsData
import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult
import java.io.File import java.io.File
import java.net.InetAddress import java.net.InetAddress
@@ -230,9 +230,9 @@ class BuildReportsService {
} }
} }
private fun addBuildScanReport(data: CompileStatisticsData, customValuesLimit: Int, buildScan: BuildScanExtensionHolder) { private fun addBuildScanReport(data: GradleCompileStatisticsData, customValuesLimit: Int, buildScan: BuildScanExtensionHolder) {
val elapsedTime = measureTimeMillis { val elapsedTime = measureTimeMillis {
tags.addAll(data.tags) tags.addAll(data.getTags())
if (customValues < customValuesLimit) { if (customValues < customValuesLimit) {
readableString(data).forEach { readableString(data).forEach {
if (customValues < customValuesLimit) { if (customValues < customValuesLimit) {
@@ -240,7 +240,7 @@ class BuildReportsService {
} else { } else {
log.debug( log.debug(
"Can't add any more custom values into build scan." + "Can't add any more custom values into build scan." +
" Statistic data for ${data.taskName} was cut due to custom values limit." " Statistic data for ${data.getTaskName()} was cut due to custom values limit."
) )
} }
} }
@@ -254,10 +254,10 @@ class BuildReportsService {
private fun addBuildScanValue( private fun addBuildScanValue(
buildScan: BuildScanExtensionHolder, buildScan: BuildScanExtensionHolder,
data: CompileStatisticsData, data: GradleCompileStatisticsData,
customValue: String customValue: String
) { ) {
buildScan.buildScan.value(data.taskName, customValue) buildScan.buildScan.value(data.getTaskName(), customValue)
customValues++ customValues++
} }
@@ -289,30 +289,30 @@ class BuildReportsService {
} }
} }
private fun readableString(data: CompileStatisticsData): List<String> { private fun readableString(data: GradleCompileStatisticsData): List<String> {
val readableString = StringBuilder() val readableString = StringBuilder()
if (data.nonIncrementalAttributes.isEmpty()) { if (data.getNonIncrementalAttributes().isEmpty()) {
readableString.append("Incremental build; ") readableString.append("Incremental build; ")
data.changes.joinTo(readableString, prefix = "Changes: [", postfix = "]; ") { it.substringAfterLast(File.separator) } data.getChanges().joinTo(readableString, prefix = "Changes: [", postfix = "]; ") { it.substringAfterLast(File.separator) }
} else { } else {
data.nonIncrementalAttributes.joinTo( data.getNonIncrementalAttributes().joinTo(
readableString, readableString,
prefix = "Non incremental build because: [", prefix = "Non incremental build because: [",
postfix = "]; " postfix = "]; "
) { it.readableString } ) { it.readableString }
} }
data.kotlinLanguageVersion?.also { data.getKotlinLanguageVersion()?.also {
readableString.append("Kotlin language version: $it; ") readableString.append("Kotlin language version: $it; ")
} }
val timeData = val timeData =
data.buildTimesMetrics.map { (key, value) -> "${key.readableString}: ${value}ms" } //sometimes it is better to have separate variable to be able debug data.getBuildTimesMetrics().map { (key, value) -> "${key.getReadableString()}: ${value}ms" } //sometimes it is better to have separate variable to be able debug
val perfData = data.performanceMetrics.map { (key, value) -> val perfData = data.getPerformanceMetrics().map { (key, value) ->
when (key.type) { when (key.getType()) {
ValueType.BYTES -> "${key.readableString}: ${formatSize(value)}" ValueType.BYTES -> "${key.getReadableString()}: ${formatSize(value)}"
ValueType.MILLISECONDS -> DATE_FORMATTER.format(value) ValueType.MILLISECONDS -> DATE_FORMATTER.format(value)
else -> "${key.readableString}: $value" else -> "${key.getReadableString()}: $value"
} }
} }
timeData.union(perfData).joinTo(readableString, ",", "Performance: [", "]") timeData.union(perfData).joinTo(readableString, ",", "Performance: [", "]")
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2023 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.gradle.report
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
class GradleBuildMetricsReporter : BuildMetricsReporterImpl<GradleBuildTime, GradleBuildPerformanceMetric>() {
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.report
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.gradle.internal.build.metrics.GradleBuildMetricsData import org.jetbrains.kotlin.gradle.internal.build.metrics.GradleBuildMetricsData
import org.jetbrains.kotlin.gradle.internal.build.metrics.BuildOperationData import org.jetbrains.kotlin.gradle.internal.build.metrics.BuildOperationData
import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.kotlinDebug
@@ -26,8 +27,8 @@ internal class MetricsWriter(
outputFile.parentFile?.apply { mkdirs() } outputFile.parentFile?.apply { mkdirs() }
val buildMetricsData = GradleBuildMetricsData() val buildMetricsData = GradleBuildMetricsData()
for (metric in BuildTime.values()) { for (metric in GradleBuildTime.values()) {
buildMetricsData.parentMetric[metric.name] = metric.parent?.name buildMetricsData.parentMetric[metric.name] = metric.getParent()?.getName()
} }
for (attr in BuildAttribute.values()) { for (attr in BuildAttribute.values()) {
buildMetricsData.buildAttributeKind[attr.name] = attr.kind.name buildMetricsData.buildAttributeKind[attr.name] = attr.kind.name
@@ -6,12 +6,14 @@
package org.jetbrains.kotlin.gradle.report package org.jetbrains.kotlin.gradle.report
import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.BuildMetrics
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.build.report.statistics.StatTag import org.jetbrains.kotlin.build.report.statistics.StatTag
import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.ChangedFiles
internal class TaskExecutionResult( internal class TaskExecutionResult(
val buildMetrics: BuildMetrics, val buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>,
val taskInfo: TaskExecutionInfo = TaskExecutionInfo(), val taskInfo: TaskExecutionInfo = TaskExecutionInfo(),
val icLogLines: List<String> = emptyList() val icLogLines: List<String> = emptyList()
) )
@@ -10,13 +10,15 @@ import org.jetbrains.kotlin.build.report.FileReportSettings
import org.jetbrains.kotlin.build.report.HttpReportSettings import org.jetbrains.kotlin.build.report.HttpReportSettings
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_BUILD_REPORT_SINGLE_FILE import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_BUILD_REPORT_SINGLE_FILE
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_BUILD_REPORT_HTTP_URL import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_BUILD_REPORT_HTTP_URL
import org.jetbrains.kotlin.gradle.plugin.internal.isProjectIsolationEnabled import org.jetbrains.kotlin.gradle.plugin.internal.isProjectIsolationEnabled
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toUpperCaseAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.toUpperCaseAsciiOnly
private val availableMetrics = BuildTime.values().map { it.name } + BuildPerformanceMetric.values().map { it.name } private val availableMetrics = GradleBuildTime.values().map { it.name } + GradleBuildPerformanceMetric.values().map { it.name }
internal fun reportingSettings(project: Project): ReportingSettings { internal fun reportingSettings(project: Project): ReportingSettings {
val properties = PropertiesProvider(project) val properties = PropertiesProvider(project)
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.gradle.report.data package org.jetbrains.kotlin.gradle.report.data
import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.BuildMetrics
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.build.report.statistics.BuildStartParameters import org.jetbrains.kotlin.build.report.statistics.BuildStartParameters
class BuildExecutionData( class BuildExecutionData(
@@ -14,7 +16,7 @@ class BuildExecutionData(
val buildOperationRecord: Collection<BuildOperationRecord> val buildOperationRecord: Collection<BuildOperationRecord>
) { ) {
val aggregatedMetrics by lazy { val aggregatedMetrics by lazy {
BuildMetrics().also { acc -> BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>().also { acc ->
buildOperationRecord.forEach { acc.addAll(it.buildMetrics) } buildOperationRecord.forEach { acc.addAll(it.buildMetrics) }
} }
} }
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.gradle.report.data package org.jetbrains.kotlin.gradle.report.data
import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.BuildMetrics
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
/** Data for a build operation (e.g., task or transform). */ /** Data for a build operation (e.g., task or transform). */
interface BuildOperationRecord { interface BuildOperationRecord {
@@ -14,7 +16,7 @@ interface BuildOperationRecord {
val isFromKotlinPlugin: Boolean val isFromKotlinPlugin: Boolean
val startTimeMs: Long // Measured by System.currentTimeMillis() val startTimeMs: Long // Measured by System.currentTimeMillis()
val totalTimeMs: Long val totalTimeMs: Long
val buildMetrics: BuildMetrics val buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>
val didWork: Boolean val didWork: Boolean
val skipMessage: String? val skipMessage: String?
val icLogLines: List<String> val icLogLines: List<String>
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2023 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.gradle.report.data
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.build.report.statistics.BuildDataType
import org.jetbrains.kotlin.build.report.statistics.CompileStatisticsData
import org.jetbrains.kotlin.build.report.statistics.StatTag
class GradleCompileStatisticsData(
private val projectName: String?,
private val label: String?,
private val taskName: String,
private val taskResult: String?,
private val startTimeMs: Long,
private val durationMs: Long,
private val tags: Set<StatTag>,
private val changes: List<String>,
private val buildUuid: String = "Unset",
private val kotlinVersion: String,
private val kotlinLanguageVersion: String?,
private val hostName: String? = "Unset",
private val finishTime: Long,
private val compilerArguments: List<String>,
private val nonIncrementalAttributes: Set<BuildAttribute>,
private val buildTimesMetrics: Map<GradleBuildTime, Long>,
private val performanceMetrics: Map<GradleBuildPerformanceMetric, Long>,
private val gcTimeMetrics: Map<String, Long>?,
private val gcCountMetrics: Map<String, Long>?,
private val type: String = BuildDataType.TASK_DATA.name,
private val fromKotlinPlugin: Boolean?,
private val compiledSources: List<String> = emptyList(),
private val skipMessage: String?,
private val icLogLines: List<String>,
) : CompileStatisticsData<GradleBuildTime, GradleBuildPerformanceMetric> {
override fun getProjectName(): String? = projectName
override fun getLabel(): String? = label
override fun getTaskName(): String = taskName
override fun getTaskResult(): String? = taskResult
override fun getStartTimeMs(): Long = startTimeMs
override fun getDurationMs(): Long = durationMs
override fun getTags(): Set<StatTag> = tags
override fun getChanges(): List<String> = changes
override fun getKotlinVersion(): String = kotlinVersion
override fun getKotlinLanguageVersion(): String? = kotlinLanguageVersion
override fun getFinishTime(): Long = finishTime
override fun getCompilerArguments(): List<String> = compilerArguments
override fun getNonIncrementalAttributes(): Set<BuildAttribute> = nonIncrementalAttributes
override fun getBuildTimesMetrics(): Map<GradleBuildTime, Long> = buildTimesMetrics
override fun getPerformanceMetrics(): Map<GradleBuildPerformanceMetric, Long> = performanceMetrics
override fun getGcTimeMetrics(): Map<String, Long>? = gcTimeMetrics
override fun getGcCountMetrics(): Map<String, Long>? = gcCountMetrics
override fun getFromKotlinPlugin(): Boolean? = fromKotlinPlugin
override fun getSkipMessage(): String? = skipMessage
override fun getIcLogLines(): List<String> = icLogLines
}
@@ -10,12 +10,12 @@ import org.gradle.tooling.events.task.TaskFinishEvent
import org.gradle.tooling.events.task.TaskSkippedResult import org.gradle.tooling.events.task.TaskSkippedResult
import org.gradle.tooling.events.task.TaskSuccessResult import org.gradle.tooling.events.task.TaskSuccessResult
import org.jetbrains.kotlin.build.report.metrics.* import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.statistics.CompileStatisticsData
import org.jetbrains.kotlin.build.report.statistics.StatTag import org.jetbrains.kotlin.build.report.statistics.StatTag
import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord
import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.ChangedFiles
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.report.data.GradleCompileStatisticsData
internal fun getTaskResult(event: TaskFinishEvent) = when (val result = event.result) { internal fun getTaskResult(event: TaskFinishEvent) = when (val result = event.result) {
@@ -40,7 +40,7 @@ internal fun prepareData(
onlyKotlinTask: Boolean = true, onlyKotlinTask: Boolean = true,
additionalTags: Set<StatTag> = emptySet(), additionalTags: Set<StatTag> = emptySet(),
metricsToShow: Set<String>? = null metricsToShow: Set<String>? = null
): CompileStatisticsData? { ): GradleCompileStatisticsData? {
val result = event.result val result = event.result
val taskPath = event.descriptor.taskPath val taskPath = event.descriptor.taskPath
return prepareData(getTaskResult(event), taskPath, result.startTime, result.endTime - result.startTime, projectName, uuid, return prepareData(getTaskResult(event), taskPath, result.startTime, result.endTime - result.startTime, projectName, uuid,
@@ -60,7 +60,7 @@ internal fun prepareData(
onlyKotlinTask: Boolean = true, onlyKotlinTask: Boolean = true,
additionalTags: Set<StatTag> = emptySet(), additionalTags: Set<StatTag> = emptySet(),
metricsToShow: Set<String>? = null metricsToShow: Set<String>? = null
): CompileStatisticsData? { ): GradleCompileStatisticsData? {
if (onlyKotlinTask && !(buildOperationRecord is TaskRecord && buildOperationRecord.isFromKotlinPlugin)) { if (onlyKotlinTask && !(buildOperationRecord is TaskRecord && buildOperationRecord.isFromKotlinPlugin)) {
return null return null
} }
@@ -78,7 +78,7 @@ internal fun prepareData(
} }
val kotlinLanguageVersion = if (buildOperationRecord is TaskRecord) buildOperationRecord.kotlinLanguageVersion else null val kotlinLanguageVersion = if (buildOperationRecord is TaskRecord) buildOperationRecord.kotlinLanguageVersion else null
return CompileStatisticsData( return GradleCompileStatisticsData(
durationMs = buildOperationRecord.totalTimeMs, durationMs = buildOperationRecord.totalTimeMs,
taskResult = taskResult?.name, taskResult = taskResult?.name,
label = label, label = label,
@@ -110,51 +110,51 @@ fun collectCompilerArguments(buildOperationRecord: BuildOperationRecord?): List<
} else emptyList() } else emptyList()
} }
private fun <E : Enum<E>> filterMetrics( private fun <E : BuildTime> filterMetrics(
expectedMetrics: Set<String>?, expectedMetrics: Set<String>?,
buildTimesMetrics: Map<E, Long> buildTimesMetrics: Map<E, Long>
): Map<E, Long> = expectedMetrics?.let { buildTimesMetrics.filterKeys { metric -> it.contains(metric.name) } } ?: buildTimesMetrics ): Map<E, Long> = expectedMetrics?.let { buildTimesMetrics.filterKeys { metric -> it.contains(metric.getName()) } } ?: buildTimesMetrics
private fun collectBuildAttributes(buildMetrics: BuildMetrics?): Set<BuildAttribute> { private fun collectBuildAttributes(buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>?): Set<BuildAttribute> {
return buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys ?: emptySet() return buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys ?: emptySet()
} }
private fun collectBuildPerformanceMetrics( private fun collectBuildPerformanceMetrics(
buildMetrics: BuildMetrics? buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>?
): Map<BuildPerformanceMetric, Long> { ): Map<GradleBuildPerformanceMetric, Long> {
return buildMetrics?.buildPerformanceMetrics?.asMap() return buildMetrics?.buildPerformanceMetrics?.asMap()
?.filterValues { value -> value != 0L } ?.filterValues { value -> value != 0L }
?.filterKeys { key -> ?.filterKeys { key ->
key !in listOf( key !in listOf(
BuildPerformanceMetric.START_WORKER_EXECUTION, GradleBuildPerformanceMetric.START_WORKER_EXECUTION,
BuildPerformanceMetric.CALL_WORKER, GradleBuildPerformanceMetric.CALL_WORKER,
BuildPerformanceMetric.CALL_KOTLIN_DAEMON, GradleBuildPerformanceMetric.CALL_KOTLIN_DAEMON,
BuildPerformanceMetric.START_KOTLIN_DAEMON_EXECUTION GradleBuildPerformanceMetric.START_KOTLIN_DAEMON_EXECUTION
) )
} }
?: emptyMap() ?: emptyMap()
} }
private fun collectBuildMetrics( private fun collectBuildMetrics(
buildMetrics: BuildMetrics?, buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>?,
gradleTaskStartTime: Long? = null, gradleTaskStartTime: Long? = null,
taskFinishEventTime: Long? = null, taskFinishEventTime: Long? = null,
): Map<BuildTime, Long> { ): Map<GradleBuildTime, Long> {
val taskBuildMetrics = HashMap<BuildTime, Long>(buildMetrics?.buildTimes?.asMapMs()) val taskBuildMetrics = HashMap<GradleBuildTime, Long>(buildMetrics?.buildTimes?.asMapMs())
val performanceMetrics = buildMetrics?.buildPerformanceMetrics?.asMap() ?: emptyMap() val performanceMetrics = buildMetrics?.buildPerformanceMetrics?.asMap() ?: emptyMap()
gradleTaskStartTime?.let { startTime -> gradleTaskStartTime?.let { startTime ->
performanceMetrics[BuildPerformanceMetric.START_TASK_ACTION_EXECUTION]?.let { actionStartTime -> performanceMetrics[GradleBuildPerformanceMetric.START_TASK_ACTION_EXECUTION]?.let { actionStartTime ->
taskBuildMetrics.put(BuildTime.GRADLE_TASK_PREPARATION, actionStartTime - startTime) taskBuildMetrics.put(GradleBuildTime.GRADLE_TASK_PREPARATION, actionStartTime - startTime)
} }
} }
taskFinishEventTime?.let { listenerNotificationTime -> taskFinishEventTime?.let { listenerNotificationTime ->
performanceMetrics[BuildPerformanceMetric.FINISH_KOTLIN_DAEMON_EXECUTION]?.let { daemonFinishTime -> performanceMetrics[GradleBuildPerformanceMetric.FINISH_KOTLIN_DAEMON_EXECUTION]?.let { daemonFinishTime ->
taskBuildMetrics.put(BuildTime.TASK_FINISH_LISTENER_NOTIFICATION, listenerNotificationTime - daemonFinishTime) taskBuildMetrics.put(GradleBuildTime.TASK_FINISH_LISTENER_NOTIFICATION, listenerNotificationTime - daemonFinishTime)
} }
} }
performanceMetrics[BuildPerformanceMetric.CALL_WORKER]?.let { callWorkerTime -> performanceMetrics[GradleBuildPerformanceMetric.CALL_WORKER]?.let { callWorkerTime ->
performanceMetrics[BuildPerformanceMetric.START_WORKER_EXECUTION]?.let { startWorkerExecutionTime -> performanceMetrics[GradleBuildPerformanceMetric.START_WORKER_EXECUTION]?.let { startWorkerExecutionTime ->
taskBuildMetrics.put(BuildTime.RUN_WORKER_DELAY, TimeUnit.NANOSECONDS.toMillis(startWorkerExecutionTime - callWorkerTime)) taskBuildMetrics.put(GradleBuildTime.RUN_WORKER_DELAY, TimeUnit.NANOSECONDS.toMillis(startWorkerExecutionTime - callWorkerTime))
} }
} }
return taskBuildMetrics.filterValues { value -> value != 0L } return taskBuildMetrics.filterValues { value -> value != 0L }
@@ -22,9 +22,7 @@ import org.gradle.deployment.internal.DeploymentRegistry
import org.gradle.process.internal.ExecHandle import org.gradle.process.internal.ExecHandle
import org.gradle.process.internal.ExecHandleFactory import org.gradle.process.internal.ExecHandleFactory
import org.gradle.work.NormalizeLineEndings import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName
@@ -67,7 +65,7 @@ constructor(
open val execHandleFactory: ExecHandleFactory open val execHandleFactory: ExecHandleFactory
get() = injected get() = injected
private val metrics: Property<BuildMetricsReporter> = project.objects private val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>> = project.objects
.property(BuildMetricsReporterImpl()) .property(BuildMetricsReporterImpl())
@Suppress("unused") @Suppress("unused")
@@ -299,7 +297,7 @@ constructor(
.map { it.length() } .map { it.length() }
.sum() .sum()
.let { .let {
buildMetrics.addMetric(BuildPerformanceMetric.BUNDLE_SIZE, it) buildMetrics.addMetric(GradleBuildPerformanceMetric.BUNDLE_SIZE, it)
} }
buildMetricsService.orNull?.also { it.addTask(path, this.javaClass, buildMetrics) } buildMetricsService.orNull?.also { it.addTask(path, this.javaClass, buildMetrics) }
@@ -17,9 +17,7 @@ import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.work.* import org.gradle.work.*
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.compilerRunner.CompilerExecutionSettings import org.jetbrains.kotlin.compilerRunner.CompilerExecutionSettings
@@ -234,8 +232,8 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
fun execute(inputChanges: InputChanges) { fun execute(inputChanges: InputChanges) {
notifyUserAboutExperimentalICOptimizations() notifyUserAboutExperimentalICOptimizations()
val buildMetrics = metrics.get() val buildMetrics = metrics.get()
buildMetrics.addTimeMetric(BuildPerformanceMetric.START_TASK_ACTION_EXECUTION) buildMetrics.addTimeMetric(GradleBuildPerformanceMetric.START_TASK_ACTION_EXECUTION)
buildMetrics.measure(BuildTime.OUT_OF_WORKER_TASK_ACTION) { buildMetrics.measure(GradleBuildTime.OUT_OF_WORKER_TASK_ACTION) {
KotlinBuildStatsService.applyIfInitialised { KotlinBuildStatsService.applyIfInitialised {
if (name.contains("Test")) if (name.contains("Test"))
it.report(BooleanMetrics.TESTS_EXECUTED, true) it.report(BooleanMetrics.TESTS_EXECUTED, true)
@@ -252,7 +250,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
// To prevent this, we backup outputs before incremental build and restore when exception is thrown // To prevent this, we backup outputs before incremental build and restore when exception is thrown
val outputsBackup: TaskOutputsBackup? = val outputsBackup: TaskOutputsBackup? =
if (isIncrementalCompilationEnabled() && inputChanges.isIncremental) if (isIncrementalCompilationEnabled() && inputChanges.isIncremental)
buildMetrics.measure(BuildTime.BACKUP_OUTPUT) { buildMetrics.measure(GradleBuildTime.BACKUP_OUTPUT) {
TaskOutputsBackup( TaskOutputsBackup(
fileSystemOperations, fileSystemOperations,
layout.buildDirectory, layout.buildDirectory,
@@ -20,11 +20,13 @@ import org.gradle.api.tasks.util.PatternSet
import org.gradle.work.DisableCachingByDefault import org.gradle.work.DisableCachingByDefault
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAware import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAware
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer
import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter
import org.jetbrains.kotlin.gradle.utils.fileExtensionCasePermutations import org.jetbrains.kotlin.gradle.utils.fileExtensionCasePermutations
import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.property
import javax.inject.Inject import javax.inject.Inject
@@ -113,8 +115,8 @@ abstract class AbstractKotlinCompileTool<T : CommonToolArguments> @Inject constr
} }
@get:Internal @get:Internal
final override val metrics: Property<BuildMetricsReporter> = project.objects final override val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>> = project.objects
.property(BuildMetricsReporterImpl()) .property(GradleBuildMetricsReporter())
/** /**
* By default, should be set by plugin from [COMPILER_CLASSPATH_CONFIGURATION_NAME] configuration. * By default, should be set by plugin from [COMPILER_CLASSPATH_CONFIGURATION_NAME] configuration.
@@ -1,8 +1,6 @@
package org.jetbrains.kotlin.gradle.tasks package org.jetbrains.kotlin.gradle.tasks
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.buildtools.api.KotlinLogger import org.jetbrains.kotlin.buildtools.api.KotlinLogger
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
@@ -71,7 +69,7 @@ internal fun TaskWithLocalState.cleanOutputsAndLocalState(reason: String? = null
internal fun cleanOutputsAndLocalState( internal fun cleanOutputsAndLocalState(
outputFiles: Iterable<File>, outputFiles: Iterable<File>,
log: KotlinLogger, log: KotlinLogger,
metrics: BuildMetricsReporter, metrics: BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>,
reason: String? = null reason: String? = null
) { ) {
log.kotlinDebug { log.kotlinDebug {
@@ -79,7 +77,7 @@ internal fun cleanOutputsAndLocalState(
"Cleaning output$suffix:" "Cleaning output$suffix:"
} }
metrics.measure(BuildTime.CLEAR_OUTPUT) { metrics.measure(GradleBuildTime.CLEAR_OUTPUT) {
for (file in outputFiles) { for (file in outputFiles) {
when { when {
file.isDirectory -> { file.isDirectory -> {
@@ -43,12 +43,12 @@ class ReportDataTest {
) )
assertNotNull(statisticData) assertNotNull(statisticData)
assertTrue(statisticData.tags.contains(StatTag.KOTLIN_DEBUG)) assertTrue(statisticData.getTags().contains(StatTag.KOTLIN_DEBUG))
assertTrue(statisticData.tags.contains(StatTag.NON_INCREMENTAL)) assertTrue(statisticData.getTags().contains(StatTag.NON_INCREMENTAL))
assertTrue(statisticData.tags.contains(StatTag.KOTLIN_1)) assertTrue(statisticData.getTags().contains(StatTag.KOTLIN_1))
} }
private fun taskRecord(buildMetrics: BuildMetrics) = TaskRecord( private fun taskRecord(buildMetrics: BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>) = TaskRecord(
path = kotlinTaskPath, path = kotlinTaskPath,
classFqName = "org.jetbrains.kotlin.TestTask", classFqName = "org.jetbrains.kotlin.TestTask",
startTimeMs = 10, startTimeMs = 10,
@@ -67,17 +67,17 @@ class ReportDataTest {
fun testMetricFilter() { fun testMetricFilter() {
val buildOperationRecord = taskRecord( val buildOperationRecord = taskRecord(
BuildMetrics( BuildMetrics(
buildPerformanceMetrics = BuildPerformanceMetrics().also { buildPerformanceMetrics = BuildPerformanceMetrics<GradleBuildPerformanceMetric>().also {
it.add(BuildPerformanceMetric.COMPILE_ITERATION) it.add(GradleBuildPerformanceMetric.COMPILE_ITERATION)
it.add(BuildPerformanceMetric.CLASSPATH_ENTRY_COUNT) it.add(GradleBuildPerformanceMetric.CLASSPATH_ENTRY_COUNT)
it.add(BuildPerformanceMetric.BUNDLE_SIZE) it.add(GradleBuildPerformanceMetric.BUNDLE_SIZE)
it.add(BuildPerformanceMetric.CACHE_DIRECTORY_SIZE) it.add(GradleBuildPerformanceMetric.CACHE_DIRECTORY_SIZE)
}, },
buildTimes = BuildTimes().also { buildTimes = BuildTimes<GradleBuildTime>().also {
it.addTimeMs(BuildTime.STORE_BUILD_INFO, 20) it.addTimeMs(GradleBuildTime.STORE_BUILD_INFO, 20)
it.addTimeMs(BuildTime.GRADLE_TASK_ACTION, 100) it.addTimeMs(GradleBuildTime.GRADLE_TASK_ACTION, 100)
it.addTimeMs(BuildTime.RESTORE_OUTPUT_FROM_BACKUP, 10) it.addTimeMs(GradleBuildTime.RESTORE_OUTPUT_FROM_BACKUP, 10)
it.addTimeMs(BuildTime.IC_ANALYZE_JAR_FILES, 10) it.addTimeMs(GradleBuildTime.IC_ANALYZE_JAR_FILES, 10)
} }
) )
) )
@@ -92,22 +92,22 @@ class ReportDataTest {
onlyKotlinTask = true, onlyKotlinTask = true,
additionalTags = setOf(StatTag.KOTLIN_DEBUG), additionalTags = setOf(StatTag.KOTLIN_DEBUG),
metricsToShow = setOf( metricsToShow = setOf(
BuildPerformanceMetric.BUNDLE_SIZE.name,// from TaskExecutionResult GradleBuildPerformanceMetric.BUNDLE_SIZE.name,// from TaskExecutionResult
BuildTime.GRADLE_TASK_ACTION.name,// from buildOperationRecord GradleBuildTime.GRADLE_TASK_ACTION.name,// from buildOperationRecord
BuildPerformanceMetric.COMPILE_ITERATION.name, //from buildOperationRecord GradleBuildPerformanceMetric.COMPILE_ITERATION.name, //from buildOperationRecord
BuildTime.IC_CALCULATE_INITIAL_DIRTY_SET.name, //not set GradleBuildTime.IC_CALCULATE_INITIAL_DIRTY_SET.name, //not set
BuildPerformanceMetric.START_WORKER_EXECUTION.name, //not set GradleBuildPerformanceMetric.START_WORKER_EXECUTION.name, //not set
BuildTime.RESTORE_OUTPUT_FROM_BACKUP.name, //from TaskExecutionResult GradleBuildTime.RESTORE_OUTPUT_FROM_BACKUP.name, //from TaskExecutionResult
) )
) )
assertNotNull(statisticData) assertNotNull(statisticData)
assertEquals(2, statisticData.performanceMetrics.size) assertEquals(2, statisticData.getPerformanceMetrics().size)
assertTrue(statisticData.performanceMetrics.containsKey(BuildPerformanceMetric.BUNDLE_SIZE)) assertTrue(statisticData.getPerformanceMetrics().containsKey(GradleBuildPerformanceMetric.BUNDLE_SIZE))
assertTrue(statisticData.performanceMetrics.containsKey(BuildPerformanceMetric.COMPILE_ITERATION)) assertTrue(statisticData.getPerformanceMetrics().containsKey(GradleBuildPerformanceMetric.COMPILE_ITERATION))
assertEquals(2, statisticData.buildTimesMetrics.size) assertEquals(2, statisticData.getBuildTimesMetrics().size)
assertTrue(statisticData.buildTimesMetrics.containsKey(BuildTime.GRADLE_TASK_ACTION)) assertTrue(statisticData.getBuildTimesMetrics().containsKey(GradleBuildTime.GRADLE_TASK_ACTION))
assertTrue(statisticData.buildTimesMetrics.containsKey(BuildTime.RESTORE_OUTPUT_FROM_BACKUP)) assertTrue(statisticData.getBuildTimesMetrics().containsKey(GradleBuildTime.RESTORE_OUTPUT_FROM_BACKUP))
} }
@Ignore //temporary ignore flaky test @Ignore //temporary ignore flaky test
@@ -120,12 +120,12 @@ class ReportDataTest {
val finishGradleTask = System.nanoTime() val finishGradleTask = System.nanoTime()
val buildOperationRecord = taskRecord( val buildOperationRecord = taskRecord(
BuildMetrics( BuildMetrics<GradleBuildTime, GradleBuildPerformanceMetric>(
buildPerformanceMetrics = BuildPerformanceMetrics().also { buildPerformanceMetrics = BuildPerformanceMetrics<GradleBuildPerformanceMetric>().also {
it.add(BuildPerformanceMetric.FINISH_KOTLIN_DAEMON_EXECUTION, System.currentTimeMillis()) it.add(GradleBuildPerformanceMetric.FINISH_KOTLIN_DAEMON_EXECUTION, System.currentTimeMillis())
it.add(BuildPerformanceMetric.START_WORKER_EXECUTION, TimeUnit.MILLISECONDS.toNanos(startWorker)) it.add(GradleBuildPerformanceMetric.START_WORKER_EXECUTION, TimeUnit.MILLISECONDS.toNanos(startWorker))
it.add(BuildPerformanceMetric.START_TASK_ACTION_EXECUTION, startTaskAction) it.add(GradleBuildPerformanceMetric.START_TASK_ACTION_EXECUTION, startTaskAction)
it.add(BuildPerformanceMetric.CALL_WORKER, TimeUnit.MILLISECONDS.toNanos(callWorker)) it.add(GradleBuildPerformanceMetric.CALL_WORKER, TimeUnit.MILLISECONDS.toNanos(callWorker))
} }
) )
) )
@@ -141,9 +141,9 @@ class ReportDataTest {
additionalTags = setOf(StatTag.KOTLIN_DEBUG), additionalTags = setOf(StatTag.KOTLIN_DEBUG),
) )
assertNotNull(statisticData) assertNotNull(statisticData)
assertEquals(startTaskAction - startGradleTask, statisticData.buildTimesMetrics[BuildTime.GRADLE_TASK_PREPARATION]) assertEquals(startTaskAction - startGradleTask, statisticData.getBuildTimesMetrics()[GradleBuildTime.GRADLE_TASK_PREPARATION])
assertEquals(1, statisticData.buildTimesMetrics[BuildTime.TASK_FINISH_LISTENER_NOTIFICATION]?.sign) assertEquals(1, statisticData.getBuildTimesMetrics()[GradleBuildTime.TASK_FINISH_LISTENER_NOTIFICATION]?.sign)
assertEquals(startWorker - callWorker, statisticData.buildTimesMetrics[BuildTime.RUN_WORKER_DELAY]) assertEquals(startWorker - callWorker, statisticData.getBuildTimesMetrics()[GradleBuildTime.RUN_WORKER_DELAY])
} }
private fun taskFinishEvent(startTime: Long = 1L, endTime: Long =10L) = object : TaskFinishEvent { private fun taskFinishEvent(startTime: Long = 1L, endTime: Long =10L) = object : TaskFinishEvent {