Add minimal statistic report for JPS build
Fix build stat for gradle 8 #KT-56438 Fixed
This commit is contained in:
committed by
Space Team
parent
f3ca465647
commit
e34dd043da
@@ -19,12 +19,14 @@ dependencies {
|
|||||||
compileOnly(intellijCore())
|
compileOnly(intellijCore())
|
||||||
compileOnly(commonDependency("org.jetbrains.intellij.deps:asm-all"))
|
compileOnly(commonDependency("org.jetbrains.intellij.deps:asm-all"))
|
||||||
compileOnly(commonDependency("org.jetbrains.intellij.deps:trove4j"))
|
compileOnly(commonDependency("org.jetbrains.intellij.deps:trove4j"))
|
||||||
|
compileOnly(project(":kotlin-build-statistic"))
|
||||||
|
|
||||||
testCompileOnly(project(":compiler:cli-common"))
|
testCompileOnly(project(":compiler:cli-common"))
|
||||||
testApi(projectTests(":compiler:tests-common"))
|
testApi(projectTests(":compiler:tests-common"))
|
||||||
testApi(commonDependency("junit:junit"))
|
testApi(commonDependency("junit:junit"))
|
||||||
testApi(protobufFull())
|
testApi(protobufFull())
|
||||||
testApi(kotlinStdlib())
|
testApi(kotlinStdlib())
|
||||||
|
testImplementation(project(":kotlin-build-statistic"))
|
||||||
testImplementation(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
testImplementation(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||||
testImplementation("org.reflections:reflections:0.10.2")
|
testImplementation("org.reflections:reflections:0.10.2")
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -143,6 +143,7 @@ val commonCompilerModules = arrayOf(
|
|||||||
":analysis:project-structure",
|
":analysis:project-structure",
|
||||||
":analysis:kt-references",
|
":analysis:kt-references",
|
||||||
":kotlin-build-common",
|
":kotlin-build-common",
|
||||||
|
":kotlin-build-statistic",
|
||||||
).also { extra["commonCompilerModules"] = it }
|
).also { extra["commonCompilerModules"] = it }
|
||||||
|
|
||||||
val firCompilerCoreModules = arrayOf(
|
val firCompilerCoreModules = arrayOf(
|
||||||
@@ -262,7 +263,8 @@ extra["kotlinJpsPluginMavenDependencies"] = listOf(
|
|||||||
":kotlin-util-io",
|
":kotlin-util-io",
|
||||||
":kotlin-util-klib",
|
":kotlin-util-klib",
|
||||||
":kotlin-util-klib-metadata",
|
":kotlin-util-klib-metadata",
|
||||||
":native:kotlin-native-utils"
|
":native:kotlin-native-utils",
|
||||||
|
":kotlin-build-statistic",
|
||||||
)
|
)
|
||||||
|
|
||||||
extra["kotlinJpsPluginMavenDependenciesNonTransitiveLibs"] = listOf(
|
extra["kotlinJpsPluginMavenDependenciesNonTransitiveLibs"] = listOf(
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ val kotlinGradlePluginAndItsRequired = arrayOf(
|
|||||||
":native:kotlin-klib-commonizer-api",
|
":native:kotlin-klib-commonizer-api",
|
||||||
":compiler:build-tools:kotlin-build-tools-api",
|
":compiler:build-tools:kotlin-build-tools-api",
|
||||||
":compiler:build-tools:kotlin-build-tools-impl",
|
":compiler:build-tools:kotlin-build-tools-impl",
|
||||||
|
":compiler:kotlin-build-statistic"
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Task.dependsOnKotlinGradlePluginInstall() {
|
fun Task.dependsOnKotlinGradlePluginInstall() {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ fun <PathProvider : Any> getLibraryFromHome(
|
|||||||
|
|
||||||
fun MessageCollector.toLogger(): Logger =
|
fun MessageCollector.toLogger(): Logger =
|
||||||
object : Logger {
|
object : Logger {
|
||||||
override fun error(message: String) {
|
override fun error(message: String, throwable: Throwable?) {
|
||||||
report(CompilerMessageSeverity.ERROR, message)
|
report(CompilerMessageSeverity.ERROR, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,5 +103,9 @@ fun MessageCollector.toLogger(): Logger =
|
|||||||
override fun log(message: String) {
|
override fun log(message: String) {
|
||||||
report(CompilerMessageSeverity.LOGGING, message)
|
report(CompilerMessageSeverity.LOGGING, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun lifecycle(message: String) {
|
||||||
|
report(CompilerMessageSeverity.INFO, message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ dependencies {
|
|||||||
api(project(":compiler:backend.jvm.entrypoint"))
|
api(project(":compiler:backend.jvm.entrypoint"))
|
||||||
api(project(":kotlin-build-common"))
|
api(project(":kotlin-build-common"))
|
||||||
api(project(":daemon-common"))
|
api(project(":daemon-common"))
|
||||||
|
api(project(":kotlin-build-statistic"))
|
||||||
compileOnly(intellijCore())
|
compileOnly(intellijCore())
|
||||||
|
|
||||||
testApi(commonDependency("junit:junit"))
|
testApi(commonDependency("junit:junit"))
|
||||||
@@ -28,6 +29,7 @@ dependencies {
|
|||||||
testApi(intellijCore())
|
testApi(intellijCore())
|
||||||
testApi(commonDependency("org.jetbrains.intellij.deps:log4j"))
|
testApi(commonDependency("org.jetbrains.intellij.deps:log4j"))
|
||||||
testApi(commonDependency("org.jetbrains.intellij.deps:jdom"))
|
testApi(commonDependency("org.jetbrains.intellij.deps:jdom"))
|
||||||
|
testApi(projectTests(":kotlin-build-statistic"))
|
||||||
|
|
||||||
testImplementation(commonDependency("com.google.code.gson:gson"))
|
testImplementation(commonDependency("com.google.code.gson:gson"))
|
||||||
testRuntimeOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
testRuntimeOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||||
|
|||||||
@@ -106,8 +106,9 @@ val CompilerConfiguration.resolverLogger: Logger
|
|||||||
null -> DummyLogger
|
null -> DummyLogger
|
||||||
else -> object : Logger {
|
else -> object : Logger {
|
||||||
override fun log(message: String) = messageLogger.report(IrMessageLogger.Severity.INFO, message, null)
|
override fun log(message: String) = messageLogger.report(IrMessageLogger.Severity.INFO, message, null)
|
||||||
override fun error(message: String) = messageLogger.report(IrMessageLogger.Severity.ERROR, message, null)
|
override fun error(message: String, throwable: Throwable?) = messageLogger.report(IrMessageLogger.Severity.ERROR, message, null)
|
||||||
override fun warning(message: String) = messageLogger.report(IrMessageLogger.Severity.WARNING, message, null)
|
override fun warning(message: String) = messageLogger.report(IrMessageLogger.Severity.WARNING, message, null)
|
||||||
|
override fun lifecycle(message: String) = messageLogger.report(IrMessageLogger.Severity.INFO, message, null)
|
||||||
|
|
||||||
override fun fatal(message: String): Nothing {
|
override fun fatal(message: String): Nothing {
|
||||||
messageLogger.report(IrMessageLogger.Severity.ERROR, message, null)
|
messageLogger.report(IrMessageLogger.Severity.ERROR, message, null)
|
||||||
|
|||||||
@@ -175,8 +175,9 @@ object GenerationUtils {
|
|||||||
|
|
||||||
fun messageCollectorLogger(collector: MessageCollector) = object : Logger {
|
fun messageCollectorLogger(collector: MessageCollector) = object : Logger {
|
||||||
override fun warning(message: String) = collector.report(CompilerMessageSeverity.STRONG_WARNING, message)
|
override fun warning(message: String) = collector.report(CompilerMessageSeverity.STRONG_WARNING, message)
|
||||||
override fun error(message: String) = collector.report(CompilerMessageSeverity.ERROR, message)
|
override fun error(message: String, throwable: Throwable?) = collector.report(CompilerMessageSeverity.ERROR, message)
|
||||||
override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message)
|
override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message)
|
||||||
|
override fun lifecycle(message: String) = collector.report(CompilerMessageSeverity.INFO, message)
|
||||||
override fun fatal(message: String): Nothing {
|
override fun fatal(message: String): Nothing {
|
||||||
collector.report(CompilerMessageSeverity.ERROR, message)
|
collector.report(CompilerMessageSeverity.ERROR, message)
|
||||||
(collector as? GroupingMessageCollector)?.flush()
|
(collector as? GroupingMessageCollector)?.flush()
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import kotlin.system.exitProcess
|
|||||||
|
|
||||||
interface Logger {
|
interface Logger {
|
||||||
fun log(message: String)
|
fun log(message: String)
|
||||||
fun error(message: String)
|
fun error(message: String, throwable: Throwable? = null)
|
||||||
fun warning(message: String)
|
fun warning(message: String)
|
||||||
fun fatal(message: String): Nothing
|
fun fatal(message: String): Nothing
|
||||||
|
fun lifecycle(message: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WithLogger {
|
interface WithLogger {
|
||||||
@@ -15,10 +16,18 @@ interface WithLogger {
|
|||||||
|
|
||||||
object DummyLogger : Logger {
|
object DummyLogger : Logger {
|
||||||
override fun log(message: String) = println(message)
|
override fun log(message: String) = println(message)
|
||||||
override fun error(message: String) = println("e: $message")
|
override fun error(message: String, throwable: Throwable?) {
|
||||||
|
println("e: $message")
|
||||||
|
throwable?.also {
|
||||||
|
println("${it.message}:\n${it.stackTraceToString()} ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun warning(message: String) = println("w: $message")
|
override fun warning(message: String) = println("w: $message")
|
||||||
override fun fatal(message: String): Nothing {
|
override fun fatal(message: String): Nothing {
|
||||||
println("e: $message")
|
println("e: $message")
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun lifecycle(message: String) = println("i: $message")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ fun resolveSingleFileKlib(
|
|||||||
libraryFile: File,
|
libraryFile: File,
|
||||||
logger: Logger = object : Logger {
|
logger: Logger = object : Logger {
|
||||||
override fun log(message: String) {}
|
override fun log(message: String) {}
|
||||||
override fun error(message: String) = kotlin.error("e: $message")
|
override fun error(message: String, throwable: Throwable?) = kotlin.error("e: $message")
|
||||||
override fun warning(message: String) {}
|
override fun warning(message: String) {}
|
||||||
override fun fatal(message: String) = kotlin.error("e: $message")
|
override fun fatal(message: String) = kotlin.error("e: $message")
|
||||||
|
override fun lifecycle(message: String) {}
|
||||||
},
|
},
|
||||||
strategy: SingleFileKlibResolveStrategy = CompilerSingleFileKlibResolveStrategy
|
strategy: SingleFileKlibResolveStrategy = CompilerSingleFileKlibResolveStrategy
|
||||||
): KotlinLibrary = strategy.resolve(libraryFile, logger)
|
): KotlinLibrary = strategy.resolve(libraryFile, logger)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<trust group="org.jetbrains.kotlin" name="kotlin-build-tools-enum-compat" version="1.9.[0-9](-.+)?" regex="true"/>
|
<trust group="org.jetbrains.kotlin" name="kotlin-build-tools-enum-compat" version="1.9.[0-9](-.+)?" regex="true"/>
|
||||||
<trust group="org.jetbrains.kotlin" name="kotlin-build-tools-api" version="1.9.[0-9](-.+)?" regex="true"/>
|
<trust group="org.jetbrains.kotlin" name="kotlin-build-tools-api" version="1.9.[0-9](-.+)?" regex="true"/>
|
||||||
<trust group="org.jetbrains.kotlin" name="kotlin-build-tools-impl" version="1.9.[0-9](-.+)?" regex="true"/>
|
<trust group="org.jetbrains.kotlin" name="kotlin-build-tools-impl" version="1.9.[0-9](-.+)?" regex="true"/>
|
||||||
|
<trust group="org.jetbrains.kotlin" name="kotlin-build-statistic" version="1.9.0.*" regex="true"/>
|
||||||
<trust group="org.jetbrains.kotlin" name="kotlin-compiler-embeddable" version="1.9.[0-9](-.+)?" regex="true"/>
|
<trust group="org.jetbrains.kotlin" name="kotlin-compiler-embeddable" version="1.9.[0-9](-.+)?" regex="true"/>
|
||||||
<trust group="org.jetbrains.kotlin" name="kotlin-compiler-runner" version="1.9.[0-9](-.+)?" regex="true"/>
|
<trust group="org.jetbrains.kotlin" name="kotlin-compiler-runner" version="1.9.[0-9](-.+)?" regex="true"/>
|
||||||
<trust group="org.jetbrains.kotlin" name="kotlin-daemon-client" version="1.9.[0-9](-.+)?" regex="true"/>
|
<trust group="org.jetbrains.kotlin" name="kotlin-daemon-client" version="1.9.[0-9](-.+)?" regex="true"/>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.jps.KotlinJpsBundle
|
|||||||
import org.jetbrains.kotlin.jps.incremental.JpsIncrementalCache
|
import org.jetbrains.kotlin.jps.incremental.JpsIncrementalCache
|
||||||
import org.jetbrains.kotlin.jps.incremental.JpsLookupStorageManager
|
import org.jetbrains.kotlin.jps.incremental.JpsLookupStorageManager
|
||||||
import org.jetbrains.kotlin.jps.model.kotlinKind
|
import org.jetbrains.kotlin.jps.model.kotlinKind
|
||||||
|
import org.jetbrains.kotlin.jps.statistic.KotlinBuilderReportService
|
||||||
import org.jetbrains.kotlin.jps.targets.KotlinJvmModuleBuildTarget
|
import org.jetbrains.kotlin.jps.targets.KotlinJvmModuleBuildTarget
|
||||||
import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget
|
import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
@@ -67,6 +68,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
|||||||
System.getProperty("kotlin.jps.classesToLoadByParent")?.split(',')?.map { it.trim() } ?: emptyList()
|
System.getProperty("kotlin.jps.classesToLoadByParent")?.split(',')?.map { it.trim() } ?: emptyList()
|
||||||
private val classPrefixesToLoadByParentFromRegistry =
|
private val classPrefixesToLoadByParentFromRegistry =
|
||||||
System.getProperty("kotlin.jps.classPrefixesToLoadByParent")?.split(',')?.map { it.trim() } ?: emptyList()
|
System.getProperty("kotlin.jps.classPrefixesToLoadByParent")?.split(',')?.map { it.trim() } ?: emptyList()
|
||||||
|
private val reportService = KotlinBuilderReportService()
|
||||||
|
|
||||||
val classesToLoadByParent: ClassCondition
|
val classesToLoadByParent: ClassCondition
|
||||||
get() = ClassCondition { className ->
|
get() = ClassCondition { className ->
|
||||||
@@ -100,6 +102,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
|||||||
|
|
||||||
override fun buildStarted(context: CompileContext) {
|
override fun buildStarted(context: CompileContext) {
|
||||||
logSettings(context)
|
logSettings(context)
|
||||||
|
reportService.buildStarted(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logSettings(context: CompileContext) {
|
private fun logSettings(context: CompileContext) {
|
||||||
@@ -160,6 +163,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
|||||||
|
|
||||||
override fun buildFinished(context: CompileContext) {
|
override fun buildFinished(context: CompileContext) {
|
||||||
ensureKotlinContextDisposed(context)
|
ensureKotlinContextDisposed(context)
|
||||||
|
reportService.buildFinished(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureKotlinContextDisposed(context: CompileContext) {
|
private fun ensureKotlinContextDisposed(context: CompileContext) {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.intellij.openapi.diagnostic.Logger
|
||||||
|
|
||||||
|
class JpsLoggerAdapter(private val log: Logger) : org.jetbrains.kotlin.util.Logger {
|
||||||
|
|
||||||
|
override fun log(message: String) {
|
||||||
|
log.info(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun warning(message: String) {
|
||||||
|
log.warn(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fatal(message: String): Nothing {
|
||||||
|
log.error(message)
|
||||||
|
kotlin.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(message: String, throwable: Throwable?) {
|
||||||
|
log.error(message, throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun lifecycle(message: String) {
|
||||||
|
log.info(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.intellij.openapi.diagnostic.Logger
|
||||||
|
import org.jetbrains.jps.incremental.CompileContext
|
||||||
|
import org.jetbrains.kotlin.build.report.FileReportSettings
|
||||||
|
import org.jetbrains.kotlin.build.report.HttpReportSettings
|
||||||
|
import org.jetbrains.kotlin.build.report.metrics.*
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.BuildDataType
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.CompileStatisticsData
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.HttpReportServiceImpl
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.file.FileReportService
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
import java.net.InetAddress
|
||||||
|
|
||||||
|
interface JpsBuilderMetricReporter : BuildMetricsReporter {
|
||||||
|
fun flush(context: CompileContext): CompileStatisticsData
|
||||||
|
}
|
||||||
|
|
||||||
|
//single thread execution
|
||||||
|
class JpsBuilderMetricReporterImpl(private val reporter: BuildMetricsReporterImpl) : JpsBuilderMetricReporter, BuildMetricsReporter by reporter {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log = Logger.getInstance("#org.jetbrains.kotlin.jps.statistic.KotlinBuilderMetricImpl")
|
||||||
|
private val hostName: String? = try {
|
||||||
|
InetAddress.getLocalHost().hostName
|
||||||
|
} catch (_: Exception) {
|
||||||
|
//do nothing
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val uuid = UUID.randomUUID()
|
||||||
|
private val startTime = System.currentTimeMillis()
|
||||||
|
|
||||||
|
override fun flush(context: CompileContext/*, listener: BuildListener*/): CompileStatisticsData {
|
||||||
|
val buildMetrics = reporter.getMetrics()
|
||||||
|
return CompileStatisticsData(
|
||||||
|
projectName = context.projectDescriptor.project.name,
|
||||||
|
label = "JPS build", //TODO
|
||||||
|
taskName = "JPS build",
|
||||||
|
taskResult = "Unknown",//TODO
|
||||||
|
startTimeMs = startTime,
|
||||||
|
durationMs = System.currentTimeMillis() - startTime,
|
||||||
|
tags = emptySet(),
|
||||||
|
buildUuid = uuid.toString(),
|
||||||
|
changes = emptyList(), //TODO
|
||||||
|
kotlinVersion = "kotlin_version", //TODO
|
||||||
|
hostName = hostName,
|
||||||
|
finishTime = System.currentTimeMillis(),
|
||||||
|
buildTimesMetrics = buildMetrics.buildTimes.asMapMs(),
|
||||||
|
performanceMetrics = buildMetrics.buildPerformanceMetrics.asMap(),
|
||||||
|
compilerArguments = emptyList(), //TODO
|
||||||
|
nonIncrementalAttributes = emptySet(),
|
||||||
|
type = BuildDataType.JPS_DATA.name,
|
||||||
|
fromKotlinPlugin = true,
|
||||||
|
compiledSources = emptyList(),
|
||||||
|
skipMessage = null,
|
||||||
|
icLogLines = emptyList(),
|
||||||
|
gcTimeMetrics = buildMetrics.gcMetrics.asGcTimeMap(),
|
||||||
|
gcCountMetrics = buildMetrics.gcMetrics.asGcCountMap(),
|
||||||
|
kotlinLanguageVersion = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO test UserDataHolder in CompileContext to store CompileStatisticsData.Build or KotlinBuilderMetric
|
||||||
|
class KotlinBuilderReportService(
|
||||||
|
private val fileReportSettings: FileReportSettings?,
|
||||||
|
private val httpReportSettings: HttpReportSettings?
|
||||||
|
) {
|
||||||
|
constructor() : this(
|
||||||
|
initFileReportSettings(),
|
||||||
|
initHttpReportSettings(),
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun initFileReportSettings(): FileReportSettings? {
|
||||||
|
return System.getProperty("kotlin.build.report.file.output_dir")?.let { FileReportSettings(File(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initHttpReportSettings(): HttpReportSettings? {
|
||||||
|
val httpReportUrl = System.getProperty("kotlin.build.report.http.url") ?: return null
|
||||||
|
val httpReportUser = System.getProperty("kotlin.build.report.http.user")
|
||||||
|
val httpReportPassword = System.getProperty("kotlin.build.report.http.password")
|
||||||
|
val includeGitBranch = System.getProperty("kotlin.build.report.http.git_branch", "false").toBoolean()
|
||||||
|
val verboseEnvironment = System.getProperty("kotlin.build.report.http.environment.verbose", "false").toBoolean()
|
||||||
|
return HttpReportSettings(httpReportUrl, httpReportUser, httpReportPassword, verboseEnvironment, includeGitBranch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val contextMetrics = HashMap<CompileContext, JpsBuilderMetricReporter>()
|
||||||
|
private val log = Logger.getInstance("#org.jetbrains.kotlin.jps.statistic.KotlinBuilderReportService")
|
||||||
|
private val loggerAdapter = JpsLoggerAdapter(log)
|
||||||
|
private val httpService = httpReportSettings?.let { HttpReportServiceImpl(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())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildFinished(context: CompileContext) {
|
||||||
|
val metrics = contextMetrics.remove(context)
|
||||||
|
if (metrics == null) {
|
||||||
|
log.error("Service hasn't initialized for context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
httpService?.sendData(metrics.flush(context), loggerAdapter)
|
||||||
|
fileReportSettings?.also { FileReportService(it.buildReportDir, true, loggerAdapter) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addMetric(context: CompileContext, metric: BuildTime, value: Long) {
|
||||||
|
val metrics = contextMetrics[context]
|
||||||
|
if (metrics == null) {
|
||||||
|
log.error("Service hasn't initialized for context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
metrics.addTimeMetricNs(metric, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion as GradleKotlinVersion
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
|
||||||
|
|
||||||
|
description = "Kotlin Build Report Common"
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":core:util.runtime"))
|
||||||
|
compileOnly(project(":compiler:util"))
|
||||||
|
compileOnly(project(":kotlin-util-io"))
|
||||||
|
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||||
|
|
||||||
|
compileOnly(kotlinStdlib())
|
||||||
|
compileOnly(intellijCore())
|
||||||
|
implementation(commonDependency("com.google.code.gson:gson"))
|
||||||
|
testApi(kotlinStdlib())
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
publish()
|
||||||
|
|
||||||
|
runtimeJar()
|
||||||
|
sourcesJar()
|
||||||
|
javadocJar()
|
||||||
|
|
||||||
|
testsJar()
|
||||||
|
|
||||||
|
projectTest(parallel = true)
|
||||||
|
|
||||||
|
projectTest("testJUnit5", jUnitMode = JUnitMode.JUnit5, parallel = true) {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.9 level breaks Kotlin Gradle plugins via changes in enums (KT-48872)
|
||||||
|
// We limit api and LV until KGP will stop using Kotlin compiler directly (KT-56574)
|
||||||
|
tasks.withType<KotlinCompilationTask<*>>().configureEach {
|
||||||
|
compilerOptions.apiVersion.value(GradleKotlinVersion.KOTLIN_1_8).finalizeValueOnRead()
|
||||||
|
compilerOptions.languageVersion.value(GradleKotlinVersion.KOTLIN_1_8).finalizeValueOnRead()
|
||||||
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+2
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -57,6 +57,7 @@ class BuildMetricsReporterImpl : BuildMetricsReporter, Serializable {
|
|||||||
when (metric.type) {
|
when (metric.type) {
|
||||||
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())
|
||||||
else -> error("Unable to add time metric for '${metric.type}' type")
|
else -> error("Unable to add time metric for '${metric.type}' type")
|
||||||
}
|
}
|
||||||
|
|
||||||
+6
-4
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -41,13 +41,14 @@ enum class BuildPerformanceMetric(val parent: BuildPerformanceMetric? = null, va
|
|||||||
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(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),
|
LOAD_CLASSPATH_ENTRY_SNAPSHOT_CACHE_MISSES(parent = LOAD_CLASSPATH_SNAPSHOT_EXECUTION_COUNT, "Number of cache misses when loading classpath entry snapshots", type = ValueType.NUMBER),
|
||||||
|
|
||||||
//exact time
|
//time metrics
|
||||||
START_TASK_ACTION_EXECUTION(readableString = "Start time of task action", type = ValueType.MILLISECONDS),
|
START_TASK_ACTION_EXECUTION(readableString = "Start time of task action", type = ValueType.TIME),
|
||||||
|
FINISH_KOTLIN_DAEMON_EXECUTION(readableString = "Finish time of kotlin daemon execution", type = ValueType.TIME),
|
||||||
|
|
||||||
CALL_KOTLIN_DAEMON(readableString = "Finish gradle part of task execution", type = ValueType.NANOSECONDS),
|
CALL_KOTLIN_DAEMON(readableString = "Finish gradle part of task execution", type = ValueType.NANOSECONDS),
|
||||||
CALL_WORKER(readableString = "Worker submit time", type = ValueType.NANOSECONDS),
|
CALL_WORKER(readableString = "Worker submit time", type = ValueType.NANOSECONDS),
|
||||||
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),
|
||||||
FINISH_KOTLIN_DAEMON_EXECUTION(readableString = "Finish kotlin daemon execution", type = ValueType.MILLISECONDS),
|
|
||||||
;
|
;
|
||||||
companion object {
|
companion object {
|
||||||
const val serialVersionUID = 0L
|
const val serialVersionUID = 0L
|
||||||
@@ -63,4 +64,5 @@ enum class ValueType {
|
|||||||
NUMBER,
|
NUMBER,
|
||||||
NANOSECONDS,
|
NANOSECONDS,
|
||||||
MILLISECONDS,
|
MILLISECONDS,
|
||||||
|
TIME
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.build.report
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class FileReportSettings(
|
||||||
|
val buildReportDir: File,
|
||||||
|
val includeMetricsInReport: Boolean = false,
|
||||||
|
) : Serializable {
|
||||||
|
companion object {
|
||||||
|
const val serialVersionUID: Long = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class HttpReportSettings(
|
||||||
|
val url: String,
|
||||||
|
val password: String?,
|
||||||
|
val user: String?,
|
||||||
|
val verboseEnvironment: Boolean,
|
||||||
|
val includeGitBranchName: Boolean
|
||||||
|
) : Serializable {
|
||||||
|
companion object {
|
||||||
|
const val serialVersionUID: Long = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-11
@@ -1,31 +1,31 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* 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.plugin.stat
|
package org.jetbrains.kotlin.build.report.statistic
|
||||||
|
|
||||||
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.BuildPerformanceMetric
|
||||||
import org.jetbrains.kotlin.build.report.metrics.BuildTime
|
import org.jetbrains.kotlin.build.report.metrics.BuildTime
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
|
||||||
|
|
||||||
//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(
|
data class CompileStatisticsData(
|
||||||
val version: Int = 2,
|
val version: Int = 3,
|
||||||
val projectName: String?,
|
val projectName: String?,
|
||||||
val label: String?,
|
val label: String?,
|
||||||
val taskName: String?,
|
val taskName: String,
|
||||||
val taskResult: String,
|
val taskResult: String?,
|
||||||
|
val startTimeMs: Long,
|
||||||
val durationMs: Long,
|
val durationMs: Long,
|
||||||
val tags: List<StatTag>,
|
val tags: Set<StatTag>,
|
||||||
val changes: List<String>,
|
val changes: List<String>,
|
||||||
val buildUuid: String = "Unset",
|
val buildUuid: String = "Unset",
|
||||||
val kotlinVersion: String,
|
val kotlinVersion: String,
|
||||||
val kotlinLanguageVersion: KotlinVersion?,
|
val kotlinLanguageVersion: String?,
|
||||||
val hostName: String? = "Unset",
|
val hostName: String? = "Unset",
|
||||||
val finishTime: Long,
|
val finishTime: Long,
|
||||||
val timestamp: String = formatter.format(finishTime),
|
val timestamp: String = formatter.format(finishTime),
|
||||||
@@ -36,7 +36,11 @@ data class CompileStatisticsData(
|
|||||||
val performanceMetrics: Map<BuildPerformanceMetric, Long>,
|
val performanceMetrics: Map<BuildPerformanceMetric, Long>,
|
||||||
val gcTimeMetrics: Map<String, Long>?,
|
val gcTimeMetrics: Map<String, Long>?,
|
||||||
val gcCountMetrics: Map<String, Long>?,
|
val gcCountMetrics: Map<String, Long>?,
|
||||||
val type: String = BuildDataType.TASK_DATA.name
|
val type: String = BuildDataType.TASK_DATA.name,
|
||||||
|
val fromKotlinPlugin: Boolean?,
|
||||||
|
val compiledSources: List<String> = emptyList(),
|
||||||
|
val skipMessage: String?,
|
||||||
|
val icLogLines: List<String>,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +61,8 @@ enum class StatTag(val readableString: String) {
|
|||||||
|
|
||||||
enum class BuildDataType {
|
enum class BuildDataType {
|
||||||
TASK_DATA,
|
TASK_DATA,
|
||||||
BUILD_DATA
|
BUILD_DATA,
|
||||||
|
JPS_DATA
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sensitive data. This object is used directly for statistic via http
|
//Sensitive data. This object is used directly for statistic via http
|
||||||
@@ -80,7 +85,7 @@ data class BuildFinishStatisticsData(
|
|||||||
val finishTime: Long,
|
val finishTime: Long,
|
||||||
val timestamp: String = formatter.format(finishTime),
|
val timestamp: String = formatter.format(finishTime),
|
||||||
val hostName: String? = "Unset",
|
val hostName: String? = "Unset",
|
||||||
val tags: List<StatTag>,
|
val tags: Set<StatTag>,
|
||||||
val gitBranch: String = "Unset"
|
val gitBranch: String = "Unset"
|
||||||
)
|
)
|
||||||
|
|
||||||
+7
-10
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* 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
|
package org.jetbrains.kotlin.build.report.statistic
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import org.gradle.api.logging.Logger
|
import org.jetbrains.kotlin.util.Logger
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
@@ -23,7 +23,6 @@ class HttpReportServiceImpl(
|
|||||||
private val password: String?,
|
private val password: String?,
|
||||||
private val user: String?,
|
private val user: String?,
|
||||||
) : HttpReportService, Serializable {
|
) : HttpReportService, Serializable {
|
||||||
constructor(httpSettings: HttpReportSettings) : this(httpSettings.url, httpSettings.password, httpSettings.user)
|
|
||||||
|
|
||||||
private var invalidUrl = false
|
private var invalidUrl = false
|
||||||
private var requestPreviousFailed = false
|
private var requestPreviousFailed = false
|
||||||
@@ -33,9 +32,7 @@ class HttpReportServiceImpl(
|
|||||||
if (isResponseBad) {
|
if (isResponseBad) {
|
||||||
val message = "Failed to send statistic to ${connection.url} with ${connection.responseCode}: ${connection.responseMessage}"
|
val message = "Failed to send statistic to ${connection.url} with ${connection.responseCode}: ${connection.responseMessage}"
|
||||||
if (!requestPreviousFailed) {
|
if (!requestPreviousFailed) {
|
||||||
log.warn(message)
|
log.warning(message)
|
||||||
} else {
|
|
||||||
log.debug(message)
|
|
||||||
}
|
}
|
||||||
requestPreviousFailed = true
|
requestPreviousFailed = true
|
||||||
}
|
}
|
||||||
@@ -49,7 +46,7 @@ class HttpReportServiceImpl(
|
|||||||
val connection = try {
|
val connection = try {
|
||||||
URL(url).openConnection() as HttpURLConnection
|
URL(url).openConnection() as HttpURLConnection
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
log.warn("Unable to open connection to ${url}: ${e.message}")
|
log.warning("Unable to open connection to ${url}: ${e.message}")
|
||||||
invalidUrl = true
|
invalidUrl = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -70,12 +67,12 @@ class HttpReportServiceImpl(
|
|||||||
connection.connect()
|
connection.connect()
|
||||||
checkResponseAndLog(connection, log)
|
checkResponseAndLog(connection, log)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.debug("Unexpected exception happened ${e.message}: ${e.stackTrace}")
|
log.warning("Unexpected exception happened ${e.message}: ${e.stackTrace}")
|
||||||
checkResponseAndLog(connection, log)
|
checkResponseAndLog(connection, log)
|
||||||
} finally {
|
} finally {
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.debug("Report statistic by http takes $elapsedTime ms")
|
log.log("Report statistic by http takes $elapsedTime ms")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+294
@@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
* 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.build.report.statistic.file
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.build.report.metrics.*
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.asString
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.formatSize
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.formatTime
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.CompileStatisticsData
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.GradleBuildStartParameters
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
import java.io.File
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class FileReportService(
|
||||||
|
private val outputFile: File,
|
||||||
|
private val printMetrics: Boolean,
|
||||||
|
private val logger: Logger
|
||||||
|
) : Serializable {
|
||||||
|
companion object {
|
||||||
|
private val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").also { it.timeZone = TimeZone.getTimeZone("UTC")}
|
||||||
|
fun reportBuildStatInFile(
|
||||||
|
buildReportDir: File,
|
||||||
|
projectName: String,
|
||||||
|
includeMetricsInReport: Boolean,
|
||||||
|
buildData: List<CompileStatisticsData>,
|
||||||
|
startParameters: GradleBuildStartParameters,
|
||||||
|
failureMessages: List<String>,
|
||||||
|
logger: Logger
|
||||||
|
) {
|
||||||
|
val ts = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Calendar.getInstance().time)
|
||||||
|
val reportFile = buildReportDir.resolve("$projectName-build-$ts.txt")
|
||||||
|
|
||||||
|
FileReportService(
|
||||||
|
outputFile = reportFile,
|
||||||
|
printMetrics = includeMetricsInReport,
|
||||||
|
logger = logger
|
||||||
|
).process(buildData, startParameters, failureMessages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var p: Printer
|
||||||
|
|
||||||
|
fun process(
|
||||||
|
statisticsData: List<CompileStatisticsData>,
|
||||||
|
startParameters: GradleBuildStartParameters,
|
||||||
|
failureMessages: List<String>
|
||||||
|
) {
|
||||||
|
val buildReportPath = outputFile.toPath().toUri().toString()
|
||||||
|
try {
|
||||||
|
outputFile.parentFile.mkdirs()
|
||||||
|
if (!(outputFile.parentFile.exists() && outputFile.parentFile.isDirectory)) {
|
||||||
|
logger.error("Kotlin build report cannot be created: '$outputFile.parentFile' is a file or do not have permissions to create")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile.bufferedWriter().use { writer ->
|
||||||
|
p = Printer(writer)
|
||||||
|
printBuildReport(statisticsData, startParameters, failureMessages)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.lifecycle("Kotlin build report is written to $buildReportPath")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("Could not write Kotlin build report to $buildReportPath", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printBuildReport(
|
||||||
|
statisticsData: List<CompileStatisticsData>,
|
||||||
|
startParameters: GradleBuildStartParameters,
|
||||||
|
failureMessages: List<String>
|
||||||
|
) {
|
||||||
|
// 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
|
||||||
|
// a bit unfamiliar.
|
||||||
|
// TODO: If it is confusing, consider renaming "tasks" to "build operations" in this class.
|
||||||
|
printBuildInfo(startParameters, failureMessages)
|
||||||
|
if (printMetrics) {
|
||||||
|
printMetrics(
|
||||||
|
statisticsData.map { it.buildTimesMetrics }.reduce { agg, value ->
|
||||||
|
(agg.keys + value.keys).associateWith { (agg[it] ?: 0) + (value[it] ?: 0) }
|
||||||
|
},
|
||||||
|
statisticsData.map { it.performanceMetrics }.reduce { agg, value ->
|
||||||
|
(agg.keys + value.keys).associateWith { (agg[it] ?: 0) + (value[it] ?: 0) }
|
||||||
|
},
|
||||||
|
statisticsData.map { it.nonIncrementalAttributes.asSequence() }.reduce { agg, value -> agg + value }.toList(),
|
||||||
|
aggregatedMetric = true
|
||||||
|
)
|
||||||
|
p.println()
|
||||||
|
}
|
||||||
|
printTaskOverview(statisticsData)
|
||||||
|
printTasksLog(statisticsData)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printBuildInfo(startParameters: GradleBuildStartParameters, failureMessages: List<String>) {
|
||||||
|
p.withIndent("Gradle start parameters:") {
|
||||||
|
startParameters.let {
|
||||||
|
p.println("tasks = ${it.tasks}")
|
||||||
|
p.println("excluded tasks = ${it.excludedTasks}")
|
||||||
|
p.println("current dir = ${it.currentDir}")
|
||||||
|
p.println("project properties args = ${it.projectProperties}")
|
||||||
|
p.println("system properties args = ${it.systemProperties}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.println()
|
||||||
|
|
||||||
|
if (failureMessages.isNotEmpty()) {
|
||||||
|
p.println("Build failed: ${failureMessages}")
|
||||||
|
p.println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printMetrics(
|
||||||
|
buildTimesMetrics: Map<BuildTime, Long>,
|
||||||
|
performanceMetrics: Map<BuildPerformanceMetric, Long>,
|
||||||
|
nonIncrementalAttributes: Collection<BuildAttribute>,
|
||||||
|
gcTimeMetrics: Map<String, Long>? = emptyMap(),
|
||||||
|
gcCountMetrics: Map<String, Long>? = emptyMap(),
|
||||||
|
aggregatedMetric: Boolean = false
|
||||||
|
) {
|
||||||
|
printBuildTimes(buildTimesMetrics)
|
||||||
|
if (aggregatedMetric) p.println()
|
||||||
|
|
||||||
|
printBuildPerformanceMetrics(performanceMetrics)
|
||||||
|
if (aggregatedMetric) p.println()
|
||||||
|
|
||||||
|
printBuildAttributes(nonIncrementalAttributes)
|
||||||
|
|
||||||
|
//TODO: KT-57310 Implement build GC metric in
|
||||||
|
if (!aggregatedMetric) {
|
||||||
|
printGcMetrics(gcTimeMetrics, gcCountMetrics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printGcMetrics(
|
||||||
|
gcTimeMetrics: Map<String, Long>?,
|
||||||
|
gcCountMetrics: Map<String, Long>?
|
||||||
|
) {
|
||||||
|
val keys = HashSet<String>()
|
||||||
|
gcCountMetrics?.keys?.also { keys.addAll(it) }
|
||||||
|
gcTimeMetrics?.keys?.also { keys.addAll(it) }
|
||||||
|
if (keys.isEmpty()) return
|
||||||
|
|
||||||
|
p.withIndent("GC metrics:") {
|
||||||
|
for (key in keys) {
|
||||||
|
p.println("$key:")
|
||||||
|
p.withIndent {
|
||||||
|
gcCountMetrics?.get(key)?.also { p.println("GC count: ${it}") }
|
||||||
|
gcTimeMetrics?.get(key)?.also { p.println("GC time: ${formatTime(it)}") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printBuildTimes(buildTimes: Map<BuildTime, Long>) {
|
||||||
|
if (buildTimes.isEmpty()) return
|
||||||
|
|
||||||
|
p.println("Time metrics:")
|
||||||
|
p.withIndent {
|
||||||
|
val visitedBuildTimes = HashSet<BuildTime>()
|
||||||
|
fun printBuildTime(buildTime: BuildTime) {
|
||||||
|
if (!visitedBuildTimes.add(buildTime)) return
|
||||||
|
|
||||||
|
val timeMs = buildTimes[buildTime]
|
||||||
|
if (timeMs != null) {
|
||||||
|
p.println("${buildTime.readableString}: ${formatTime(timeMs)}")
|
||||||
|
p.withIndent {
|
||||||
|
BuildTime.children[buildTime]?.forEach { printBuildTime(it) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Skip formatting if parent metric does not set
|
||||||
|
BuildTime.children[buildTime]?.forEach { printBuildTime(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (buildTime in BuildTime.values()) {
|
||||||
|
if (buildTime.parent != null) continue
|
||||||
|
|
||||||
|
printBuildTime(buildTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printBuildPerformanceMetrics(buildMetrics: Map<BuildPerformanceMetric, Long>) {
|
||||||
|
if (buildMetrics.isEmpty()) return
|
||||||
|
|
||||||
|
p.withIndent("Size metrics:") {
|
||||||
|
for (metric in BuildPerformanceMetric.values()) {
|
||||||
|
buildMetrics[metric]?.let { printSizeMetric(metric, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printSizeMetric(sizeMetric: BuildPerformanceMetric, value: Long) {
|
||||||
|
fun BuildPerformanceMetric.numberOfAncestors(): Int {
|
||||||
|
var count = 0
|
||||||
|
var parent: BuildPerformanceMetric? = parent
|
||||||
|
while (parent != null) {
|
||||||
|
count++
|
||||||
|
parent = parent.parent
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
val indentLevel = sizeMetric.numberOfAncestors()
|
||||||
|
|
||||||
|
repeat(indentLevel) { p.pushIndent() }
|
||||||
|
when (sizeMetric.type) {
|
||||||
|
ValueType.BYTES -> p.println("${sizeMetric.readableString}: ${formatSize(value)}")
|
||||||
|
ValueType.NUMBER -> p.println("${sizeMetric.readableString}: $value")
|
||||||
|
ValueType.NANOSECONDS -> p.println("${sizeMetric.readableString}: $value")
|
||||||
|
ValueType.MILLISECONDS -> p.println("${sizeMetric.readableString}: ${formatTime(value)}")
|
||||||
|
ValueType.TIME -> p.println("${sizeMetric.readableString}: ${formatter.format(value)}")
|
||||||
|
}
|
||||||
|
repeat(indentLevel) { p.popIndent() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printBuildAttributes(buildAttributes: Collection<BuildAttribute>) {
|
||||||
|
if (buildAttributes.isEmpty()) return
|
||||||
|
|
||||||
|
val buildAttributesMap = buildAttributes.groupingBy { it }.eachCount()
|
||||||
|
p.withIndent("Build attributes:") {
|
||||||
|
val attributesByKind = buildAttributesMap.entries.groupBy { it.key.kind }.toSortedMap()
|
||||||
|
for ((kind, attributesCounts) in attributesByKind) {
|
||||||
|
printMap(p, kind.name, attributesCounts.associate { (k, v) -> k.readableString to v })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printTaskOverview(statisticsData: Collection<CompileStatisticsData>) {
|
||||||
|
var allTasksTimeMs = 0L
|
||||||
|
var kotlinTotalTimeMs = 0L
|
||||||
|
val kotlinTasks = ArrayList<CompileStatisticsData>()
|
||||||
|
|
||||||
|
for (task in statisticsData) {
|
||||||
|
val taskTimeMs = task.durationMs
|
||||||
|
allTasksTimeMs += taskTimeMs
|
||||||
|
|
||||||
|
if (task.fromKotlinPlugin == true) {
|
||||||
|
kotlinTotalTimeMs += taskTimeMs
|
||||||
|
kotlinTasks.add(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kotlinTasks.isEmpty()) {
|
||||||
|
p.println("No Kotlin task was run")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val ktTaskPercent = (kotlinTotalTimeMs.toDouble() / allTasksTimeMs * 100).asString(1)
|
||||||
|
p.println("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeMs)} ($ktTaskPercent % of all tasks time)")
|
||||||
|
|
||||||
|
val table = TextTable("Time", "% of Kotlin time", "Task")
|
||||||
|
for (task in kotlinTasks.sortedWith(compareBy({ -it.durationMs }, { it.startTimeMs }))) {
|
||||||
|
val timeMs = task.durationMs
|
||||||
|
val percent = (timeMs.toDouble() / kotlinTotalTimeMs * 100).asString(1)
|
||||||
|
table.addRow(formatTime(timeMs), "$percent %", task.taskName)
|
||||||
|
}
|
||||||
|
table.printTo(p)
|
||||||
|
p.println()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printTasksLog(statisticsData: List<CompileStatisticsData>) {
|
||||||
|
for (task in statisticsData.sortedWith(compareBy({ -it.durationMs }, { it.startTimeMs }))) {
|
||||||
|
printTaskLog(task)
|
||||||
|
p.println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printTaskLog(statisticsData: CompileStatisticsData) {
|
||||||
|
val skipMessage = statisticsData.skipMessage
|
||||||
|
if (skipMessage != null) {
|
||||||
|
p.println("Task '${statisticsData.taskName}' was skipped: $skipMessage")
|
||||||
|
} else {
|
||||||
|
p.println("Task '${statisticsData.taskName}' finished in ${formatTime(statisticsData.durationMs)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statisticsData.icLogLines.isNotEmpty()) {
|
||||||
|
p.withIndent("Compilation log for task '${statisticsData.taskName}':") {
|
||||||
|
statisticsData.icLogLines.forEach { p.println(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printMetrics) {
|
||||||
|
printMetrics(statisticsData.buildTimesMetrics, statisticsData.performanceMetrics, statisticsData.nonIncrementalAttributes,
|
||||||
|
statisticsData.gcTimeMetrics, statisticsData.gcCountMetrics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.build.report.statistic.file
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
internal fun printMap(p: Printer, name: String, mapping: Map<String, Int>) {
|
||||||
|
if (mapping.isEmpty()) return
|
||||||
|
|
||||||
|
if (mapping.size == 1) {
|
||||||
|
p.println("$name: ${mapping.keys.single()}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.withIndent("$name:") {
|
||||||
|
val sortedEnumMap = mapping.toSortedMap()
|
||||||
|
for ((k, v) in sortedEnumMap) {
|
||||||
|
p.println("$k($v)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TextTable(vararg columnNames: String) {
|
||||||
|
private val rows = ArrayList<List<String>>()
|
||||||
|
private val columnsCount = columnNames.size
|
||||||
|
private val maxLengths = IntArray(columnsCount) { columnNames[it].length }
|
||||||
|
|
||||||
|
init {
|
||||||
|
rows.add(columnNames.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addRow(vararg row: String) {
|
||||||
|
check(row.size == columnsCount) { "Row size ${row.size} differs from columns count $columnsCount" }
|
||||||
|
rows.add(row.toList())
|
||||||
|
|
||||||
|
for ((i, col) in row.withIndex()) {
|
||||||
|
maxLengths[i] = max(maxLengths[i], col.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printTo(p: Printer) {
|
||||||
|
for (row in rows) {
|
||||||
|
val rowStr = row.withIndex().joinToString("|") { (i, col) -> col.padEnd(maxLengths[i], ' ') }
|
||||||
|
p.println(rowStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-14
@@ -1,19 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* 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.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
package org.jetbrains.kotlin.gradle.utils
|
|
||||||
|
package org.jetbrains.kotlin.build.report.statistic.file
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.build.report.statistic
|
||||||
|
|
||||||
|
internal fun formatTime(ms: Long): String {
|
||||||
|
val seconds = ms.toDouble() / 1_000
|
||||||
|
return seconds.asString(2) + " s"
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val kbSize = 1024
|
||||||
|
private const val mbSize = kbSize * 1024
|
||||||
|
private const val gbSize = mbSize * 1024
|
||||||
|
|
||||||
|
public fun formatSize(sizeInBytes: Long): String = when {
|
||||||
|
sizeInBytes / gbSize >= 1 -> "${(sizeInBytes.toDouble() / gbSize).asString(1)} GB"
|
||||||
|
sizeInBytes / mbSize >= 1 -> "${(sizeInBytes.toDouble() / mbSize).asString(1)} MB"
|
||||||
|
sizeInBytes / kbSize >= 1 -> "${(sizeInBytes.toDouble() / kbSize).asString(1)} KB"
|
||||||
|
else -> "$sizeInBytes B"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Double.asString(decPoints: Int): String = "%,.${decPoints}f".format(this)
|
||||||
+2
-1
@@ -38,12 +38,13 @@ class KonanLibrariesResolveSupport(
|
|||||||
object : Logger {
|
object : Logger {
|
||||||
private val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
private val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||||
override fun warning(message: String)= collector.report(CompilerMessageSeverity.STRONG_WARNING, message)
|
override fun warning(message: String)= collector.report(CompilerMessageSeverity.STRONG_WARNING, message)
|
||||||
override fun error(message: String) = collector.report(CompilerMessageSeverity.ERROR, message)
|
override fun error(message: String, throwable: Throwable?) = collector.report(CompilerMessageSeverity.ERROR, message)
|
||||||
override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message)
|
override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message)
|
||||||
override fun fatal(message: String): Nothing {
|
override fun fatal(message: String): Nothing {
|
||||||
collector.report(CompilerMessageSeverity.ERROR, message)
|
collector.report(CompilerMessageSeverity.ERROR, message)
|
||||||
throw KonanCompilationException()
|
throw KonanCompilationException()
|
||||||
}
|
}
|
||||||
|
override fun lifecycle(message: String) =collector.report(CompilerMessageSeverity.LOGGING, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val resolver = defaultResolver(
|
private val resolver = defaultResolver(
|
||||||
|
|||||||
@@ -88,9 +88,10 @@ fun error(text: String): Nothing {
|
|||||||
|
|
||||||
object KlibToolLogger : Logger {
|
object KlibToolLogger : Logger {
|
||||||
override fun warning(message: String) = org.jetbrains.kotlin.cli.klib.warn(message)
|
override fun warning(message: String) = org.jetbrains.kotlin.cli.klib.warn(message)
|
||||||
override fun error(message: String) = org.jetbrains.kotlin.cli.klib.warn(message)
|
override fun error(message: String, throwable: Throwable?) = org.jetbrains.kotlin.cli.klib.warn(message)
|
||||||
override fun fatal(message: String) = org.jetbrains.kotlin.cli.klib.error(message)
|
override fun fatal(message: String) = org.jetbrains.kotlin.cli.klib.error(message)
|
||||||
override fun log(message: String) = println(message)
|
override fun log(message: String) = println(message)
|
||||||
|
override fun lifecycle(message: String) = println(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultRepository = File(DependencyProcessor.localKonanDir.resolve("klib").absolutePath)
|
val defaultRepository = File(DependencyProcessor.localKonanDir.resolve("klib").absolutePath)
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ dependencies {
|
|||||||
testImplementation(project(":kotlin-compiler-embeddable"))
|
testImplementation(project(":kotlin-compiler-embeddable"))
|
||||||
testImplementation(commonDependency("org.jetbrains.intellij.deps:jdom"))
|
testImplementation(commonDependency("org.jetbrains.intellij.deps:jdom"))
|
||||||
testImplementation(project(":compiler:cli-common"))
|
testImplementation(project(":compiler:cli-common"))
|
||||||
|
testImplementation(project(":kotlin-build-statistic"))
|
||||||
// testCompileOnly dependency on non-shaded artifacts is needed for IDE support
|
// testCompileOnly dependency on non-shaded artifacts is needed for IDE support
|
||||||
// testRuntimeOnly on shaded artifact is needed for running tests with shaded compiler
|
// testRuntimeOnly on shaded artifact is needed for running tests with shaded compiler
|
||||||
testCompileOnly(project(":kotlin-gradle-plugin-test-utils-embeddable"))
|
testCompileOnly(project(":kotlin-gradle-plugin-test-utils-embeddable"))
|
||||||
|
|||||||
+1
-2
@@ -17,9 +17,8 @@ import io.ktor.server.engine.*
|
|||||||
import io.ktor.server.netty.*
|
import io.ktor.server.netty.*
|
||||||
import io.ktor.util.*
|
import io.ktor.util.*
|
||||||
import io.ktor.util.collections.*
|
import io.ktor.util.collections.*
|
||||||
import org.gradle.api.logging.LogLevel
|
|
||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.*
|
import org.jetbrains.kotlin.build.report.statistic.*
|
||||||
import org.jetbrains.kotlin.gradle.report.BuildReportType
|
import org.jetbrains.kotlin.gradle.report.BuildReportType
|
||||||
import org.jetbrains.kotlin.gradle.testbase.*
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ dependencies {
|
|||||||
commonCompileOnly(intellijCore())
|
commonCompileOnly(intellijCore())
|
||||||
commonCompileOnly(commonDependency("org.jetbrains.teamcity:serviceMessages"))
|
commonCompileOnly(commonDependency("org.jetbrains.teamcity:serviceMessages"))
|
||||||
commonCompileOnly("com.gradle:gradle-enterprise-gradle-plugin:3.12.4")
|
commonCompileOnly("com.gradle:gradle-enterprise-gradle-plugin:3.12.4")
|
||||||
commonCompileOnly(commonDependency("com.google.code.gson:gson"))
|
|
||||||
commonCompileOnly(commonDependency("com.google.guava:guava"))
|
commonCompileOnly(commonDependency("com.google.guava:guava"))
|
||||||
commonCompileOnly("de.undercouch:gradle-download-task:4.1.1")
|
commonCompileOnly("de.undercouch:gradle-download-task:4.1.1")
|
||||||
commonCompileOnly("com.github.gundy:semver4j:0.16.4:nodeps") {
|
commonCompileOnly("com.github.gundy:semver4j:0.16.4:nodeps") {
|
||||||
@@ -67,6 +66,7 @@ dependencies {
|
|||||||
commonImplementation(project(":native:kotlin-klib-commonizer-api"))
|
commonImplementation(project(":native:kotlin-klib-commonizer-api"))
|
||||||
commonImplementation(project(":kotlin-project-model"))
|
commonImplementation(project(":kotlin-project-model"))
|
||||||
commonImplementation(project(":compiler:build-tools:kotlin-build-tools-api"))
|
commonImplementation(project(":compiler:build-tools:kotlin-build-tools-api"))
|
||||||
|
commonImplementation(project(":kotlin-build-statistic"))
|
||||||
|
|
||||||
commonRuntimeOnly(project(":kotlin-compiler-embeddable"))
|
commonRuntimeOnly(project(":kotlin-compiler-embeddable"))
|
||||||
commonRuntimeOnly(project(":kotlin-annotation-processing-embeddable"))
|
commonRuntimeOnly(project(":kotlin-annotation-processing-embeddable"))
|
||||||
@@ -111,6 +111,7 @@ dependencies {
|
|||||||
testImplementation(commonDependency("junit:junit"))
|
testImplementation(commonDependency("junit:junit"))
|
||||||
testImplementation(project(":kotlin-gradle-statistics"))
|
testImplementation(project(":kotlin-gradle-statistics"))
|
||||||
testImplementation(project(":kotlin-tooling-metadata"))
|
testImplementation(project(":kotlin-tooling-metadata"))
|
||||||
|
testImplementation(projectTests(":kotlin-build-statistic"))
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.commonCompileClasspath.get().exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
|
configurations.commonCompileClasspath.get().exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
|
||||||
|
|||||||
+16
-6
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
|||||||
import org.jetbrains.kotlin.gradle.logging.*
|
import org.jetbrains.kotlin.gradle.logging.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.StatTag
|
||||||
import org.jetbrains.kotlin.gradle.report.*
|
import org.jetbrains.kotlin.gradle.report.*
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
||||||
import org.jetbrains.kotlin.gradle.tasks.cleanOutputsAndLocalState
|
import org.jetbrains.kotlin.gradle.tasks.cleanOutputsAndLocalState
|
||||||
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.incremental.IncrementalModuleInfo
|
|||||||
import org.jetbrains.kotlin.incremental.util.ExceptionLocation
|
import org.jetbrains.kotlin.incremental.util.ExceptionLocation
|
||||||
import org.jetbrains.kotlin.incremental.util.reportException
|
import org.jetbrains.kotlin.incremental.util.reportException
|
||||||
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
@@ -34,6 +36,7 @@ import java.util.*
|
|||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.collections.HashSet
|
||||||
|
|
||||||
internal class ProjectFilesForCompilation(
|
internal class ProjectFilesForCompilation(
|
||||||
val projectRootFile: File,
|
val projectRootFile: File,
|
||||||
@@ -41,10 +44,9 @@ internal class ProjectFilesForCompilation(
|
|||||||
val sessionFlagFile: File,
|
val sessionFlagFile: File,
|
||||||
val buildDir: File
|
val buildDir: File
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
//TODO
|
constructor(logger: Logger, projectDir:File, buildDir: File, projectName: String, projectCacheDirProvider: File, sessionDir: File) : this(
|
||||||
constructor(logger: Logger, projectDir:File, buildDir: File, prjectName: String, projectCacheDirProvider: File, sessionDir: File) : this(
|
|
||||||
projectRootFile = projectDir,
|
projectRootFile = projectDir,
|
||||||
clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(logger, prjectName),
|
clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(logger, projectName),
|
||||||
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(logger, sessionDir, projectCacheDirProvider),
|
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(logger, sessionDir, projectCacheDirProvider),
|
||||||
buildDir = buildDir
|
buildDir = buildDir
|
||||||
)
|
)
|
||||||
@@ -114,7 +116,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
|
|||||||
TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } }
|
TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } }
|
||||||
?: run {
|
?: run {
|
||||||
val logger = LoggerFactory.getLogger("GradleKotlinCompilerWork")
|
val logger = LoggerFactory.getLogger("GradleKotlinCompilerWork")
|
||||||
val kotlinLogger = if (logger is org.gradle.api.logging.Logger) {
|
val kotlinLogger = if (logger is Logger) {
|
||||||
GradleKotlinLogger(logger)
|
GradleKotlinLogger(logger)
|
||||||
} else SL4JKotlinLogger(logger)
|
} else SL4JKotlinLogger(logger)
|
||||||
|
|
||||||
@@ -144,8 +146,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
|
|||||||
kotlinLanguageVersion = kotlinLanguageVersion,
|
kotlinLanguageVersion = kotlinLanguageVersion,
|
||||||
changedFiles = incrementalCompilationEnvironment?.changedFiles,
|
changedFiles = incrementalCompilationEnvironment?.changedFiles,
|
||||||
compilerArguments = if (reportingSettings.includeCompilerArguments) compilerArgs else emptyArray(),
|
compilerArguments = if (reportingSettings.includeCompilerArguments) compilerArgs else emptyArray(),
|
||||||
withAbiSnapshot = incrementalCompilationEnvironment?.withAbiSnapshot,
|
tags = collectStatTags(),
|
||||||
withArtifactTransform = incrementalCompilationEnvironment?.classpathChanges is ClasspathChanges.ClasspathSnapshotEnabled
|
|
||||||
)
|
)
|
||||||
metrics.endMeasure(BuildTime.RUN_COMPILATION_IN_WORKER)
|
metrics.endMeasure(BuildTime.RUN_COMPILATION_IN_WORKER)
|
||||||
val result = TaskExecutionResult(buildMetrics = metrics.getMetrics(), icLogLines = icLogLines, taskInfo = taskInfo)
|
val result = TaskExecutionResult(buildMetrics = metrics.getMetrics(), icLogLines = icLogLines, taskInfo = taskInfo)
|
||||||
@@ -153,6 +154,15 @@ internal class GradleKotlinCompilerWork @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun collectStatTags(): Set<StatTag> {
|
||||||
|
val statTags = HashSet<StatTag>()
|
||||||
|
incrementalCompilationEnvironment?.withAbiSnapshot?.ifTrue { statTags.add(StatTag.ABI_SNAPSHOT) }
|
||||||
|
if (incrementalCompilationEnvironment?.classpathChanges is ClasspathChanges.ClasspathSnapshotEnabled) {
|
||||||
|
statTags.add(StatTag.ARTIFACT_TRANSFORM)
|
||||||
|
}
|
||||||
|
return statTags
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileWithDaemonOrFallbackImpl(messageCollector: MessageCollector): Pair<ExitCode, KotlinCompilerExecutionStrategy> {
|
private fun compileWithDaemonOrFallbackImpl(messageCollector: MessageCollector): Pair<ExitCode, KotlinCompilerExecutionStrategy> {
|
||||||
with(log) {
|
with(log) {
|
||||||
kotlinDebug { "Kotlin compiler class: $compilerClassName" }
|
kotlinDebug { "Kotlin compiler class: $compilerClassName" }
|
||||||
|
|||||||
-5
@@ -12,8 +12,6 @@ import org.gradle.api.provider.Provider
|
|||||||
import org.gradle.api.services.BuildService
|
import org.gradle.api.services.BuildService
|
||||||
import org.gradle.api.services.BuildServiceParameters
|
import org.gradle.api.services.BuildServiceParameters
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.projectCacheDir
|
import org.jetbrains.kotlin.gradle.utils.projectCacheDir
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -65,9 +63,6 @@ internal abstract class KotlinGradleBuildServices : BuildService<KotlinGradleBui
|
|||||||
override fun close() {
|
override fun close() {
|
||||||
buildHandler.buildFinished(parameters.projectCacheDir)
|
buildHandler.buildFinished(parameters.projectCacheDir)
|
||||||
log.kotlinDebug(DISPOSE_MESSAGE)
|
log.kotlinDebug(DISPOSE_MESSAGE)
|
||||||
|
|
||||||
TaskLoggers.clear()
|
|
||||||
TaskExecutionResults.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
+1
-7
@@ -98,13 +98,7 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
|
|||||||
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
|
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildMetricsService.registerIfAbsent(project)?.also { buildMetricsService ->
|
BuildMetricsService.registerIfAbsent(project)
|
||||||
val buildEventsListenerRegistryHolder = BuildEventsListenerRegistryHolder.getInstance(project)
|
|
||||||
buildEventsListenerRegistryHolder.listenerRegistry.onTaskCompletion(buildMetricsService)
|
|
||||||
BuildReportsService.registerIfAbsent(project, buildMetricsService).also {
|
|
||||||
buildEventsListenerRegistryHolder.listenerRegistry.onTaskCompletion(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addKotlinCompilerConfiguration(project: Project) {
|
private fun addKotlinCompilerConfiguration(project: Project) {
|
||||||
|
|||||||
+165
-56
@@ -7,14 +7,16 @@ package org.jetbrains.kotlin.gradle.report
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.Task
|
import org.gradle.api.Task
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
|
import org.gradle.api.invocation.Gradle
|
||||||
import org.gradle.api.logging.Logging
|
import org.gradle.api.logging.Logging
|
||||||
|
import org.gradle.api.provider.ListProperty
|
||||||
import org.gradle.api.provider.Property
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.services.BuildService
|
import org.gradle.api.services.BuildService
|
||||||
import org.gradle.api.services.BuildServiceParameters
|
import org.gradle.api.services.BuildServiceParameters
|
||||||
import org.gradle.api.tasks.Internal
|
import org.gradle.api.tasks.Internal
|
||||||
import org.gradle.tooling.events.FailureResult
|
import org.gradle.tooling.events.FailureResult
|
||||||
import org.gradle.tooling.events.FinishEvent
|
|
||||||
import org.gradle.tooling.events.OperationCompletionListener
|
import org.gradle.tooling.events.OperationCompletionListener
|
||||||
import org.gradle.tooling.events.task.TaskExecutionResult
|
import org.gradle.tooling.events.task.TaskExecutionResult
|
||||||
import org.gradle.tooling.events.task.TaskFailureResult
|
import org.gradle.tooling.events.task.TaskFailureResult
|
||||||
@@ -24,13 +26,22 @@ import org.jetbrains.kotlin.build.report.metrics.BuildMetrics
|
|||||||
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.BuildTime
|
import org.jetbrains.kotlin.build.report.metrics.BuildTime
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.HttpReportService
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.HttpReportServiceImpl
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.GradleBuildStartParameters
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.StatTag
|
||||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||||
|
import org.jetbrains.kotlin.gradle.report.BuildReportsService.Companion.getStartParameters
|
||||||
import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord
|
import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord
|
||||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
import org.jetbrains.kotlin.gradle.tasks.withType
|
||||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
||||||
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||||
|
import org.jetbrains.kotlin.incremental.ChangedFiles
|
||||||
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
|
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
|
||||||
|
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||||
@@ -40,13 +51,27 @@ internal interface UsesBuildMetricsService : Task {
|
|||||||
val buildMetricsService: Property<BuildMetricsService?>
|
val buildMetricsService: Property<BuildMetricsService?>
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BuildMetricsService : BuildService<BuildServiceParameters.None>, OperationCompletionListener {
|
abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters>, AutoCloseable {
|
||||||
|
|
||||||
|
//Part of BuildReportService
|
||||||
|
interface Parameters : BuildServiceParameters {
|
||||||
|
val startParameters: Property<GradleBuildStartParameters>
|
||||||
|
val reportingSettings: Property<ReportingSettings>
|
||||||
|
val httpService: Property<HttpReportService>
|
||||||
|
|
||||||
|
val projectDir: DirectoryProperty
|
||||||
|
val label: Property<String?>
|
||||||
|
val projectName: Property<String>
|
||||||
|
val kotlinVersion: Property<String>
|
||||||
|
val buildConfigurationTags: ListProperty<StatTag>
|
||||||
|
}
|
||||||
|
|
||||||
private val log = Logging.getLogger(this.javaClass)
|
private val log = Logging.getLogger(this.javaClass)
|
||||||
|
private val buildReportService = BuildReportsService()
|
||||||
|
|
||||||
// Tasks and transforms' records
|
// Tasks and transforms' records
|
||||||
internal val buildOperationRecords = ConcurrentLinkedQueue<BuildOperationRecord>()
|
private val buildOperationRecords = ConcurrentLinkedQueue<BuildOperationRecord>()
|
||||||
internal 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>()
|
||||||
@@ -76,69 +101,87 @@ abstract class BuildMetricsService : BuildService<BuildServiceParameters.None>,
|
|||||||
failureMessage?.let { failureMessages.add(it) }
|
failureMessage?.let { failureMessages.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinish(event: FinishEvent?) {
|
private fun updateBuildOperationRecord(event: TaskFinishEvent): TaskRecord {
|
||||||
if (event is TaskFinishEvent) {
|
val result = event.result
|
||||||
val result = event.result
|
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()
|
||||||
buildMetrics.buildTimes.addTimeMs(BuildTime.GRADLE_TASK, totalTimeMs)
|
buildMetrics.buildTimes.addTimeMs(BuildTime.GRADLE_TASK, totalTimeMs)
|
||||||
taskPathToMetricsReporter[taskPath]?.let {
|
taskPathToMetricsReporter[taskPath]?.let {
|
||||||
buildMetrics.addAll(it.getMetrics())
|
buildMetrics.addAll(it.getMetrics())
|
||||||
}
|
}
|
||||||
val taskExecutionResult = TaskExecutionResults[taskPath]
|
val taskExecutionResult = TaskExecutionResults[taskPath]
|
||||||
taskExecutionResult?.buildMetrics?.also {
|
taskExecutionResult?.buildMetrics?.also {
|
||||||
buildMetrics.addAll(it)
|
buildMetrics.addAll(it)
|
||||||
|
|
||||||
KotlinBuildStatsService.applyIfInitialised { collector ->
|
KotlinBuildStatsService.applyIfInitialised { collector ->
|
||||||
collector.report(NumericalMetrics.COMPILATION_DURATION, totalTimeMs)
|
collector.report(NumericalMetrics.COMPILATION_DURATION, totalTimeMs)
|
||||||
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[BuildPerformanceMetric.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 {
|
metricsMap[BuildPerformanceMetric.ANALYSIS_LPS]?.also { value ->
|
||||||
collector.report(NumericalMetrics.ANALYSIS_LINES_PER_SECOND, it, null, linesOfCode)
|
collector.report(NumericalMetrics.ANALYSIS_LINES_PER_SECOND, value, null, linesOfCode)
|
||||||
}
|
}
|
||||||
metricsMap[BuildPerformanceMetric.CODE_GENERATION_LPS]?.also { value ->
|
metricsMap[BuildPerformanceMetric.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)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
collector.report(NumericalMetrics.COMPILATIONS_COUNT, 1)
|
|
||||||
collector.report(
|
|
||||||
NumericalMetrics.INCREMENTAL_COMPILATIONS_COUNT,
|
|
||||||
if (taskExecutionResult.buildMetrics.buildAttributes.asMap().isEmpty()) 1 else 0
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
collector.report(NumericalMetrics.COMPILATIONS_COUNT, 1)
|
||||||
|
collector.report(
|
||||||
buildOperationRecords.add(
|
NumericalMetrics.INCREMENTAL_COMPILATIONS_COUNT,
|
||||||
TaskRecord(
|
if (taskExecutionResult.buildMetrics.buildAttributes.asMap().isEmpty()) 1 else 0
|
||||||
path = taskPath,
|
|
||||||
classFqName = taskPathToTaskClass[taskPath] ?: "unknown",
|
|
||||||
startTimeMs = result.startTime,
|
|
||||||
totalTimeMs = totalTimeMs,
|
|
||||||
buildMetrics = buildMetrics,
|
|
||||||
didWork = result is TaskExecutionResult,
|
|
||||||
skipMessage = (result as? TaskSkippedResult)?.skipMessage,
|
|
||||||
icLogLines = taskExecutionResult?.icLogLines ?: emptyList(),
|
|
||||||
kotlinLanguageVersion = taskExecutionResult?.taskInfo?.kotlinLanguageVersion
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
if (result is TaskFailureResult) {
|
|
||||||
failureMessages.addAll(result.failures.map { it.message })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val buildOperation = TaskRecord(
|
||||||
|
path = taskPath,
|
||||||
|
classFqName = taskPathToTaskClass[taskPath] ?: "unknown",
|
||||||
|
startTimeMs = result.startTime,
|
||||||
|
totalTimeMs = totalTimeMs,
|
||||||
|
buildMetrics = buildMetrics,
|
||||||
|
didWork = result is TaskExecutionResult,
|
||||||
|
skipMessage = (result as? TaskSkippedResult)?.skipMessage,
|
||||||
|
icLogLines = taskExecutionResult?.icLogLines ?: emptyList(),
|
||||||
|
changedFiles = taskExecutionResult?.taskInfo?.changedFiles,
|
||||||
|
compilerArguments = taskExecutionResult?.taskInfo?.compilerArguments ?: emptyArray(),
|
||||||
|
kotlinLanguageVersion = taskExecutionResult?.taskInfo?.kotlinLanguageVersion,
|
||||||
|
statTags = taskExecutionResult?.taskInfo?.tags ?: emptySet()
|
||||||
|
)
|
||||||
|
buildOperationRecords.add(buildOperation)
|
||||||
|
if (result is TaskFailureResult) {
|
||||||
|
failureMessages.addAll(result.failures.map { it.message })
|
||||||
|
}
|
||||||
|
return buildOperation
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
buildReportService.close(buildOperationRecords, failureMessages.toList(), parameters.toBuildReportParameters())
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val serviceClass = BuildMetricsService::class.java
|
private val serviceClass = BuildMetricsService::class.java
|
||||||
private val serviceName = "${serviceClass.name}_${serviceClass.classLoader.hashCode()}"
|
private val serviceName = "${serviceClass.name}_${serviceClass.classLoader.hashCode()}"
|
||||||
|
|
||||||
private fun registerIfAbsentImpl(project: Project): Provider<BuildMetricsService>? {
|
private fun Parameters.toBuildReportParameters() = BuildReportParameters(
|
||||||
|
startParameters = startParameters.get(),
|
||||||
|
reportingSettings = reportingSettings.get(),
|
||||||
|
httpService = httpService.orNull,
|
||||||
|
projectDir = projectDir.asFile.get(),
|
||||||
|
label = label.orNull,
|
||||||
|
projectName = projectName.get(),
|
||||||
|
kotlinVersion = kotlinVersion.get(),
|
||||||
|
additionalTags = HashSet(buildConfigurationTags.get())
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun registerIfAbsentImpl(
|
||||||
|
project: Project,
|
||||||
|
): Provider<BuildMetricsService>? {
|
||||||
// Return early if the service was already registered to avoid the overhead of reading the reporting settings below
|
// Return early if the service was already registered to avoid the overhead of reading the reporting settings below
|
||||||
project.gradle.sharedServices.registrations.findByName(serviceName)?.let {
|
project.gradle.sharedServices.registrations.findByName(serviceName)?.let {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@@ -151,7 +194,59 @@ abstract class BuildMetricsService : BuildService<BuildServiceParameters.None>,
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return project.gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) {}!!
|
val kotlinVersion = project.getKotlinPluginVersion()
|
||||||
|
|
||||||
|
return project.gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) {
|
||||||
|
it.parameters.label.set(reportingSettings.buildReportLabel)
|
||||||
|
it.parameters.projectName.set(project.rootProject.name)
|
||||||
|
it.parameters.kotlinVersion.set(kotlinVersion)
|
||||||
|
it.parameters.startParameters.set(getStartParameters(project))
|
||||||
|
it.parameters.reportingSettings.set(reportingSettings)
|
||||||
|
reportingSettings.httpReportSettings?.let { httpSettings ->
|
||||||
|
it.parameters.httpService.set(
|
||||||
|
HttpReportServiceImpl(
|
||||||
|
httpSettings.url,
|
||||||
|
httpSettings.user,
|
||||||
|
httpSettings.password
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
it.parameters.projectDir.set(project.rootProject.layout.projectDirectory)
|
||||||
|
//init gradle tags for build scan and http reports
|
||||||
|
it.parameters.buildConfigurationTags.value(setupTags(project.gradle))
|
||||||
|
}.also {
|
||||||
|
subscribeForTaskEvents(project, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeForTaskEvents(project: Project, buildMetricService: Provider<BuildMetricsService>) {
|
||||||
|
// BuildScanExtension cant be parameter nor BuildService's field
|
||||||
|
val buildScanExtension = project.rootProject.extensions.findByName("buildScan")
|
||||||
|
val buildScan = buildScanExtension?.let { BuildScanExtensionHolder(it) }
|
||||||
|
val buildReportService = buildMetricService.map { it.buildReportService }
|
||||||
|
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider {
|
||||||
|
OperationCompletionListener { event ->
|
||||||
|
if (event is TaskFinishEvent) {
|
||||||
|
val buildOperation = buildMetricService.get().updateBuildOperationRecord(event)
|
||||||
|
val buildParameters = buildMetricService.get().parameters.toBuildReportParameters()
|
||||||
|
buildReportService.get().onFinish(event, buildOperation, buildParameters, buildScan)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
val buildScanReportSettings = buildMetricService.get().parameters.reportingSettings.orNull?.buildScanReportSettings
|
||||||
|
if (buildScanReportSettings != null) {
|
||||||
|
buildScan?.also {
|
||||||
|
buildReportService.get().initBuildScanTags(
|
||||||
|
it, buildMetricService.get().parameters.label.orNull
|
||||||
|
)
|
||||||
|
it.buildScan.buildFinished {
|
||||||
|
buildReportService.get().addCollectedTags(buildScan)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerIfAbsent(project: Project) = registerIfAbsentImpl(project)?.also { serviceProvider ->
|
fun registerIfAbsent(project: Project) = registerIfAbsentImpl(project)?.also { serviceProvider ->
|
||||||
@@ -161,6 +256,17 @@ abstract class BuildMetricsService : BuildService<BuildServiceParameters.None>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupTags(gradle: Gradle): ArrayList<StatTag> {
|
||||||
|
val additionalTags = ArrayList<StatTag>()
|
||||||
|
if (isConfigurationCacheAvailable(gradle)) {
|
||||||
|
additionalTags.add(StatTag.CONFIGURATION_CACHE)
|
||||||
|
}
|
||||||
|
if (gradle.startParameter.isBuildCacheEnabled) {
|
||||||
|
additionalTags.add(StatTag.BUILD_CACHE)
|
||||||
|
}
|
||||||
|
return additionalTags
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -174,7 +280,10 @@ internal class TaskRecord(
|
|||||||
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>,
|
||||||
val kotlinLanguageVersion: KotlinVersion?
|
val kotlinLanguageVersion: KotlinVersion?,
|
||||||
|
val changedFiles: ChangedFiles? = null,
|
||||||
|
val compilerArguments: Array<String> = emptyArray(),
|
||||||
|
val statTags: Set<StatTag> = emptySet(),
|
||||||
) : BuildOperationRecord {
|
) : BuildOperationRecord {
|
||||||
override val isFromKotlinPlugin: Boolean = classFqName.startsWith("org.jetbrains.kotlin")
|
override val isFromKotlinPlugin: Boolean = classFqName.startsWith("org.jetbrains.kotlin")
|
||||||
}
|
}
|
||||||
|
|||||||
+137
-197
@@ -6,33 +6,21 @@
|
|||||||
package org.jetbrains.kotlin.gradle.report
|
package org.jetbrains.kotlin.gradle.report
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.Task
|
|
||||||
import org.gradle.api.file.DirectoryProperty
|
|
||||||
import org.gradle.api.invocation.Gradle
|
|
||||||
import org.gradle.api.logging.Logging
|
import org.gradle.api.logging.Logging
|
||||||
import org.gradle.api.provider.ListProperty
|
|
||||||
import org.gradle.api.provider.Property
|
|
||||||
import org.gradle.api.provider.Provider
|
|
||||||
import org.gradle.api.services.BuildService
|
|
||||||
import org.gradle.api.services.BuildServiceParameters
|
|
||||||
import org.gradle.api.tasks.Internal
|
|
||||||
import org.gradle.tooling.events.FinishEvent
|
|
||||||
import org.gradle.tooling.events.OperationCompletionListener
|
|
||||||
import org.gradle.tooling.events.task.TaskFinishEvent
|
import org.gradle.tooling.events.task.TaskFinishEvent
|
||||||
import org.jetbrains.kotlin.build.report.metrics.ValueType
|
import org.jetbrains.kotlin.build.report.metrics.ValueType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder
|
import org.jetbrains.kotlin.build.report.statistic.HttpReportService
|
||||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
import org.jetbrains.kotlin.build.report.statistic.file.FileReportService
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.BuildFinishStatisticsData
|
import org.jetbrains.kotlin.build.report.statistic.formatSize
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.CompileStatisticsData
|
import org.jetbrains.kotlin.build.report.statistic.BuildFinishStatisticsData
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.GradleBuildStartParameters
|
import org.jetbrains.kotlin.build.report.statistic.CompileStatisticsData
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.StatTag
|
import org.jetbrains.kotlin.build.report.statistic.GradleBuildStartParameters
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.StatTag
|
||||||
import org.jetbrains.kotlin.gradle.report.data.BuildExecutionData
|
import org.jetbrains.kotlin.gradle.report.data.BuildExecutionData
|
||||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord
|
||||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.formatSize
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult
|
import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.lang.management.ManagementFactory
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -41,18 +29,16 @@ import java.util.concurrent.Executors
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
internal interface UsesBuildReportsService : Task {
|
//Because of https://github.com/gradle/gradle/issues/23359 gradle issue, two build services interaction is not reliable at the end of the build
|
||||||
@get:Internal
|
//Switch back to proper BuildService as soon as this issue is fixed
|
||||||
val buildReportsService: Property<BuildReportsService?>
|
class BuildReportsService {
|
||||||
}
|
|
||||||
|
|
||||||
abstract class BuildReportsService : BuildService<BuildReportsService.Parameters>, AutoCloseable, OperationCompletionListener {
|
|
||||||
|
|
||||||
private val log = Logging.getLogger(this.javaClass)
|
private val log = Logging.getLogger(this.javaClass)
|
||||||
|
private val loggerAdapter = GradleLoggerAdapter(log)
|
||||||
|
|
||||||
private val startTime = System.nanoTime()
|
private val startTime = System.nanoTime()
|
||||||
private val buildUuid = UUID.randomUUID().toString()
|
private val buildUuid = UUID.randomUUID().toString()
|
||||||
private var executorService: ExecutorService = Executors.newSingleThreadExecutor()
|
private val executorService: ExecutorService = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
private val tags = LinkedHashSet<StatTag>()
|
private val tags = LinkedHashSet<StatTag>()
|
||||||
private var customValues = 0 // doesn't need to be thread-safe
|
private var customValues = 0 // doesn't need to be thread-safe
|
||||||
@@ -61,33 +47,46 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
log.info("Build report service is registered. Unique build id: $buildUuid")
|
log.info("Build report service is registered. Unique build id: $buildUuid")
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Parameters : BuildServiceParameters {
|
fun close(
|
||||||
val startParameters: Property<GradleBuildStartParameters>
|
buildOperationRecords: Collection<BuildOperationRecord>,
|
||||||
val reportingSettings: Property<ReportingSettings>
|
failureMessages: List<String>,
|
||||||
var buildMetricsService: Provider<BuildMetricsService>
|
parameters: BuildReportParameters
|
||||||
val httpService: Property<HttpReportService>
|
) {
|
||||||
|
|
||||||
val projectDir: DirectoryProperty
|
|
||||||
val label: Property<String?>
|
|
||||||
val projectName: Property<String>
|
|
||||||
val kotlinVersion: Property<String>
|
|
||||||
val additionalTags: ListProperty<StatTag>
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
val buildData = BuildExecutionData(
|
val buildData = BuildExecutionData(
|
||||||
startParameters = parameters.startParameters.get(),
|
startParameters = parameters.startParameters,
|
||||||
failureMessages = parameters.buildMetricsService.orNull?.failureMessages?.toList() ?: emptyList(),
|
failureMessages = failureMessages,
|
||||||
buildOperationRecord = parameters.buildMetricsService.orNull?.buildOperationRecords?.sortedBy { it.startTimeMs } ?: emptyList()
|
buildOperationRecord = buildOperationRecords.sortedBy { it.startTimeMs }
|
||||||
)
|
)
|
||||||
|
|
||||||
val reportingSettings = parameters.reportingSettings.get()
|
val reportingSettings = parameters.reportingSettings
|
||||||
|
|
||||||
reportingSettings.httpReportSettings?.also {
|
reportingSettings.httpReportSettings?.also {
|
||||||
executorService.submit { reportBuildFinish() } //
|
executorService.submit { reportBuildFinish(parameters) }
|
||||||
}
|
}
|
||||||
reportingSettings.fileReportSettings?.also {
|
reportingSettings.fileReportSettings?.also {
|
||||||
reportBuildStatInFile(it, buildData)
|
FileReportService.reportBuildStatInFile(
|
||||||
|
it.buildReportDir,
|
||||||
|
parameters.projectName,
|
||||||
|
it.includeMetricsInReport,
|
||||||
|
buildOperationRecords.mapNotNull {
|
||||||
|
prepareData(
|
||||||
|
taskResult = null,
|
||||||
|
it.path,
|
||||||
|
it.startTimeMs,
|
||||||
|
it.totalTimeMs + it.startTimeMs,
|
||||||
|
parameters.projectName,
|
||||||
|
buildUuid,
|
||||||
|
parameters.label,
|
||||||
|
parameters.kotlinVersion,
|
||||||
|
it,
|
||||||
|
onlyKotlinTask = false,
|
||||||
|
parameters.additionalTags
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters.startParameters,
|
||||||
|
failureMessages.filter { it.isNotEmpty() },
|
||||||
|
loggerAdapter
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
reportingSettings.singleOutputFile?.also { singleOutputFile ->
|
reportingSettings.singleOutputFile?.also { singleOutputFile ->
|
||||||
@@ -98,26 +97,20 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
executorService.shutdown()
|
executorService.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinish(event: FinishEvent?) {
|
fun onFinish(
|
||||||
addHttpReport(event)
|
event: TaskFinishEvent, buildOperation: BuildOperationRecord,
|
||||||
|
parameters: BuildReportParameters, buildScan: BuildScanExtensionHolder?
|
||||||
|
) {
|
||||||
|
buildScan?.also { addBuildScanReport(event, buildOperation, parameters, it) }
|
||||||
|
addHttpReport(event, buildOperation, parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportBuildStatInFile(fileReportSettings: FileReportSettings, buildData: BuildExecutionData) {
|
private fun reportBuildFinish(parameters: BuildReportParameters) {
|
||||||
val ts = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Calendar.getInstance().time)
|
val httpReportSettings = parameters.reportingSettings.httpReportSettings ?: return
|
||||||
val reportFile = fileReportSettings.buildReportDir.resolve("${parameters.projectName.get()}-build-$ts.txt")
|
|
||||||
|
|
||||||
PlainTextBuildReportWriter(
|
|
||||||
outputFile = reportFile,
|
|
||||||
printMetrics = fileReportSettings.includeMetricsInReport
|
|
||||||
).process(buildData, log)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reportBuildFinish() {
|
|
||||||
val httpReportSettings = parameters.reportingSettings.get().httpReportSettings ?: return
|
|
||||||
|
|
||||||
val branchName = if (httpReportSettings.includeGitBranchName) {
|
val branchName = if (httpReportSettings.includeGitBranchName) {
|
||||||
val process = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
|
val process = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||||
.directory(parameters.projectDir.asFile.get())
|
.directory(parameters.projectDir)
|
||||||
.start().also {
|
.start().also {
|
||||||
it.waitFor(5, TimeUnit.SECONDS)
|
it.waitFor(5, TimeUnit.SECONDS)
|
||||||
}
|
}
|
||||||
@@ -125,19 +118,19 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
} else "is not set"
|
} else "is not set"
|
||||||
|
|
||||||
val buildFinishData = BuildFinishStatisticsData(
|
val buildFinishData = BuildFinishStatisticsData(
|
||||||
projectName = parameters.projectName.get(),
|
projectName = parameters.projectName,
|
||||||
startParameters = parameters.startParameters.get()
|
startParameters = parameters.startParameters
|
||||||
.includeVerboseEnvironment(parameters.reportingSettings.get().httpReportSettings?.verboseEnvironment ?: false),
|
.includeVerboseEnvironment(parameters.reportingSettings.httpReportSettings.verboseEnvironment),
|
||||||
buildUuid = buildUuid,
|
buildUuid = buildUuid,
|
||||||
label = parameters.label.orNull,
|
label = parameters.label,
|
||||||
totalTime = TimeUnit.NANOSECONDS.toMillis((System.nanoTime() - startTime)),
|
totalTime = TimeUnit.NANOSECONDS.toMillis((System.nanoTime() - startTime)),
|
||||||
finishTime = System.currentTimeMillis(),
|
finishTime = System.currentTimeMillis(),
|
||||||
hostName = hostName,
|
hostName = hostName,
|
||||||
tags = tags.toList(),
|
tags = tags,
|
||||||
gitBranch = branchName
|
gitBranch = branchName
|
||||||
)
|
)
|
||||||
|
|
||||||
parameters.httpService.orNull?.sendData(buildFinishData, log)
|
parameters.httpService?.sendData(buildFinishData, loggerAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun GradleBuildStartParameters.includeVerboseEnvironment(verboseEnvironment: Boolean): GradleBuildStartParameters {
|
private fun GradleBuildStartParameters.includeVerboseEnvironment(verboseEnvironment: Boolean): GradleBuildStartParameters {
|
||||||
@@ -154,69 +147,72 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addHttpReport(event: FinishEvent?) {
|
private fun addHttpReport(
|
||||||
parameters.httpService.orNull?.also { httpService ->
|
event: TaskFinishEvent,
|
||||||
if (event is TaskFinishEvent) {
|
buildOperationRecord: BuildOperationRecord,
|
||||||
val data =
|
parameters: BuildReportParameters
|
||||||
prepareData(
|
) {
|
||||||
event,
|
parameters.httpService?.also { httpService ->
|
||||||
parameters.projectName.get(),
|
val data =
|
||||||
buildUuid,
|
prepareData(
|
||||||
parameters.label.orNull,
|
event,
|
||||||
parameters.kotlinVersion.get(),
|
parameters.projectName,
|
||||||
parameters.buildMetricsService.get().buildOperationRecords,
|
buildUuid,
|
||||||
parameters.additionalTags.get()
|
parameters.label,
|
||||||
)
|
parameters.kotlinVersion,
|
||||||
data?.also {
|
buildOperationRecord,
|
||||||
executorService.submit {
|
onlyKotlinTask = true,
|
||||||
httpService.sendData(data, log)
|
parameters.additionalTags
|
||||||
}
|
)
|
||||||
|
data?.also {
|
||||||
|
executorService.submit {
|
||||||
|
httpService.sendData(data, loggerAdapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addBuildScanReport(
|
||||||
|
event: TaskFinishEvent,
|
||||||
|
buildOperationRecord: BuildOperationRecord,
|
||||||
|
parameters: BuildReportParameters,
|
||||||
|
buildScanExtension: BuildScanExtensionHolder
|
||||||
|
) {
|
||||||
|
val buildScanSettings = parameters.reportingSettings.buildScanReportSettings ?: return
|
||||||
|
|
||||||
private fun addBuildScanReport(event: FinishEvent?, buildScan: BuildScanExtensionHolder) {
|
val (collectDataDuration, compileStatData) = measureTimeMillisWithResult {
|
||||||
val buildScanSettings = parameters.reportingSettings.orNull?.buildScanReportSettings
|
prepareData(
|
||||||
if (buildScanSettings != null && buildScan.buildScan != null) {
|
event,
|
||||||
if (event is TaskFinishEvent) {
|
parameters.projectName, buildUuid, parameters.label,
|
||||||
val (collectDataDuration, compileStatData) = measureTimeMillisWithResult {
|
parameters.kotlinVersion,
|
||||||
prepareData(
|
buildOperationRecord,
|
||||||
event, parameters.projectName.get(), buildUuid, parameters.label.orNull,
|
metricsToShow = buildScanSettings.metrics
|
||||||
parameters.kotlinVersion.get(),
|
)
|
||||||
parameters.buildMetricsService.get().buildOperationRecords,
|
}
|
||||||
metricsToShow = buildScanSettings.metrics
|
log.debug("Collect data takes $collectDataDuration: $compileStatData")
|
||||||
)
|
|
||||||
}
|
|
||||||
log.debug("Collect data takes $collectDataDuration: $compileStatData")
|
|
||||||
|
|
||||||
compileStatData?.also {
|
compileStatData?.also {
|
||||||
addBuildScanReport(it, buildScanSettings.customValueLimit, buildScan)
|
addBuildScanReport(it, buildScanSettings.customValueLimit, buildScanExtension)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addBuildScanReport(data: CompileStatisticsData, customValuesLimit: Int, buildScan: BuildScanExtensionHolder) {
|
private fun addBuildScanReport(data: CompileStatisticsData, customValuesLimit: Int, buildScan: BuildScanExtensionHolder) {
|
||||||
val elapsedTime = measureTimeMillis {
|
val elapsedTime = measureTimeMillis {
|
||||||
data.tags.forEach { tags.add(it) }
|
tags.addAll(data.tags)
|
||||||
buildScan.buildScan?.also {
|
if (customValues < customValuesLimit) {
|
||||||
if (customValues < customValuesLimit) {
|
readableString(data).forEach {
|
||||||
readableString(data).forEach {
|
if (customValues < customValuesLimit) {
|
||||||
if (customValues < customValuesLimit) {
|
addBuildScanValue(buildScan, data, it)
|
||||||
addBuildScanValue(buildScan, data, it)
|
} 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.taskName} was cut due to custom values limit."
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.debug("Can't add any more custom values into build scan.")
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("Can't add any more custom values into build scan.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +224,7 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
data: CompileStatisticsData,
|
data: CompileStatisticsData,
|
||||||
customValue: String
|
customValue: String
|
||||||
) {
|
) {
|
||||||
buildScan.buildScan?.value(data.taskName, customValue)
|
buildScan.buildScan.value(data.taskName, customValue)
|
||||||
customValues++
|
customValues++
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +241,7 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
) { it.readableString }
|
) { it.readableString }
|
||||||
}
|
}
|
||||||
|
|
||||||
data.kotlinLanguageVersion?.version?.also {
|
data.kotlinLanguageVersion?.also {
|
||||||
readableString.append("Kotlin language version: $it; ")
|
readableString.append("Kotlin language version: $it; ")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,14 +279,18 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
return splattedString
|
return splattedString
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initBuildScanTags(buildScan: BuildScanExtensionHolder) {
|
internal fun initBuildScanTags(buildScan: BuildScanExtensionHolder, label: String?) {
|
||||||
buildScan.buildScan?.tag(buildUuid)
|
buildScan.buildScan.tag(buildUuid)
|
||||||
parameters.label.orNull?.also {
|
label?.also {
|
||||||
buildScan.buildScan?.tag(it)
|
buildScan.buildScan.tag(it)
|
||||||
|
}
|
||||||
|
val debugConfiguration = "-agentlib:"
|
||||||
|
if (ManagementFactory.getRuntimeMXBean().inputArguments.firstOrNull { it.startsWith(debugConfiguration) } != null) {
|
||||||
|
buildScan.buildScan.tag(StatTag.GRADLE_DEBUG.readableString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addCollectedTags(buildScan: BuildScanExtensionHolder) {
|
internal fun addCollectedTags(buildScan: BuildScanExtensionHolder) {
|
||||||
replaceWithCombinedTag(
|
replaceWithCombinedTag(
|
||||||
StatTag.KOTLIN_1,
|
StatTag.KOTLIN_1,
|
||||||
StatTag.KOTLIN_2,
|
StatTag.KOTLIN_2,
|
||||||
@@ -303,7 +303,7 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
StatTag.INCREMENTAL_AND_NON_INCREMENTAL
|
StatTag.INCREMENTAL_AND_NON_INCREMENTAL
|
||||||
)
|
)
|
||||||
|
|
||||||
tags.forEach { buildScan.buildScan?.tag(it.readableString) }
|
tags.forEach { buildScan.buildScan.tag(it.readableString) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceWithCombinedTag(firstTag: StatTag, secondTag: StatTag, combinedTag: StatTag) {
|
private fun replaceWithCombinedTag(firstTag: StatTag, secondTag: StatTag, combinedTag: StatTag) {
|
||||||
@@ -331,78 +331,6 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerIfAbsentImpl(
|
|
||||||
project: Project,
|
|
||||||
buildMetricsService: Provider<BuildMetricsService>
|
|
||||||
): Provider<BuildReportsService>? {
|
|
||||||
val serviceClass = BuildReportsService::class.java
|
|
||||||
val serviceName = "${serviceClass.name}_${serviceClass.classLoader.hashCode()}"
|
|
||||||
|
|
||||||
val reportingSettings = reportingSettings(project)
|
|
||||||
if (reportingSettings.buildReportOutputs.isEmpty()) {
|
|
||||||
return null //no need to collect data
|
|
||||||
}
|
|
||||||
|
|
||||||
val kotlinVersion = project.getKotlinPluginVersion()
|
|
||||||
val gradle = project.gradle
|
|
||||||
project.gradle.sharedServices.registrations.findByName(serviceName)?.let {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return it.service as Provider<BuildReportsService>
|
|
||||||
}
|
|
||||||
|
|
||||||
return gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) {
|
|
||||||
it.parameters.label.set(reportingSettings.buildReportLabel)
|
|
||||||
it.parameters.projectName.set(project.rootProject.name)
|
|
||||||
it.parameters.kotlinVersion.set(kotlinVersion)
|
|
||||||
it.parameters.startParameters.set(getStartParameters(project))
|
|
||||||
it.parameters.reportingSettings.set(reportingSettings)
|
|
||||||
reportingSettings.httpReportSettings?.let { httpSettings -> it.parameters.httpService.set(HttpReportServiceImpl(httpSettings)) }
|
|
||||||
it.parameters.buildMetricsService = buildMetricsService
|
|
||||||
it.parameters.projectDir.set(project.rootProject.layout.projectDirectory)
|
|
||||||
|
|
||||||
//init gradle tags for build scan and http reports
|
|
||||||
it.parameters.additionalTags.value(setupTags(gradle))
|
|
||||||
}.also { buildServiceProvider ->
|
|
||||||
if (reportingSettings.httpReportSettings != null) {
|
|
||||||
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(buildServiceProvider)
|
|
||||||
}
|
|
||||||
|
|
||||||
val buildScanExtension = project.rootProject.extensions.findByName("buildScan")
|
|
||||||
if (reportingSettings.buildScanReportSettings != null && buildScanExtension != null) {
|
|
||||||
val buildScan = BuildScanExtensionHolder(buildScanExtension)
|
|
||||||
buildServiceProvider.get().initBuildScanTags(buildScan)
|
|
||||||
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider {
|
|
||||||
OperationCompletionListener { event ->
|
|
||||||
buildServiceProvider.get().addBuildScanReport(event, buildScan)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
buildScan.buildScan?.buildFinished {
|
|
||||||
buildServiceProvider.get().addCollectedTags(buildScan)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun registerIfAbsent(project: Project, buildMetricsService: Provider<BuildMetricsService>) =
|
|
||||||
registerIfAbsentImpl(project, buildMetricsService)?.also { serviceProvider ->
|
|
||||||
SingleActionPerProject.run(project, UsesBuildReportsService::class.java.name) {
|
|
||||||
project.tasks.withType<UsesBuildReportsService>().configureEach { task ->
|
|
||||||
task.usesService(serviceProvider)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupTags(gradle: Gradle): ArrayList<StatTag> {
|
|
||||||
val additionalTags = ArrayList<StatTag>()
|
|
||||||
if (isConfigurationCacheAvailable(gradle)) {
|
|
||||||
additionalTags.add(StatTag.CONFIGURATION_CACHE)
|
|
||||||
}
|
|
||||||
if (gradle.startParameter.isBuildCacheEnabled) {
|
|
||||||
additionalTags.add(StatTag.BUILD_CACHE)
|
|
||||||
}
|
|
||||||
return additionalTags
|
|
||||||
}
|
|
||||||
|
|
||||||
val hostName: String? = try {
|
val hostName: String? = try {
|
||||||
InetAddress.getLocalHost().hostName
|
InetAddress.getLocalHost().hostName
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
@@ -422,3 +350,15 @@ enum class TaskExecutionState {
|
|||||||
UP_TO_DATE
|
UP_TO_DATE
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class BuildReportParameters(
|
||||||
|
val startParameters: GradleBuildStartParameters,
|
||||||
|
val reportingSettings: ReportingSettings,
|
||||||
|
val httpService: HttpReportService?,
|
||||||
|
|
||||||
|
val projectDir: File,
|
||||||
|
val label: String?,
|
||||||
|
val projectName: String,
|
||||||
|
val kotlinVersion: String,
|
||||||
|
val additionalTags: Set<StatTag>
|
||||||
|
)
|
||||||
+2
-2
@@ -7,6 +7,6 @@ package org.jetbrains.kotlin.gradle.report
|
|||||||
|
|
||||||
import com.gradle.scan.plugin.BuildScanExtension
|
import com.gradle.scan.plugin.BuildScanExtension
|
||||||
|
|
||||||
class BuildScanExtensionHolder(val buildScan: BuildScanExtension?) : java.io.Serializable {
|
class BuildScanExtensionHolder(val buildScan: BuildScanExtension) : java.io.Serializable {
|
||||||
constructor(extension: Any?) : this(extension as BuildScanExtension)
|
constructor(extension: Any) : this(extension as BuildScanExtension)
|
||||||
}
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.api.logging.Logger
|
||||||
|
|
||||||
|
class GradleLoggerAdapter(private val log: Logger) : org.jetbrains.kotlin.util.Logger {
|
||||||
|
override fun log(message: String) {
|
||||||
|
log.info(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun warning(message: String) {
|
||||||
|
log.warn(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fatal(message: String): Nothing {
|
||||||
|
log.error(message)
|
||||||
|
kotlin.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(message: String, throwable: Throwable?) {
|
||||||
|
throwable?.let { log.error(message, throwable) } ?: log.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun lifecycle(message: String) {
|
||||||
|
log.lifecycle(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
-284
@@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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.gradle.api.logging.Logger
|
|
||||||
import org.jetbrains.kotlin.build.report.metrics.*
|
|
||||||
import org.jetbrains.kotlin.gradle.report.data.BuildExecutionData
|
|
||||||
import org.jetbrains.kotlin.gradle.report.data.BuildOperationRecord
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.Printer
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.asString
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.formatSize
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.formatTime
|
|
||||||
import java.io.File
|
|
||||||
import java.io.Serializable
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
internal class PlainTextBuildReportWriter(
|
|
||||||
private val outputFile: File,
|
|
||||||
private val printMetrics: Boolean
|
|
||||||
) : Serializable {
|
|
||||||
|
|
||||||
private lateinit var p: Printer
|
|
||||||
|
|
||||||
fun process(build: BuildExecutionData, log: Logger) {
|
|
||||||
val buildReportPath = outputFile.toPath().toUri().toString()
|
|
||||||
try {
|
|
||||||
outputFile.parentFile.mkdirs()
|
|
||||||
if (!(outputFile.parentFile.exists() && outputFile.parentFile.isDirectory)) {
|
|
||||||
log.error("Kotlin build report cannot be created: '$outputFile.parentFile' is a file or do not have permissions to create")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
outputFile.bufferedWriter().use { writer ->
|
|
||||||
p = Printer(writer)
|
|
||||||
printBuildReport(build)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.lifecycle("Kotlin build report is written to $buildReportPath")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
log.error("Could not write Kotlin build report to $buildReportPath", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printBuildReport(build: BuildExecutionData) {
|
|
||||||
// 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
|
|
||||||
// a bit unfamiliar.
|
|
||||||
// TODO: If it is confusing, consider renaming "tasks" to "build operations" in this class.
|
|
||||||
printBuildInfo(build)
|
|
||||||
if (printMetrics) {
|
|
||||||
printMetrics(build.aggregatedMetrics, aggregatedMetric = true)
|
|
||||||
p.println()
|
|
||||||
}
|
|
||||||
printTaskOverview(build)
|
|
||||||
printTasksLog(build)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printBuildInfo(build: BuildExecutionData) {
|
|
||||||
p.withIndent("Gradle start parameters:") {
|
|
||||||
build.startParameters.let {
|
|
||||||
p.println("tasks = ${it.tasks}")
|
|
||||||
p.println("excluded tasks = ${it.excludedTasks}")
|
|
||||||
p.println("current dir = ${it.currentDir}")
|
|
||||||
p.println("project properties args = ${it.projectProperties}")
|
|
||||||
p.println(" system properties args = ${it.systemProperties}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.println()
|
|
||||||
|
|
||||||
if (build.failureMessages.isNotEmpty()) {
|
|
||||||
p.println("Build failed: ${build.failureMessages}")
|
|
||||||
p.println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printMetrics(buildMetrics: BuildMetrics, aggregatedMetric: Boolean = false) {
|
|
||||||
printBuildTimes(buildMetrics.buildTimes)
|
|
||||||
if (aggregatedMetric) p.println()
|
|
||||||
|
|
||||||
printBuildPerformanceMetrics(buildMetrics.buildPerformanceMetrics)
|
|
||||||
if (aggregatedMetric) p.println()
|
|
||||||
|
|
||||||
printBuildAttributes(buildMetrics.buildAttributes)
|
|
||||||
|
|
||||||
//TODO: KT-57310 Implement build GC metric in
|
|
||||||
if (!aggregatedMetric) {
|
|
||||||
printGcMetrics(buildMetrics.gcMetrics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printBuildTimes(buildTimes: BuildTimes) {
|
|
||||||
val buildTimesMs = buildTimes.asMapMs()
|
|
||||||
|
|
||||||
if (buildTimesMs.isEmpty()) return
|
|
||||||
|
|
||||||
p.println("Time metrics:")
|
|
||||||
p.withIndent {
|
|
||||||
val visitedBuildTimes = HashSet<BuildTime>()
|
|
||||||
fun printBuildTime(buildTime: BuildTime) {
|
|
||||||
if (!visitedBuildTimes.add(buildTime)) return
|
|
||||||
|
|
||||||
val timeMs = buildTimesMs[buildTime]
|
|
||||||
if (timeMs != null) {
|
|
||||||
p.println("${buildTime.readableString}: ${formatTime(timeMs)}")
|
|
||||||
p.withIndent {
|
|
||||||
BuildTime.children[buildTime]?.forEach { printBuildTime(it) }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Skip formatting if parent metric does not set
|
|
||||||
BuildTime.children[buildTime]?.forEach { printBuildTime(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (buildTime in BuildTime.values()) {
|
|
||||||
if (buildTime.parent != null) continue
|
|
||||||
|
|
||||||
printBuildTime(buildTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printBuildPerformanceMetrics(buildMetrics: BuildPerformanceMetrics) {
|
|
||||||
val allBuildMetrics = buildMetrics.asMap()
|
|
||||||
if (allBuildMetrics.isEmpty()) return
|
|
||||||
|
|
||||||
p.withIndent("Size metrics:") {
|
|
||||||
for (metric in BuildPerformanceMetric.values()) {
|
|
||||||
allBuildMetrics[metric]?.let { printSizeMetric(metric, it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printSizeMetric(sizeMetric: BuildPerformanceMetric, value: Long) {
|
|
||||||
fun BuildPerformanceMetric.numberOfAncestors(): Int {
|
|
||||||
var count = 0
|
|
||||||
var parent: BuildPerformanceMetric? = parent
|
|
||||||
while (parent != null) {
|
|
||||||
count++
|
|
||||||
parent = parent.parent
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
val indentLevel = sizeMetric.numberOfAncestors()
|
|
||||||
|
|
||||||
repeat(indentLevel) { p.pushIndent() }
|
|
||||||
when (sizeMetric.type) {
|
|
||||||
ValueType.BYTES -> p.println("${sizeMetric.readableString}: ${formatSize(value)}")
|
|
||||||
ValueType.NUMBER -> p.println("${sizeMetric.readableString}: $value")
|
|
||||||
}
|
|
||||||
repeat(indentLevel) { p.popIndent() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printBuildAttributes(buildAttributes: BuildAttributes) {
|
|
||||||
val allAttributes = buildAttributes.asMap()
|
|
||||||
if (allAttributes.isEmpty()) return
|
|
||||||
|
|
||||||
p.withIndent("Build attributes:") {
|
|
||||||
val attributesByKind = allAttributes.entries.groupBy { it.key.kind }.toSortedMap()
|
|
||||||
for ((kind, attributesCounts) in attributesByKind) {
|
|
||||||
printMap(p, kind.name, attributesCounts.map { (k, v) -> k.readableString to v }.toMap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printGcMetrics(gcMetrics: GcMetrics) {
|
|
||||||
val allGcMetrics = gcMetrics.asMap()
|
|
||||||
if (allGcMetrics.isEmpty()) return
|
|
||||||
p.withIndent("GC metrics:") {
|
|
||||||
for (gcMetric in allGcMetrics) {
|
|
||||||
p.println("${gcMetric.key}:")
|
|
||||||
p.withIndent {
|
|
||||||
p.println("GC count: ${gcMetric.value.count}")
|
|
||||||
p.println("GC time: ${formatTime(gcMetric.value.time)}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printTaskOverview(build: BuildExecutionData) {
|
|
||||||
var allTasksTimeMs = 0L
|
|
||||||
var kotlinTotalTimeMs = 0L
|
|
||||||
val kotlinTasks = ArrayList<BuildOperationRecord>()
|
|
||||||
|
|
||||||
for (task in build.buildOperationRecord) {
|
|
||||||
val taskTimeMs = task.totalTimeMs
|
|
||||||
allTasksTimeMs += taskTimeMs
|
|
||||||
|
|
||||||
if (task.isFromKotlinPlugin) {
|
|
||||||
kotlinTotalTimeMs += taskTimeMs
|
|
||||||
kotlinTasks.add(task)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kotlinTasks.isEmpty()) {
|
|
||||||
p.println("No Kotlin task was run")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val ktTaskPercent = (kotlinTotalTimeMs.toDouble() / allTasksTimeMs * 100).asString(1)
|
|
||||||
p.println("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeMs)} ($ktTaskPercent % of all tasks time)")
|
|
||||||
|
|
||||||
val table = TextTable("Time", "% of Kotlin time", "Task")
|
|
||||||
for (task in kotlinTasks.sortedWith(compareBy({ -it.totalTimeMs }, { it.startTimeMs }))) {
|
|
||||||
val timeMs = task.totalTimeMs
|
|
||||||
val percent = (timeMs.toDouble() / kotlinTotalTimeMs * 100).asString(1)
|
|
||||||
table.addRow(formatTime(timeMs), "$percent %", task.path)
|
|
||||||
}
|
|
||||||
table.printTo(p)
|
|
||||||
p.println()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printTasksLog(build: BuildExecutionData) {
|
|
||||||
for (task in build.buildOperationRecord.sortedWith(compareBy({ -it.totalTimeMs }, { it.startTimeMs }))) {
|
|
||||||
printTaskLog(task)
|
|
||||||
p.println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printTaskLog(task: BuildOperationRecord) {
|
|
||||||
val skipMessage = task.skipMessage
|
|
||||||
if (skipMessage != null) {
|
|
||||||
p.println("Task '${task.path}' was skipped: $skipMessage")
|
|
||||||
} else {
|
|
||||||
p.println("Task '${task.path}' finished in ${formatTime(task.totalTimeMs)}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task.icLogLines.isNotEmpty()) {
|
|
||||||
p.withIndent("Compilation log for task '${task.path}':") {
|
|
||||||
task.icLogLines.forEach { p.println(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printMetrics) {
|
|
||||||
printMetrics(task.buildMetrics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printMap(p: Printer, name: String, mapping: Map<String, Int>) {
|
|
||||||
if (mapping.isEmpty()) return
|
|
||||||
|
|
||||||
if (mapping.size == 1) {
|
|
||||||
p.println("$name: ${mapping.keys.single()}")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
p.withIndent("$name:") {
|
|
||||||
val sortedEnumMap = mapping.toSortedMap()
|
|
||||||
for ((k, v) in sortedEnumMap) {
|
|
||||||
p.println("$k($v)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TextTable(vararg columnNames: String) {
|
|
||||||
private val rows = ArrayList<List<String>>()
|
|
||||||
private val columnsCount = columnNames.size
|
|
||||||
private val maxLengths = IntArray(columnsCount) { columnNames[it].length }
|
|
||||||
|
|
||||||
init {
|
|
||||||
rows.add(columnNames.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addRow(vararg row: String) {
|
|
||||||
check(row.size == columnsCount) { "Row size ${row.size} differs from columns count $columnsCount" }
|
|
||||||
rows.add(row.toList())
|
|
||||||
|
|
||||||
for ((i, col) in row.withIndex()) {
|
|
||||||
maxLengths[i] = max(maxLengths[i], col.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printTo(p: Printer) {
|
|
||||||
for (row in rows) {
|
|
||||||
val rowStr = row.withIndex().joinToString("|") { (i, col) -> col.padEnd(maxLengths[i], ' ') }
|
|
||||||
p.println(rowStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-21
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.report
|
package org.jetbrains.kotlin.gradle.report
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.build.report.FileReportSettings
|
||||||
|
import org.jetbrains.kotlin.build.report.HttpReportSettings
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
@@ -23,27 +25,6 @@ data class ReportingSettings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class FileReportSettings(
|
|
||||||
val buildReportDir: File,
|
|
||||||
val includeMetricsInReport: Boolean = false,
|
|
||||||
) : Serializable {
|
|
||||||
companion object {
|
|
||||||
const val serialVersionUID: Long = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class HttpReportSettings(
|
|
||||||
val url: String,
|
|
||||||
val password: String?,
|
|
||||||
val user: String?,
|
|
||||||
val verboseEnvironment: Boolean,
|
|
||||||
val includeGitBranchName: Boolean
|
|
||||||
) : Serializable {
|
|
||||||
companion object {
|
|
||||||
const val serialVersionUID: Long = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class BuildScanSettings(
|
data class BuildScanSettings(
|
||||||
val customValueLimit: Int,
|
val customValueLimit: Int,
|
||||||
val metrics: Set<String>?
|
val metrics: Set<String>?
|
||||||
|
|||||||
+2
-2
@@ -7,6 +7,7 @@ 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.gradle.dsl.KotlinVersion
|
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||||
|
import org.jetbrains.kotlin.build.report.statistic.StatTag
|
||||||
import org.jetbrains.kotlin.incremental.ChangedFiles
|
import org.jetbrains.kotlin.incremental.ChangedFiles
|
||||||
|
|
||||||
internal class TaskExecutionResult(
|
internal class TaskExecutionResult(
|
||||||
@@ -19,6 +20,5 @@ internal class TaskExecutionInfo(
|
|||||||
val kotlinLanguageVersion: KotlinVersion? = null,
|
val kotlinLanguageVersion: KotlinVersion? = null,
|
||||||
val changedFiles: ChangedFiles? = null,
|
val changedFiles: ChangedFiles? = null,
|
||||||
val compilerArguments: Array<String> = emptyArray(),
|
val compilerArguments: Array<String> = emptyArray(),
|
||||||
val withArtifactTransform: Boolean? = false,
|
val tags: Set<StatTag> = emptySet(),
|
||||||
val withAbiSnapshot: Boolean? = false
|
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-1
@@ -6,6 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.gradle.report
|
package org.jetbrains.kotlin.gradle.report
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.build.report.FileReportSettings
|
||||||
|
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.gradle.plugin.PropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||||
@@ -14,7 +16,6 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
|
|||||||
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 = BuildTime.values().map { it.name } + BuildPerformanceMetric.values().map { it.name }
|
||||||
|
|
||||||
internal fun reportingSettings(project: Project): ReportingSettings {
|
internal fun reportingSettings(project: Project): ReportingSettings {
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
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.gradle.plugin.stat.GradleBuildStartParameters
|
import org.jetbrains.kotlin.build.report.statistic.GradleBuildStartParameters
|
||||||
|
|
||||||
class BuildExecutionData(
|
class BuildExecutionData(
|
||||||
val startParameters: GradleBuildStartParameters,
|
val startParameters: GradleBuildStartParameters,
|
||||||
|
|||||||
+92
-78
@@ -10,20 +10,24 @@ 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.gradle.plugin.internal.state.TaskExecutionResults
|
import org.jetbrains.kotlin.build.report.statistic.CompileStatisticsData
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.CompileStatisticsData
|
import org.jetbrains.kotlin.build.report.statistic.StatTag
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.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 org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
|
||||||
import java.lang.management.ManagementFactory
|
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||||
|
|
||||||
|
|
||||||
private fun availableForStat(taskPath: String): Boolean {
|
internal fun getTaskResult(event: TaskFinishEvent) = when (val result = event.result) {
|
||||||
return taskPath.contains("Kotlin") && (TaskExecutionResults[taskPath] != null)
|
is TaskSuccessResult -> when {
|
||||||
|
result.isFromCache -> TaskExecutionState.FROM_CACHE
|
||||||
|
result.isUpToDate -> TaskExecutionState.UP_TO_DATE
|
||||||
|
else -> TaskExecutionState.SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
is TaskSkippedResult -> TaskExecutionState.SKIPPED
|
||||||
|
is TaskFailureResult -> TaskExecutionState.FAILED
|
||||||
|
else -> TaskExecutionState.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun prepareData(
|
internal fun prepareData(
|
||||||
@@ -32,95 +36,112 @@ internal fun prepareData(
|
|||||||
uuid: String,
|
uuid: String,
|
||||||
label: String?,
|
label: String?,
|
||||||
kotlinVersion: String,
|
kotlinVersion: String,
|
||||||
buildOperationRecords: Collection<BuildOperationRecord>,
|
buildOperationRecord: BuildOperationRecord,
|
||||||
additionalTags: List<StatTag> = emptyList(),
|
onlyKotlinTask: Boolean = true,
|
||||||
|
additionalTags: Set<StatTag> = emptySet(),
|
||||||
metricsToShow: Set<String>? = null
|
metricsToShow: Set<String>? = null
|
||||||
): CompileStatisticsData? {
|
): CompileStatisticsData? {
|
||||||
val result = event.result
|
val result = event.result
|
||||||
val taskPath = event.descriptor.taskPath
|
val taskPath = event.descriptor.taskPath
|
||||||
val durationMs = result.endTime - result.startTime
|
return prepareData(getTaskResult(event), taskPath, result.startTime, result.endTime - result.startTime, projectName, uuid,
|
||||||
val taskResult = when (result) {
|
label, kotlinVersion, buildOperationRecord, onlyKotlinTask, additionalTags, metricsToShow)
|
||||||
is TaskSuccessResult -> when {
|
}
|
||||||
result.isFromCache -> TaskExecutionState.FROM_CACHE
|
|
||||||
result.isUpToDate -> TaskExecutionState.UP_TO_DATE
|
|
||||||
else -> TaskExecutionState.SUCCESS
|
|
||||||
}
|
|
||||||
|
|
||||||
is TaskSkippedResult -> TaskExecutionState.SKIPPED
|
internal fun prepareData(
|
||||||
is TaskFailureResult -> TaskExecutionState.FAILED
|
taskResult: TaskExecutionState?,
|
||||||
else -> TaskExecutionState.UNKNOWN
|
taskPath: String,
|
||||||
}
|
startTime: Long,
|
||||||
|
finishTime: Long,
|
||||||
if (!availableForStat(taskPath)) {
|
projectName: String,
|
||||||
|
uuid: String,
|
||||||
|
label: String?,
|
||||||
|
kotlinVersion: String,
|
||||||
|
buildOperationRecord: BuildOperationRecord,
|
||||||
|
onlyKotlinTask: Boolean = true,
|
||||||
|
additionalTags: Set<StatTag> = emptySet(),
|
||||||
|
metricsToShow: Set<String>? = null
|
||||||
|
): CompileStatisticsData? {
|
||||||
|
if (onlyKotlinTask && !(buildOperationRecord is TaskRecord && buildOperationRecord.isFromKotlinPlugin)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val taskExecutionResult = TaskExecutionResults[taskPath]
|
val buildMetrics = buildOperationRecord.buildMetrics
|
||||||
val buildMetrics = buildOperationRecords.firstOrNull { it.path == taskPath }?.buildMetrics
|
|
||||||
|
|
||||||
val performanceMetrics = collectBuildPerformanceMetrics(taskExecutionResult, buildMetrics)
|
val performanceMetrics = collectBuildPerformanceMetrics(buildMetrics)
|
||||||
val buildTimesMetrics = collectBuildMetrics(
|
val buildTimesMetrics = collectBuildMetrics(
|
||||||
taskExecutionResult, buildMetrics, performanceMetrics, result.startTime,
|
buildMetrics, startTime, System.currentTimeMillis()
|
||||||
System.currentTimeMillis()
|
|
||||||
)
|
)
|
||||||
val buildAttributes = collectBuildAttributes(taskExecutionResult, buildMetrics)
|
val buildAttributes = collectBuildAttributes(buildMetrics)
|
||||||
val changes = when (val changedFiles = taskExecutionResult?.taskInfo?.changedFiles) {
|
val changes = if (buildOperationRecord is TaskRecord && buildOperationRecord.changedFiles is ChangedFiles.Known) {
|
||||||
is ChangedFiles.Known -> changedFiles.modified.map { it.absolutePath } + changedFiles.removed.map { it.absolutePath }
|
buildOperationRecord.changedFiles.modified.map { it.absolutePath } + buildOperationRecord.changedFiles.removed.map { it.absolutePath }
|
||||||
else -> emptyList<String>()
|
} else {
|
||||||
|
emptyList<String>()
|
||||||
}
|
}
|
||||||
|
val kotlinLanguageVersion = if (buildOperationRecord is TaskRecord) buildOperationRecord.kotlinLanguageVersion else null
|
||||||
|
|
||||||
return CompileStatisticsData(
|
return CompileStatisticsData(
|
||||||
durationMs = durationMs,
|
durationMs = buildOperationRecord.totalTimeMs,
|
||||||
taskResult = taskResult.name,
|
taskResult = taskResult?.name,
|
||||||
label = label,
|
label = label,
|
||||||
buildTimesMetrics = filterMetrics(metricsToShow, buildTimesMetrics),
|
buildTimesMetrics = filterMetrics(metricsToShow, buildTimesMetrics),
|
||||||
performanceMetrics = filterMetrics(metricsToShow, performanceMetrics),
|
performanceMetrics = filterMetrics(metricsToShow, performanceMetrics),
|
||||||
projectName = projectName,
|
projectName = projectName,
|
||||||
taskName = taskPath,
|
taskName = taskPath,
|
||||||
changes = changes,
|
changes = changes,
|
||||||
tags = collectTags(taskExecutionResult, buildMetrics, additionalTags),
|
tags = collectTags(buildOperationRecord, additionalTags),
|
||||||
nonIncrementalAttributes = buildAttributes,
|
nonIncrementalAttributes = buildAttributes,
|
||||||
hostName = BuildReportsService.hostName,
|
hostName = BuildReportsService.hostName,
|
||||||
kotlinVersion = kotlinVersion,
|
kotlinVersion = kotlinVersion,
|
||||||
kotlinLanguageVersion = taskExecutionResult?.taskInfo?.kotlinLanguageVersion,
|
kotlinLanguageVersion = kotlinLanguageVersion?.version,
|
||||||
buildUuid = uuid,
|
buildUuid = uuid,
|
||||||
finishTime = System.currentTimeMillis(),
|
compilerArguments = collectCompilerArguments(buildOperationRecord),
|
||||||
compilerArguments = taskExecutionResult?.taskInfo?.compilerArguments?.asList() ?: emptyList(),
|
gcCountMetrics = buildMetrics.gcMetrics.asGcCountMap(),
|
||||||
gcCountMetrics = buildMetrics?.gcMetrics?.asGcCountMap(),
|
gcTimeMetrics = buildMetrics.gcMetrics.asGcTimeMap(),
|
||||||
gcTimeMetrics = buildMetrics?.gcMetrics?.asGcTimeMap()
|
finishTime = finishTime,
|
||||||
|
startTimeMs = startTime,
|
||||||
|
fromKotlinPlugin = buildOperationRecord.isFromKotlinPlugin,
|
||||||
|
skipMessage = buildOperationRecord.skipMessage,
|
||||||
|
icLogLines = buildOperationRecord.icLogLines
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun collectCompilerArguments(buildOperationRecord: BuildOperationRecord?): List<String> {
|
||||||
|
return if (buildOperationRecord is TaskRecord) {
|
||||||
|
buildOperationRecord.compilerArguments.asList()
|
||||||
|
} else emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
private fun <E : Enum<E>> filterMetrics(
|
private fun <E : Enum<E>> 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.name) } } ?: buildTimesMetrics
|
||||||
|
|
||||||
private fun collectBuildAttributes(taskExecutionResult: TaskExecutionResult?, buildMetrics: BuildMetrics?): Set<BuildAttribute> {
|
private fun collectBuildAttributes(buildMetrics: BuildMetrics?): Set<BuildAttribute> {
|
||||||
val attributes = HashSet<BuildAttribute>()
|
return buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys ?: emptySet()
|
||||||
buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys?.also { attributes.addAll(it) }
|
|
||||||
taskExecutionResult?.buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys?.also { attributes.addAll(it) }
|
|
||||||
return attributes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun collectBuildPerformanceMetrics(
|
private fun collectBuildPerformanceMetrics(
|
||||||
taskExecutionResult: TaskExecutionResult?,
|
|
||||||
buildMetrics: BuildMetrics?
|
buildMetrics: BuildMetrics?
|
||||||
): Map<BuildPerformanceMetric, Long> {
|
): Map<BuildPerformanceMetric, Long> {
|
||||||
val taskBuildPerformanceMetrics = HashMap<BuildPerformanceMetric, Long>()
|
return buildMetrics?.buildPerformanceMetrics?.asMap()
|
||||||
taskExecutionResult?.buildMetrics?.buildPerformanceMetrics?.asMap()?.let { taskBuildPerformanceMetrics.putAll(it) }
|
?.filterValues { value -> value != 0L }
|
||||||
buildMetrics?.buildPerformanceMetrics?.asMap()?.let { taskBuildPerformanceMetrics.putAll(it) }
|
?.filterKeys { key ->
|
||||||
return taskBuildPerformanceMetrics.filterValues { value -> value != 0L }
|
key !in listOf(
|
||||||
|
BuildPerformanceMetric.START_WORKER_EXECUTION,
|
||||||
|
BuildPerformanceMetric.CALL_WORKER,
|
||||||
|
BuildPerformanceMetric.CALL_KOTLIN_DAEMON,
|
||||||
|
BuildPerformanceMetric.START_KOTLIN_DAEMON_EXECUTION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
?: emptyMap()
|
||||||
}
|
}
|
||||||
private fun collectBuildMetrics(
|
private fun collectBuildMetrics(
|
||||||
taskExecutionResult: TaskExecutionResult?,
|
|
||||||
buildMetrics: BuildMetrics?,
|
buildMetrics: BuildMetrics?,
|
||||||
performanceMetrics: Map<BuildPerformanceMetric, Long>,
|
|
||||||
gradleTaskStartTime: Long? = null,
|
gradleTaskStartTime: Long? = null,
|
||||||
taskFinishEventTime: Long? = null,
|
taskFinishEventTime: Long? = null,
|
||||||
): Map<BuildTime, Long> {
|
): Map<BuildTime, Long> {
|
||||||
val taskBuildMetrics = HashMap<BuildTime, Long>()
|
val taskBuildMetrics = HashMap<BuildTime, Long>(buildMetrics?.buildTimes?.asMapMs())
|
||||||
taskExecutionResult?.buildMetrics?.buildTimes?.asMapMs()?.let { taskBuildMetrics.putAll(it) }
|
val performanceMetrics = buildMetrics?.buildPerformanceMetrics?.asMap() ?: emptyMap()
|
||||||
buildMetrics?.buildTimes?.asMapMs()?.let { taskBuildMetrics.putAll(it) }
|
|
||||||
gradleTaskStartTime?.let { startTime ->
|
gradleTaskStartTime?.let { startTime ->
|
||||||
performanceMetrics[BuildPerformanceMetric.START_TASK_ACTION_EXECUTION]?.let { actionStartTime ->
|
performanceMetrics[BuildPerformanceMetric.START_TASK_ACTION_EXECUTION]?.let { actionStartTime ->
|
||||||
taskBuildMetrics.put(BuildTime.GRADLE_TASK_PREPARATION, actionStartTime - startTime)
|
taskBuildMetrics.put(BuildTime.GRADLE_TASK_PREPARATION, actionStartTime - startTime)
|
||||||
@@ -141,41 +162,34 @@ private fun collectBuildMetrics(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun collectTags(
|
private fun collectTags(
|
||||||
taskExecutionResult: TaskExecutionResult?,
|
buildOperation: BuildOperationRecord?,
|
||||||
buildMetrics: BuildMetrics?,
|
additionalTags: Set<StatTag>
|
||||||
additionalTags: List<StatTag>
|
): Set<StatTag> {
|
||||||
): List<StatTag> {
|
val tags = HashSet(additionalTags)
|
||||||
val tags = collectTags(taskExecutionResult, additionalTags)
|
if (buildOperation is TaskRecord) {
|
||||||
val nonIncrementalAttributes = collectBuildAttributes(taskExecutionResult, buildMetrics)
|
tags.addAll(collectTaskRecordTags(buildOperation))
|
||||||
|
}
|
||||||
|
|
||||||
|
val nonIncrementalAttributes = collectBuildAttributes(buildOperation?.buildMetrics)
|
||||||
if (nonIncrementalAttributes.isEmpty()) {
|
if (nonIncrementalAttributes.isEmpty()) {
|
||||||
tags.add(StatTag.INCREMENTAL)
|
tags.add(StatTag.INCREMENTAL)
|
||||||
} else {
|
} else {
|
||||||
tags.add(StatTag.NON_INCREMENTAL)
|
tags.add(StatTag.NON_INCREMENTAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectTags(
|
private fun collectTaskRecordTags(
|
||||||
taskExecutionResult: TaskExecutionResult?,
|
taskRecord: TaskRecord?,
|
||||||
additionalTags: List<StatTag>,
|
): Set<StatTag> {
|
||||||
): MutableList<StatTag> {
|
val tags = HashSet<StatTag>()
|
||||||
val tags = ArrayList(additionalTags)
|
|
||||||
val taskInfo = taskExecutionResult?.taskInfo
|
|
||||||
|
|
||||||
taskInfo?.withAbiSnapshot?.ifTrue {
|
taskRecord?.kotlinLanguageVersion?.also {
|
||||||
tags.add(StatTag.ABI_SNAPSHOT)
|
|
||||||
}
|
|
||||||
taskInfo?.withArtifactTransform?.ifTrue {
|
|
||||||
tags.add(StatTag.ARTIFACT_TRANSFORM)
|
|
||||||
}
|
|
||||||
taskInfo?.kotlinLanguageVersion?.also {
|
|
||||||
tags.add(getLanguageVersionTag(it))
|
tags.add(getLanguageVersionTag(it))
|
||||||
}
|
}
|
||||||
|
|
||||||
val debugConfiguration = "-agentlib:"
|
taskRecord?.statTags?.let { tags.addAll(it) }
|
||||||
if (ManagementFactory.getRuntimeMXBean().inputArguments.firstOrNull { it.startsWith(debugConfiguration) } != null) {
|
|
||||||
tags.add(StatTag.GRADLE_DEBUG)
|
|
||||||
}
|
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.gradle.internal.UsesClassLoadersCachingBuildService
|
|||||||
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
|
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
|
||||||
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
|
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.default
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_SUPPRESS_EXPERIMENTAL_IC_OPTIMIZATIONS_WARNING
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_SUPPRESS_EXPERIMENTAL_IC_OPTIMIZATIONS_WARNING
|
||||||
import org.jetbrains.kotlin.gradle.plugin.UsesBuildFinishedListenerService
|
import org.jetbrains.kotlin.gradle.plugin.UsesBuildFinishedListenerService
|
||||||
import org.jetbrains.kotlin.gradle.plugin.UsesVariantImplementationFactories
|
import org.jetbrains.kotlin.gradle.plugin.UsesVariantImplementationFactories
|
||||||
@@ -57,7 +56,6 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
|
|||||||
) : AbstractKotlinCompileTool<T>(objectFactory),
|
) : AbstractKotlinCompileTool<T>(objectFactory),
|
||||||
CompileUsingKotlinDaemonWithNormalization,
|
CompileUsingKotlinDaemonWithNormalization,
|
||||||
UsesBuildMetricsService,
|
UsesBuildMetricsService,
|
||||||
UsesBuildReportsService,
|
|
||||||
UsesIncrementalModuleInfoBuildService,
|
UsesIncrementalModuleInfoBuildService,
|
||||||
UsesCompilerSystemPropertiesService,
|
UsesCompilerSystemPropertiesService,
|
||||||
UsesVariantImplementationFactories,
|
UsesVariantImplementationFactories,
|
||||||
@@ -114,7 +112,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
|
|||||||
@get:Internal
|
@get:Internal
|
||||||
internal abstract val suppressKotlinOptionsFreeArgsModificationWarning: Property<Boolean>
|
internal abstract val suppressKotlinOptionsFreeArgsModificationWarning: Property<Boolean>
|
||||||
|
|
||||||
internal fun reportingSettings() = buildReportsService.orNull?.parameters?.reportingSettings?.orNull ?: ReportingSettings()
|
internal fun reportingSettings() = buildMetricsService.orNull?.parameters?.reportingSettings?.orNull ?: ReportingSettings()
|
||||||
|
|
||||||
@get:Internal
|
@get:Internal
|
||||||
protected val multiModuleICSettings: MultiModuleICSettings
|
protected val multiModuleICSettings: MultiModuleICSettings
|
||||||
|
|||||||
-5
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions
|
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions
|
||||||
import org.jetbrains.kotlin.gradle.report.BuildMetricsService
|
import org.jetbrains.kotlin.gradle.report.BuildMetricsService
|
||||||
import org.jetbrains.kotlin.gradle.report.BuildReportsService
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME
|
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME
|
||||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||||
@@ -64,7 +63,6 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
|
|||||||
|
|
||||||
val compilerSystemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project)
|
val compilerSystemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project)
|
||||||
val buildMetricsService = BuildMetricsService.registerIfAbsent(project)
|
val buildMetricsService = BuildMetricsService.registerIfAbsent(project)
|
||||||
val buildReportsService = buildMetricsService?.let { BuildReportsService.registerIfAbsent(project, buildMetricsService) }
|
|
||||||
val incrementalModuleInfoProvider =
|
val incrementalModuleInfoProvider =
|
||||||
IncrementalModuleInfoBuildService.registerIfAbsent(project, objectFactory.providerWithLazyConvention {
|
IncrementalModuleInfoBuildService.registerIfAbsent(project, objectFactory.providerWithLazyConvention {
|
||||||
GradleCompilerRunner.buildModulesInfo(project.gradle)
|
GradleCompilerRunner.buildModulesInfo(project.gradle)
|
||||||
@@ -84,9 +82,6 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
|
|||||||
task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges()
|
task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges()
|
||||||
buildMetricsService?.also { metricsService ->
|
buildMetricsService?.also { metricsService ->
|
||||||
task.buildMetricsService.value(metricsService).disallowChanges()
|
task.buildMetricsService.value(metricsService).disallowChanges()
|
||||||
buildReportsService?.also { reportsService ->
|
|
||||||
task.buildReportsService.value(reportsService).disallowChanges()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
task.systemPropertiesService.value(compilerSystemPropertiesService).disallowChanges()
|
task.systemPropertiesService.value(compilerSystemPropertiesService).disallowChanges()
|
||||||
task.incrementalModuleInfoProvider.value(incrementalModuleInfoProvider).disallowChanges()
|
task.incrementalModuleInfoProvider.value(incrementalModuleInfoProvider).disallowChanges()
|
||||||
|
|||||||
+2
-1
@@ -115,8 +115,9 @@ internal fun getAllDependencies(dependency: ResolvedDependencyResult): Set<Resol
|
|||||||
internal class GradleLoggerAdapter(private val gradleLogger: Logger) : org.jetbrains.kotlin.util.Logger {
|
internal class GradleLoggerAdapter(private val gradleLogger: Logger) : org.jetbrains.kotlin.util.Logger {
|
||||||
override fun log(message: String) = gradleLogger.info(message)
|
override fun log(message: String) = gradleLogger.info(message)
|
||||||
override fun warning(message: String) = gradleLogger.warn(message)
|
override fun warning(message: String) = gradleLogger.warn(message)
|
||||||
override fun error(message: String) = kotlin.error(message)
|
override fun error(message: String, throwable: Throwable?) = kotlin.error(message)
|
||||||
override fun fatal(message: String): Nothing = kotlin.error(message)
|
override fun fatal(message: String): Nothing = kotlin.error(message)
|
||||||
|
override fun lifecycle(message: String) = gradleLogger.lifecycle(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun libraryFilter(artifact: ResolvedArtifactResult): Boolean = artifact.file.absolutePath.endsWith(".klib")
|
private fun libraryFilter(artifact: ResolvedArtifactResult): Boolean = artifact.file.absolutePath.endsWith(".klib")
|
||||||
|
|||||||
-18
@@ -64,21 +64,3 @@ internal fun formatContentLength(bytes: Long): String = when {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun formatTime(ms: Long): String {
|
|
||||||
val seconds = ms.toDouble() / 1_000
|
|
||||||
return seconds.asString(2) + " s"
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val kbSize = 1024
|
|
||||||
private const val mbSize = kbSize * 1024
|
|
||||||
private const val gbSize = mbSize * 1024
|
|
||||||
|
|
||||||
internal fun formatSize(sizeInBytes: Long): String = when {
|
|
||||||
sizeInBytes / gbSize >= 1 -> "${(sizeInBytes.toDouble() / gbSize).asString(1)} GB"
|
|
||||||
sizeInBytes / mbSize >= 1 -> "${(sizeInBytes.toDouble() / mbSize).asString(1)} MB"
|
|
||||||
sizeInBytes / kbSize >= 1 -> "${(sizeInBytes.toDouble() / kbSize).asString(1)} KB"
|
|
||||||
else -> "$sizeInBytes B"
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun Double.asString(decPoints: Int): String = "%,.${decPoints}f".format(this)
|
|
||||||
+1
-1
@@ -42,7 +42,7 @@ fun Project.probeRemoteFileLength(url: String, probingTimeoutMs: Int = 0): Long?
|
|||||||
else {
|
else {
|
||||||
logger.kotlinDebug(::probeRemoteFileLength.name + "($url, $probingTimeoutMs): Failed to obtain content-length during the probing timeout.")
|
logger.kotlinDebug(::probeRemoteFileLength.name + "($url, $probingTimeoutMs): Failed to obtain content-length during the probing timeout.")
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
null as Long?
|
null
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
|
|||||||
+21
-41
@@ -11,10 +11,7 @@ import org.gradle.tooling.events.task.TaskFinishEvent
|
|||||||
import org.gradle.tooling.events.task.TaskOperationDescriptor
|
import org.gradle.tooling.events.task.TaskOperationDescriptor
|
||||||
import org.gradle.tooling.events.task.TaskOperationResult
|
import org.gradle.tooling.events.task.TaskOperationResult
|
||||||
import org.jetbrains.kotlin.build.report.metrics.*
|
import org.jetbrains.kotlin.build.report.metrics.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
import org.jetbrains.kotlin.build.report.statistic.StatTag
|
||||||
import org.jetbrains.kotlin.gradle.plugin.stat.StatTag
|
|
||||||
import org.jetbrains.kotlin.gradle.report.TaskExecutionInfo
|
|
||||||
import org.jetbrains.kotlin.gradle.report.TaskExecutionResult
|
|
||||||
import org.jetbrains.kotlin.gradle.report.TaskRecord
|
import org.jetbrains.kotlin.gradle.report.TaskRecord
|
||||||
import org.jetbrains.kotlin.gradle.report.prepareData
|
import org.jetbrains.kotlin.gradle.report.prepareData
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
@@ -32,11 +29,6 @@ class ReportDataTest {
|
|||||||
@Test
|
@Test
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
fun testTags() {
|
fun testTags() {
|
||||||
TaskExecutionResults[kotlinTaskPath] = TaskExecutionResult(
|
|
||||||
buildMetrics = BuildMetrics(buildAttributes = BuildAttributes()),
|
|
||||||
taskInfo = TaskExecutionInfo(kotlinLanguageVersion = KotlinVersion.KOTLIN_1_4),
|
|
||||||
icLogLines = emptyList(),
|
|
||||||
)
|
|
||||||
val buildOperationRecord =
|
val buildOperationRecord =
|
||||||
taskRecord(BuildMetrics(buildAttributes = BuildAttributes().also { it.add(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND) }))
|
taskRecord(BuildMetrics(buildAttributes = BuildAttributes().also { it.add(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND) }))
|
||||||
val statisticData = prepareData(
|
val statisticData = prepareData(
|
||||||
@@ -45,8 +37,9 @@ class ReportDataTest {
|
|||||||
uuid = "uuid",
|
uuid = "uuid",
|
||||||
label = "label",
|
label = "label",
|
||||||
kotlinVersion = "version",
|
kotlinVersion = "version",
|
||||||
buildOperationRecords = listOf(buildOperationRecord),
|
onlyKotlinTask = true,
|
||||||
additionalTags = listOf(StatTag.KOTLIN_DEBUG)
|
buildOperationRecord = buildOperationRecord,
|
||||||
|
additionalTags = setOf(StatTag.KOTLIN_DEBUG)
|
||||||
)
|
)
|
||||||
|
|
||||||
assertNotNull(statisticData)
|
assertNotNull(statisticData)
|
||||||
@@ -57,41 +50,34 @@ class ReportDataTest {
|
|||||||
|
|
||||||
private fun taskRecord(buildMetrics: BuildMetrics) = TaskRecord(
|
private fun taskRecord(buildMetrics: BuildMetrics) = TaskRecord(
|
||||||
path = kotlinTaskPath,
|
path = kotlinTaskPath,
|
||||||
classFqName = "class name",
|
classFqName = "org.jetbrains.kotlin.TestTask",
|
||||||
startTimeMs = 10,
|
startTimeMs = 10,
|
||||||
totalTimeMs = 20,
|
totalTimeMs = 20,
|
||||||
buildMetrics = buildMetrics,
|
buildMetrics = buildMetrics,
|
||||||
didWork = true,
|
didWork = true,
|
||||||
skipMessage = null,
|
skipMessage = null,
|
||||||
icLogLines = emptyList(),
|
icLogLines = emptyList(),
|
||||||
kotlinLanguageVersion = KotlinVersion.KOTLIN_1_8
|
kotlinLanguageVersion = KotlinVersion.KOTLIN_1_8,
|
||||||
|
changedFiles = null,
|
||||||
|
compilerArguments = emptyArray(),
|
||||||
|
statTags = emptySet()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMetricFilter() {
|
fun testMetricFilter() {
|
||||||
TaskExecutionResults["testKotlin"] = TaskExecutionResult(
|
|
||||||
buildMetrics = BuildMetrics(
|
|
||||||
buildPerformanceMetrics = BuildPerformanceMetrics().also {
|
|
||||||
it.add(BuildPerformanceMetric.BUNDLE_SIZE)
|
|
||||||
it.add(BuildPerformanceMetric.CACHE_DIRECTORY_SIZE)
|
|
||||||
},
|
|
||||||
buildTimes = BuildTimes().also {
|
|
||||||
it.addTimeMs(BuildTime.RESTORE_OUTPUT_FROM_BACKUP, 10)
|
|
||||||
it.addTimeMs(BuildTime.IC_ANALYZE_JAR_FILES, 10)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
taskInfo = TaskExecutionInfo(),
|
|
||||||
icLogLines = emptyList()
|
|
||||||
)
|
|
||||||
val buildOperationRecord = taskRecord(
|
val buildOperationRecord = taskRecord(
|
||||||
BuildMetrics(
|
BuildMetrics(
|
||||||
buildPerformanceMetrics = BuildPerformanceMetrics().also {
|
buildPerformanceMetrics = BuildPerformanceMetrics().also {
|
||||||
it.add(BuildPerformanceMetric.COMPILE_ITERATION)
|
it.add(BuildPerformanceMetric.COMPILE_ITERATION)
|
||||||
it.add(BuildPerformanceMetric.CLASSPATH_ENTRY_COUNT)
|
it.add(BuildPerformanceMetric.CLASSPATH_ENTRY_COUNT)
|
||||||
|
it.add(BuildPerformanceMetric.BUNDLE_SIZE)
|
||||||
|
it.add(BuildPerformanceMetric.CACHE_DIRECTORY_SIZE)
|
||||||
},
|
},
|
||||||
buildTimes = BuildTimes().also {
|
buildTimes = BuildTimes().also {
|
||||||
it.addTimeMs(BuildTime.STORE_BUILD_INFO, 20)
|
it.addTimeMs(BuildTime.STORE_BUILD_INFO, 20)
|
||||||
it.addTimeMs(BuildTime.GRADLE_TASK_ACTION, 100)
|
it.addTimeMs(BuildTime.GRADLE_TASK_ACTION, 100)
|
||||||
|
it.addTimeMs(BuildTime.RESTORE_OUTPUT_FROM_BACKUP, 10)
|
||||||
|
it.addTimeMs(BuildTime.IC_ANALYZE_JAR_FILES, 10)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -102,8 +88,9 @@ class ReportDataTest {
|
|||||||
uuid = "uuid",
|
uuid = "uuid",
|
||||||
label = "label",
|
label = "label",
|
||||||
kotlinVersion = "version",
|
kotlinVersion = "version",
|
||||||
buildOperationRecords = listOf(buildOperationRecord),
|
buildOperationRecord = buildOperationRecord,
|
||||||
additionalTags = listOf(StatTag.KOTLIN_DEBUG),
|
onlyKotlinTask = true,
|
||||||
|
additionalTags = setOf(StatTag.KOTLIN_DEBUG),
|
||||||
metricsToShow = setOf(
|
metricsToShow = setOf(
|
||||||
BuildPerformanceMetric.BUNDLE_SIZE.name,// from TaskExecutionResult
|
BuildPerformanceMetric.BUNDLE_SIZE.name,// from TaskExecutionResult
|
||||||
BuildTime.GRADLE_TASK_ACTION.name,// from buildOperationRecord
|
BuildTime.GRADLE_TASK_ACTION.name,// from buildOperationRecord
|
||||||
@@ -132,19 +119,11 @@ class ReportDataTest {
|
|||||||
val startWorker = 110L
|
val startWorker = 110L
|
||||||
val finishGradleTask = System.nanoTime()
|
val finishGradleTask = System.nanoTime()
|
||||||
|
|
||||||
TaskExecutionResults["testKotlin"] = TaskExecutionResult(
|
|
||||||
buildMetrics = BuildMetrics(
|
|
||||||
buildPerformanceMetrics = BuildPerformanceMetrics().also {
|
|
||||||
it.add(BuildPerformanceMetric.FINISH_KOTLIN_DAEMON_EXECUTION, System.currentTimeMillis())
|
|
||||||
it.add(BuildPerformanceMetric.START_WORKER_EXECUTION, TimeUnit.MILLISECONDS.toNanos(startWorker))
|
|
||||||
}
|
|
||||||
),
|
|
||||||
taskInfo = TaskExecutionInfo(),
|
|
||||||
icLogLines = emptyList()
|
|
||||||
)
|
|
||||||
val buildOperationRecord = taskRecord(
|
val buildOperationRecord = taskRecord(
|
||||||
BuildMetrics(
|
BuildMetrics(
|
||||||
buildPerformanceMetrics = BuildPerformanceMetrics().also {
|
buildPerformanceMetrics = BuildPerformanceMetrics().also {
|
||||||
|
it.add(BuildPerformanceMetric.FINISH_KOTLIN_DAEMON_EXECUTION, System.currentTimeMillis())
|
||||||
|
it.add(BuildPerformanceMetric.START_WORKER_EXECUTION, TimeUnit.MILLISECONDS.toNanos(startWorker))
|
||||||
it.add(BuildPerformanceMetric.START_TASK_ACTION_EXECUTION, startTaskAction)
|
it.add(BuildPerformanceMetric.START_TASK_ACTION_EXECUTION, startTaskAction)
|
||||||
it.add(BuildPerformanceMetric.CALL_WORKER, TimeUnit.MILLISECONDS.toNanos(callWorker))
|
it.add(BuildPerformanceMetric.CALL_WORKER, TimeUnit.MILLISECONDS.toNanos(callWorker))
|
||||||
}
|
}
|
||||||
@@ -157,8 +136,9 @@ class ReportDataTest {
|
|||||||
uuid = "uuid",
|
uuid = "uuid",
|
||||||
label = "label",
|
label = "label",
|
||||||
kotlinVersion = "version",
|
kotlinVersion = "version",
|
||||||
buildOperationRecords = listOf(buildOperationRecord),
|
buildOperationRecord = buildOperationRecord,
|
||||||
additionalTags = listOf(StatTag.KOTLIN_DEBUG),
|
onlyKotlinTask = true,
|
||||||
|
additionalTags = setOf(StatTag.KOTLIN_DEBUG),
|
||||||
)
|
)
|
||||||
assertNotNull(statisticData)
|
assertNotNull(statisticData)
|
||||||
assertEquals(startTaskAction - startGradleTask, statisticData.buildTimesMetrics[BuildTime.GRADLE_TASK_PREPARATION])
|
assertEquals(startTaskAction - startGradleTask, statisticData.buildTimesMetrics[BuildTime.GRADLE_TASK_PREPARATION])
|
||||||
|
|||||||
@@ -20,13 +20,15 @@ internal class CliLoggerAdapter(
|
|||||||
|
|
||||||
override fun warning(message: String) = printlnIndented("Warning: $message", *CommonizerLogLevel.values())
|
override fun warning(message: String) = printlnIndented("Warning: $message", *CommonizerLogLevel.values())
|
||||||
|
|
||||||
override fun error(message: String) = fatal(message)
|
override fun error(message: String, throwable: Throwable?) = fatal(message)
|
||||||
|
|
||||||
override fun fatal(message: String): Nothing {
|
override fun fatal(message: String): Nothing {
|
||||||
printlnIndented("Error: $message\n", *CommonizerLogLevel.values())
|
printlnIndented("Error: $message\n", *CommonizerLogLevel.values())
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun lifecycle(message: String) = log(message)
|
||||||
|
|
||||||
private fun printlnIndented(text: String, vararg levels: CommonizerLogLevel) {
|
private fun printlnIndented(text: String, vararg levels: CommonizerLogLevel) {
|
||||||
if (level in levels) {
|
if (level in levels) {
|
||||||
if (indent.isEmpty()) println(text)
|
if (indent.isEmpty()) println(text)
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ dependencies {
|
|||||||
fatJarContents(commonDependency("org.lz4:lz4-java")) { isTransitive = false }
|
fatJarContents(commonDependency("org.lz4:lz4-java")) { isTransitive = false }
|
||||||
fatJarContents(commonDependency("org.jetbrains.intellij.deps:asm-all")) { isTransitive = false }
|
fatJarContents(commonDependency("org.jetbrains.intellij.deps:asm-all")) { isTransitive = false }
|
||||||
fatJarContents(commonDependency("com.google.guava:guava")) { isTransitive = false }
|
fatJarContents(commonDependency("com.google.guava:guava")) { isTransitive = false }
|
||||||
|
fatJarContents(commonDependency("com.google.code.gson:gson")) { isTransitive = false}
|
||||||
|
|
||||||
fatJarContentsStripServices(commonDependency("com.fasterxml:aalto-xml")) { isTransitive = false }
|
fatJarContentsStripServices(commonDependency("com.fasterxml:aalto-xml")) { isTransitive = false }
|
||||||
fatJarContents(commonDependency("org.codehaus.woodstox:stax2-api")) { isTransitive = false }
|
fatJarContents(commonDependency("org.codehaus.woodstox:stax2-api")) { isTransitive = false }
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ include ":kotlin-imports-dumper-compiler-plugin",
|
|||||||
":kotlin-gradle-plugin-test-utils-embeddable",
|
":kotlin-gradle-plugin-test-utils-embeddable",
|
||||||
":kotlin-gradle-plugin-integration-tests",
|
":kotlin-gradle-plugin-integration-tests",
|
||||||
":kotlin-gradle-plugins-bom",
|
":kotlin-gradle-plugins-bom",
|
||||||
|
":kotlin-build-statistic",
|
||||||
":gradle:android-test-fixes",
|
":gradle:android-test-fixes",
|
||||||
":gradle:gradle-warnings-detector",
|
":gradle:gradle-warnings-detector",
|
||||||
":gradle:kotlin-compiler-args-properties",
|
":gradle:kotlin-compiler-args-properties",
|
||||||
@@ -807,6 +808,7 @@ project(':kotlin-scripting-ide-services-unshaded').projectDir = "$rootDir/plugin
|
|||||||
project(':kotlin-scripting-ide-services-test').projectDir = "$rootDir/plugins/scripting/scripting-ide-services-test" as File
|
project(':kotlin-scripting-ide-services-test').projectDir = "$rootDir/plugins/scripting/scripting-ide-services-test" as File
|
||||||
project(':kotlin-scripting-ide-services').projectDir = "$rootDir/plugins/scripting/scripting-ide-services-embeddable" as File
|
project(':kotlin-scripting-ide-services').projectDir = "$rootDir/plugins/scripting/scripting-ide-services-embeddable" as File
|
||||||
project(':kotlin-scripting-ide-common').projectDir = "$rootDir/plugins/scripting/scripting-ide-common" as File
|
project(':kotlin-scripting-ide-common').projectDir = "$rootDir/plugins/scripting/scripting-ide-common" as File
|
||||||
|
project(':kotlin-build-statistic').projectDir ="$rootDir/kotlin-build-statistic" as File
|
||||||
|
|
||||||
// Uncomment to use locally built protobuf-relocated
|
// Uncomment to use locally built protobuf-relocated
|
||||||
// includeBuild("dependencies/protobuf")
|
// includeBuild("dependencies/protobuf")
|
||||||
|
|||||||
Reference in New Issue
Block a user