Fix build metrics for JPS
diff --git a/compiler/build-tools/kotlin-build-statistics/src/org/jetbrains/kotlin/build/report/metrics/BuildTime.kt b/compiler/build-tools/kotlin-build-statistics/src/org/jetbrains/kotlin/build/report/metrics/BuildTime.kt
index abdb7e0..686032c 100644
--- a/compiler/build-tools/kotlin-build-statistics/src/org/jetbrains/kotlin/build/report/metrics/BuildTime.kt
+++ b/compiler/build-tools/kotlin-build-statistics/src/org/jetbrains/kotlin/build/report/metrics/BuildTime.kt
@@ -21,9 +21,11 @@
enum class JpsBuildTime(private val parent: JpsBuildTime? = null, private val readableString: String) : BuildTime {
-
- JPS_ITERATION(readableString = "Jps iteration")
+ // @formatter:off
+ JPS_ITERATION(readableString = "Jps iteration"),
+ COMPILATION_ROUND(JPS_ITERATION, "Sources compilation round"),
;
+ // @formatter:on
override fun getReadableString(): String = readableString
override fun getParent(): BuildTime? = parent
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
index c4aa99c..339e8c3 100644
--- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
@@ -23,7 +23,9 @@
import org.jetbrains.kotlin.build.report.ICReporter.ReportSeverity
import org.jetbrains.kotlin.build.report.ICReporterBase
import org.jetbrains.kotlin.build.report.debug
+import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.JpsBuildTime
+import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
@@ -43,6 +45,7 @@
import org.jetbrains.kotlin.jps.incremental.JpsIncrementalCache
import org.jetbrains.kotlin.jps.incremental.JpsLookupStorageManager
import org.jetbrains.kotlin.jps.model.kotlinKind
+import org.jetbrains.kotlin.jps.statistic.JpsBuilderMetricReporter
import org.jetbrains.kotlin.jps.statistic.JpsStatisticsReportService
import org.jetbrains.kotlin.jps.targets.KotlinJvmModuleBuildTarget
import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget
@@ -217,7 +220,7 @@
private fun markAdditionalFilesForInitialRound(
kotlinChunk: KotlinChunk,
chunk: ModuleChunk,
- kotlinContext: KotlinCompileContext
+ kotlinContext: KotlinCompileContext,
) {
val context = kotlinContext.jpsContext
val dirtyFilesHolder = KotlinDirtySourceFilesHolder(
@@ -295,9 +298,25 @@
context: CompileContext,
chunk: ModuleChunk,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
- outputConsumer: OutputConsumer
+ outputConsumer: OutputConsumer,
): ExitCode {
- reportService.moduleBuildStarted(chunk)
+ val reporter = reportService.moduleBuildStarted(chunk)
+ try {
+ return build(context, chunk, dirtyFilesHolder, outputConsumer, reporter).also { reporter.setResult(it) }
+ } finally {
+ reportService.moduleBuildFinished(chunk, context)
+ }
+ }
+
+
+ private fun build(
+ context: CompileContext,
+ chunk: ModuleChunk,
+ dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
+ outputConsumer: OutputConsumer,
+ metricsReporter: JpsBuilderMetricReporter,
+ ): ExitCode {
+
if (chunk.isDummy(context))
return NOTHING_DONE
@@ -322,15 +341,23 @@
val fsOperations = FSOperationsHelper(context, chunk, kotlinDirtyFilesHolder, LOG)
try {
- return reportService.reportMetrics(chunk, JpsBuildTime.JPS_ITERATION) {
+ return metricsReporter.measure(JpsBuildTime.JPS_ITERATION) {
val proposedExitCode =
- doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations)
+ doBuild(
+ chunk,
+ kotlinTarget,
+ context,
+ kotlinDirtyFilesHolder,
+ messageCollector,
+ outputConsumer,
+ fsOperations,
+ metricsReporter
+ )
val actualExitCode =
if (proposedExitCode == OK && fsOperations.hasMarkedDirty) ADDITIONAL_PASS_REQUIRED else proposedExitCode
LOG.debug("Build result: $actualExitCode")
-
context.testingContext?.buildLogger?.buildFinished(actualExitCode)
actualExitCode
}
@@ -344,8 +371,6 @@
LOG.info("Caught exception: $e")
MessageCollectorUtil.reportException(messageCollector, e)
return ABORT
- } finally {
- reportService.moduleBuildFinished(chunk, context)
}
}
@@ -356,7 +381,8 @@
kotlinDirtyFilesHolder: KotlinDirtySourceFilesHolder,
messageCollector: MessageCollectorAdapter,
outputConsumer: OutputConsumer,
- fsOperations: FSOperationsHelper
+ fsOperations: FSOperationsHelper,
+ metricsReporter: JpsBuilderMetricReporter,
): ExitCode {
// Workaround for Android Studio
if (representativeTarget is KotlinJvmModuleBuildTarget && !JavaBuilder.IS_ENABLED[context, true]) {
@@ -440,6 +466,7 @@
kotlinDirtyFilesHolder.allDirtyFiles,
kotlinDirtyFilesHolder.allRemovedFilesFiles
)
+ metricsReporter.addSourcesInformation(kotlinDirtyFilesHolder)
cleanJsOutputs(context, kotlinChunk, incrementalCaches, kotlinDirtyFilesHolder)
@@ -448,16 +475,18 @@
}
val start = System.nanoTime()
- val outputItemCollector = doCompileModuleChunk(
- kotlinChunk,
- representativeTarget,
- kotlinChunk.compilerArguments,
- context,
- kotlinDirtyFilesHolder,
- fsOperations,
- environment,
- incrementalCaches
- )
+ val outputItemCollector = metricsReporter.measure(JpsBuildTime.COMPILATION_ROUND) {
+ doCompileModuleChunk(
+ kotlinChunk,
+ representativeTarget,
+ kotlinChunk.compilerArguments,
+ context,
+ kotlinDirtyFilesHolder,
+ fsOperations,
+ environment,
+ incrementalCaches
+ )
+ }
statisticsLogger.registerStatistic(chunk, System.nanoTime() - start)
@@ -547,7 +576,7 @@
context: CompileContext,
kotlinChunk: KotlinChunk,
incrementalCaches: Map<KotlinModuleBuildTarget<*>, JpsIncrementalCache>,
- kotlinDirtyFilesHolder: KotlinDirtySourceFilesHolder
+ kotlinDirtyFilesHolder: KotlinDirtySourceFilesHolder,
) {
for (target in kotlinChunk.targets) {
val cache = incrementalCaches[target] ?: continue
@@ -590,7 +619,7 @@
dirtyFilesHolder: KotlinDirtySourceFilesHolder,
fsOperations: FSOperationsHelper,
environment: JpsCompilerEnvironment,
- incrementalCaches: Map<KotlinModuleBuildTarget<*>, JpsIncrementalCache>
+ incrementalCaches: Map<KotlinModuleBuildTarget<*>, JpsIncrementalCache>,
): OutputItemsCollector? {
kotlinChunk.targets.forEach {
it.nextRound(context)
@@ -626,7 +655,7 @@
inlineConstTracker: InlineConstTracker,
enumWhenTracker: EnumWhenTracker,
chunk: ModuleChunk,
- messageCollector: MessageCollectorAdapter
+ messageCollector: MessageCollectorAdapter,
): JpsCompilerEnvironment? {
val compilerServices = with(Services.Builder()) {
kotlinModuleBuilderTarget.makeServices(
@@ -674,7 +703,7 @@
private fun getGeneratedFiles(
context: CompileContext,
chunk: ModuleChunk,
- outputItemCollector: OutputItemsCollectorImpl
+ outputItemCollector: OutputItemsCollectorImpl,
): Map<ModuleBuildTarget, List<GeneratedFile>> {
// If there's only one target, this map is empty: get() always returns null, and the representativeTarget will be used below
val sourceToTarget = HashMap<File, ModuleBuildTarget>()
@@ -704,7 +733,7 @@
private fun updateLookupStorage(
lookupTracker: LookupTracker,
lookupStorageManager: JpsLookupStorageManager,
- dirtyFilesHolder: KotlinDirtySourceFilesHolder
+ dirtyFilesHolder: KotlinDirtySourceFilesHolder,
) {
if (lookupTracker !is LookupTrackerImpl)
throw AssertionError("Lookup tracker is expected to be LookupTrackerImpl, got ${lookupTracker::class.java}")
@@ -719,7 +748,7 @@
generatedFiles: Map<ModuleBuildTarget, List<GeneratedFile>>,
kotlinContext: KotlinCompileContext,
incrementalCaches: Map<KotlinModuleBuildTarget<*>, JpsIncrementalCache>,
- fsOperations: FSOperationsHelper
+ fsOperations: FSOperationsHelper,
) {
for ((target, files) in generatedFiles) {
val kotlinModuleBuilderTarget = kotlinContext.targetsBinding[target] ?: continue
@@ -754,7 +783,7 @@
compiledFiles: Set<File>,
lookupStorageManager: JpsLookupStorageManager,
fsOperations: FSOperationsHelper,
- caches: Iterable<JpsIncrementalCache>
+ caches: Iterable<JpsIncrementalCache>,
) {
val allCaches = caches.flatMap { it.thisWithDependentCaches }
val reporter = JpsICReporter()
@@ -780,7 +809,7 @@
private fun ChangesCollector.getDirtyFiles(
caches: Iterable<IncrementalCacheCommon>,
- lookupStorageManager: JpsLookupStorageManager
+ lookupStorageManager: JpsLookupStorageManager,
): FilesToRecompile {
val reporter = JpsICReporter()
val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = getChangedAndImpactedSymbols(caches, reporter)
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/statistic/JpsStatisticsReportService.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/statistic/JpsStatisticsReportService.kt
index aa80b11..a65783d 100644
--- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/statistic/JpsStatisticsReportService.kt
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/statistic/JpsStatisticsReportService.kt
@@ -8,6 +8,7 @@
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.incremental.CompileContext
+import org.jetbrains.jps.incremental.ModuleLevelBuilder
import org.jetbrains.kotlin.build.report.FileReportSettings
import org.jetbrains.kotlin.build.report.HttpReportSettings
import org.jetbrains.kotlin.build.report.metrics.*
@@ -17,15 +18,25 @@
import org.jetbrains.kotlin.build.report.statistics.StatTag
import org.jetbrains.kotlin.build.report.statistics.file.FileReportService
import org.jetbrains.kotlin.compilerRunner.JpsKotlinLogger
+import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder
import java.io.File
import java.net.InetAddress
import java.util.*
import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
interface JpsBuilderMetricReporter : BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> {
fun flush(context: CompileContext): JpsCompileStatisticsData
-
fun buildFinish(moduleChunk: ModuleChunk, context: CompileContext)
+ fun setResult(exitCode: ModuleLevelBuilder.ExitCode)
+ fun addCompiledSources(files: Collection<String>)
+ fun addChangedFiles(files: Collection<String>)
+ fun addSourcesInformation(fileHolder: KotlinDirtySourceFilesHolder)
+
+ fun join(reporter: JpsBuilderMetricReporter)
+
+ fun getModuleName(): String
}
private const val jpsBuildTaskName = "JPS build"
@@ -34,7 +45,7 @@
chunk: ModuleChunk,
private val reporter: BuildMetricsReporterImpl<JpsBuildTime, JpsBuildPerformanceMetric>,
private val label: String? = null,
- private val kotlinVersion: String = "kotlin_version"
+ private val kotlinVersion: String = "kotlin_version",
) :
JpsBuilderMetricReporter, BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> by reporter {
@@ -52,24 +63,52 @@
private val startTime = System.currentTimeMillis()
private var finishTime: Long = 0L
private val tags = HashSet<StatTag>()
- private val moduleString = chunk.name
+ private val module = chunk.name
+ private var exitCode: ModuleLevelBuilder.ExitCode? = null
+ private val compiledSources = HashSet<String>()
+ private val changedFiles = HashSet<String>()
override fun buildFinish(moduleChunk: ModuleChunk, context: CompileContext) {
finishTime = System.currentTimeMillis()
}
+ override fun setResult(exitCode: ModuleLevelBuilder.ExitCode) {
+ this.exitCode = exitCode
+ }
+
+ override fun addCompiledSources(files: Collection<String>) {
+ compiledSources.addAll(files)
+ }
+
+ override fun addChangedFiles(files: Collection<String>) {
+ changedFiles.addAll(files)
+ }
+
+ override fun addSourcesInformation(fileHolder: KotlinDirtySourceFilesHolder) {
+ addCompiledSources(fileHolder.allDirtyFiles.map { it.path })
+ addChangedFiles(fileHolder.allDirtyFiles.map { it.path })
+ addChangedFiles(fileHolder.allRemovedFilesFiles.map { it.path })
+ }
+
+ override fun join(reporter: JpsBuilderMetricReporter) {
+ addMetrics(reporter.getMetrics())
+ addCompiledSources(compiledSources)
+ }
+
+ override fun getModuleName(): String = module
+
override fun flush(context: CompileContext): JpsCompileStatisticsData {
val buildMetrics = reporter.getMetrics()
return JpsCompileStatisticsData(
projectName = context.projectDescriptor.project.name,
label = label,
- taskName = moduleString,
- taskResult = "Unknown",//TODO will be updated in KT-58026
+ taskName = module,
+ taskResult = exitCode?.name,
startTimeMs = startTime,
durationMs = finishTime - startTime,
tags = tags,
buildUuid = uuid.toString(),
- changes = emptyList(), //TODO will be updated in KT-58026
+ changes = changedFiles.toList(),
kotlinVersion = kotlinVersion,
hostName = hostName,
finishTime = finishTime,
@@ -79,7 +118,7 @@
nonIncrementalAttributes = emptySet(),
type = BuildDataType.JPS_DATA.name,
fromKotlinPlugin = true,
- compiledSources = emptyList(),
+ compiledSources = compiledSources.toList(),
skipMessage = null,
icLogLines = emptyList(),
gcTimeMetrics = buildMetrics.gcMetrics.asGcTimeMap(),
@@ -117,17 +156,18 @@
private val loggerAdapter = JpsKotlinLogger(log)
private val httpService = httpReportSettings?.let { HttpReportService(it.url, it.user, it.password) }
- fun moduleBuildStarted(chunk: ModuleChunk) {
+ fun moduleBuildStarted(chunk: ModuleChunk): JpsBuilderMetricReporter {
val moduleName = chunk.name
- if (buildMetrics[moduleName] != null) {
+ buildMetrics[moduleName]?.also {
log.warn("Service already initialized for context")
- return
+ return it
}
log.info("JpsStatisticsReportService: Service started")
- buildMetrics[moduleName] = JpsBuilderMetricReporterImpl(chunk, BuildMetricsReporterImpl())
+ val reporter = JpsBuilderMetricReporterImpl(chunk, BuildMetricsReporterImpl())
+ buildMetrics[moduleName] = reporter
+ return reporter
}
-
fun moduleBuildFinished(chunk: ModuleChunk, context: CompileContext) {
val moduleName = chunk.name
val metrics = buildMetrics.remove(moduleName)
@@ -142,6 +182,14 @@
fun buildFinish(context: CompileContext) {
val compileStatisticsData = finishedModuleBuildMetrics.map { it.flush(context) }
+// finishedModuleBuildMetrics.groupBy { it.getModuleName() }
+// .values.map {
+// it.reduce { first, second ->
+// first.join(second)
+// first
+// }.flush(context)
+// }
+
httpService?.sendData(compileStatisticsData, loggerAdapter)
fileReportSettings?.also {
FileReportService.reportBuildStatInFile(
@@ -151,7 +199,6 @@
}
}
-
fun <T> reportMetrics(chunk: ModuleChunk, metric: JpsBuildTime, action: () -> T): T {
val moduleName = chunk.name
val metrics = buildMetrics[moduleName]
@@ -167,6 +214,7 @@
loggerAdapter.info("Build started for $context")
}
+
}