Add JPS iteration metric

#KT-58026 In progress


Co-authored-by: Nataliya Valtman <Nataliya.Valtman@jetbrains.com>


Merge-request: KT-MR-11365
Merged-by: Aleksei Cherepanov <aleksei.cherepanov@jetbrains.com>
This commit is contained in:
Nataliya.Valtman
2023-07-31 09:15:28 +00:00
committed by Space Team
parent ecdb08952b
commit fb04356829
4 changed files with 145 additions and 118 deletions
@@ -9,7 +9,7 @@ import java.io.Serializable
import kotlin.collections.HashMap import kotlin.collections.HashMap
open class BuildMetricsReporterImpl<B : BuildTime, P : BuildPerformanceMetric> : BuildMetricsReporter<B, P>, Serializable { open class BuildMetricsReporterImpl<B : BuildTime, P : BuildPerformanceMetric> : BuildMetricsReporter<B, P>, Serializable {
private val myBuildTimeStartNs = HashMap<BuildTime, Long>() private val myBuildTimeStartNs = HashMap<B, Long>()
private val myGcPerformance = HashMap<String, GcMetric>() private val myGcPerformance = HashMap<String, GcMetric>()
private val myBuildTimes = BuildTimes<B>() private val myBuildTimes = BuildTimes<B>()
private val myBuildMetrics = BuildPerformanceMetrics<P>() private val myBuildMetrics = BuildPerformanceMetrics<P>()
@@ -101,28 +101,13 @@ enum class GradleBuildTime(private val parent: GradleBuildTime? = null, private
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( SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION(INCREMENTAL_COMPILATION_DAEMON, "Shrink and save current classpath snapshot after compilation"),
INCREMENTAL_COMPILATION_DAEMON, INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT(SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION, "Shrink current classpath snapshot incrementally"),
"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_LOAD_CURRENT_CLASSPATH_SNAPSHOT(INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"), INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT(INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"),
INCREMENTAL_LOAD_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT_AGAINST_PREVIOUS_LOOKUPS( INCREMENTAL_LOAD_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT_AGAINST_PREVIOUS_LOOKUPS(INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load shrunk current classpath snapshot against previous lookups"),
INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT(SHRINK_AND_SAVE_CURRENT_CLASSPATH_SNAPSHOT_AFTER_COMPILATION, "Shrink current classpath snapshot non-incrementally"),
"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"), NON_INCREMENTAL_LOAD_CURRENT_CLASSPATH_SNAPSHOT(NON_INCREMENTAL_SHRINK_CURRENT_CLASSPATH_SNAPSHOT, "Load current classpath snapshot"),
SAVE_SHRUNK_CURRENT_CLASSPATH_SNAPSHOT( SAVE_SHRUNK_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"
),
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)"),
@@ -23,7 +23,6 @@ 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.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
@@ -165,7 +164,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
override fun buildFinished(context: CompileContext) { override fun buildFinished(context: CompileContext) {
ensureKotlinContextDisposed(context) ensureKotlinContextDisposed(context)
reportService.buildFinished(context) reportService.buildFinish(context)
} }
private fun ensureKotlinContextDisposed(context: CompileContext) { private fun ensureKotlinContextDisposed(context: CompileContext) {
@@ -298,6 +297,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>, dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
outputConsumer: OutputConsumer outputConsumer: OutputConsumer
): ExitCode { ): ExitCode {
reportService.moduleBuildStarted(chunk)
if (chunk.isDummy(context)) if (chunk.isDummy(context))
return NOTHING_DONE return NOTHING_DONE
@@ -322,6 +322,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val fsOperations = FSOperationsHelper(context, chunk, kotlinDirtyFilesHolder, LOG) val fsOperations = FSOperationsHelper(context, chunk, kotlinDirtyFilesHolder, LOG)
try { try {
return reportService.reportMetrics(chunk, JpsBuildTime.JPS_ITERATION) {
val proposedExitCode = val proposedExitCode =
doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations) doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations)
@@ -331,7 +332,8 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
LOG.debug("Build result: $actualExitCode") LOG.debug("Build result: $actualExitCode")
context.testingContext?.buildLogger?.buildFinished(actualExitCode) context.testingContext?.buildLogger?.buildFinished(actualExitCode)
return actualExitCode actualExitCode
}
} catch (e: StopBuildException) { } catch (e: StopBuildException) {
LOG.info("Caught exception: $e") LOG.info("Caught exception: $e")
throw e throw e
@@ -342,6 +344,8 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
LOG.info("Caught exception: $e") LOG.info("Caught exception: $e")
MessageCollectorUtil.reportException(messageCollector, e) MessageCollectorUtil.reportException(messageCollector, e)
return ABORT return ABORT
} finally {
reportService.moduleBuildFinished(chunk, context)
} }
} }
@@ -6,24 +6,37 @@
package org.jetbrains.kotlin.jps.statistic package org.jetbrains.kotlin.jps.statistic
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.incremental.CompileContext import org.jetbrains.jps.incremental.CompileContext
import org.jetbrains.kotlin.build.report.FileReportSettings 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.* import org.jetbrains.kotlin.build.report.metrics.*
import org.jetbrains.kotlin.build.report.statistics.* import org.jetbrains.kotlin.build.report.statistics.BuildDataType
import org.jetbrains.kotlin.build.report.statistics.BuildStartParameters
import org.jetbrains.kotlin.build.report.statistics.HttpReportService
import org.jetbrains.kotlin.build.report.statistics.StatTag
import org.jetbrains.kotlin.build.report.statistics.file.FileReportService import org.jetbrains.kotlin.build.report.statistics.file.FileReportService
import org.jetbrains.kotlin.compilerRunner.JpsKotlinLogger import org.jetbrains.kotlin.compilerRunner.JpsKotlinLogger
import java.io.File import java.io.File
import java.util.*
import java.net.InetAddress import java.net.InetAddress
import java.util.*
import kotlin.collections.ArrayList
interface JpsBuilderMetricReporter : BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> { interface JpsBuilderMetricReporter : BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> {
fun flush(context: CompileContext): JpsCompileStatisticsData fun flush(context: CompileContext): JpsCompileStatisticsData
fun buildFinish(moduleChunk: ModuleChunk, context: CompileContext)
} }
private const val jpsBuildTaskName = "JPS build" private const val jpsBuildTaskName = "JPS build"
class JpsBuilderMetricReporterImpl(private val reporter: BuildMetricsReporterImpl<JpsBuildTime, JpsBuildPerformanceMetric>) : JpsBuilderMetricReporter, BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> by reporter { class JpsBuilderMetricReporterImpl(
chunk: ModuleChunk,
private val reporter: BuildMetricsReporterImpl<JpsBuildTime, JpsBuildPerformanceMetric>,
private val label: String? = null,
private val kotlinVersion: String = "kotlin_version"
) :
JpsBuilderMetricReporter, BuildMetricsReporter<JpsBuildTime, JpsBuildPerformanceMetric> by reporter {
companion object { companion object {
private val hostName: String? = try { private val hostName: String? = try {
@@ -32,27 +45,34 @@ class JpsBuilderMetricReporterImpl(private val reporter: BuildMetricsReporterImp
//do nothing //do nothing
null null
} }
private val uuid = UUID.randomUUID()
} }
private val uuid = UUID.randomUUID()
private val startTime = System.currentTimeMillis()
@Suppress("UNCHECKED_CAST") private val startTime = System.currentTimeMillis()
private var finishTime: Long = 0L
private val tags = HashSet<StatTag>()
private val moduleString = chunk.name
override fun buildFinish(moduleChunk: ModuleChunk, context: CompileContext) {
finishTime = System.currentTimeMillis()
}
override fun flush(context: CompileContext): JpsCompileStatisticsData { override fun flush(context: CompileContext): JpsCompileStatisticsData {
val buildMetrics = reporter.getMetrics() val buildMetrics = reporter.getMetrics()
return JpsCompileStatisticsData( return JpsCompileStatisticsData(
projectName = context.projectDescriptor.project.name, projectName = context.projectDescriptor.project.name,
label = "JPS build", //TODO will be updated in KT-58026 label = label,
taskName = jpsBuildTaskName, taskName = moduleString,
taskResult = "Unknown",//TODO will be updated in KT-58026 taskResult = "Unknown",//TODO will be updated in KT-58026
startTimeMs = startTime, startTimeMs = startTime,
durationMs = System.currentTimeMillis() - startTime, durationMs = finishTime - startTime,
tags = emptySet(), tags = tags,
buildUuid = uuid.toString(), buildUuid = uuid.toString(),
changes = emptyList(), //TODO will be updated in KT-58026 changes = emptyList(), //TODO will be updated in KT-58026
kotlinVersion = "kotlin_version", //TODO will be updated in KT-58026 kotlinVersion = kotlinVersion,
hostName = hostName, hostName = hostName,
finishTime = System.currentTimeMillis(), finishTime = finishTime,
buildTimesMetrics = buildMetrics.buildTimes.asMapMs(), buildTimesMetrics = buildMetrics.buildTimes.asMapMs(),
performanceMetrics = buildMetrics.buildPerformanceMetrics.asMap(), performanceMetrics = buildMetrics.buildPerformanceMetrics.asMap(),
compilerArguments = emptyList(), //TODO will be updated in KT-58026 compilerArguments = emptyList(), //TODO will be updated in KT-58026
@@ -91,44 +111,62 @@ class JpsStatisticsReportService {
} }
} }
private val contextMetrics = HashMap<CompileContext, JpsBuilderMetricReporter>() private val buildMetrics = HashMap<String, JpsBuilderMetricReporter>()
private val finishedModuleBuildMetrics = ArrayList<JpsBuilderMetricReporter>()
private val log = Logger.getInstance("#org.jetbrains.kotlin.jps.statistic.KotlinBuilderReportService") private val log = Logger.getInstance("#org.jetbrains.kotlin.jps.statistic.KotlinBuilderReportService")
private val loggerAdapter = JpsKotlinLogger(log) private val loggerAdapter = JpsKotlinLogger(log)
private val httpService = httpReportSettings?.let { HttpReportService(it.url, it.user, it.password) } private val httpService = httpReportSettings?.let { HttpReportService(it.url, it.user, it.password) }
fun buildStarted(context: CompileContext) {
if (contextMetrics[context] != null) {
log.error("Service already initialized for context")
}
contextMetrics[context] = JpsBuilderMetricReporterImpl(BuildMetricsReporterImpl<JpsBuildTime, JpsBuildPerformanceMetric>())
}
fun buildFinished(context: CompileContext) { fun moduleBuildStarted(chunk: ModuleChunk) {
val metrics = contextMetrics.remove(context) val moduleName = chunk.name
if (metrics == null) { if (buildMetrics[moduleName] != null) {
log.error("Service hasn't initialized for context") log.warn("Service already initialized for context")
return return
} }
log.info("JpsStatisticsReportService: Service started")
buildMetrics[moduleName] = JpsBuilderMetricReporterImpl(chunk, BuildMetricsReporterImpl())
}
val compileStatisticsData = metrics.flush(context)
fun moduleBuildFinished(chunk: ModuleChunk, context: CompileContext) {
val moduleName = chunk.name
val metrics = buildMetrics.remove(moduleName)
if (metrics == null) {
log.warn("Service hasn't initialized for context")
return
}
log.info("JpsStatisticsReportService: Service finished")
metrics.buildFinish(chunk, context)
finishedModuleBuildMetrics.add(metrics)
}
fun buildFinish(context: CompileContext) {
val compileStatisticsData = finishedModuleBuildMetrics.map { it.flush(context) }
httpService?.sendData(compileStatisticsData, loggerAdapter) httpService?.sendData(compileStatisticsData, loggerAdapter)
fileReportSettings?.also { fileReportSettings?.also {
FileReportService<JpsBuildTime, JpsBuildPerformanceMetric>(it.buildReportDir, true, loggerAdapter) FileReportService.reportBuildStatInFile(
.process( it.buildReportDir, context.projectDescriptor.project.name, true, compileStatisticsData,
listOf(compileStatisticsData), BuildStartParameters(tasks = listOf(jpsBuildTaskName)), emptyList(), loggerAdapter
BuildStartParameters(tasks = listOf(jpsBuildTaskName))
) )
} }
} }
fun <T> reportMetrics(context: CompileContext, metric: JpsBuildTime, action: () -> T): T {
val metrics = contextMetrics.remove(context) fun <T> reportMetrics(chunk: ModuleChunk, metric: JpsBuildTime, action: () -> T): T {
val moduleName = chunk.name
val metrics = buildMetrics[moduleName]
if (metrics == null) { if (metrics == null) {
log.error("Service hasn't initialized for context") log.warn("Service hasn't initialized for context")
return action.invoke() return action.invoke()
} }
log.info("JpsStatisticsReportService: report metrics")
return metrics.measure(metric, action) return metrics.measure(metric, action)
} }
fun buildStarted(context: CompileContext) {
loggerAdapter.info("Build started for $context")
}
} }