KT-57371: Add versions for FUS statistic bean

This commit is contained in:
Nataliya.Valtman
2023-03-31 02:42:25 +02:00
committed by Space Team
parent caa7bee917
commit 2c2a01113e
8 changed files with 168 additions and 83 deletions
@@ -0,0 +1,35 @@
/*
* 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
import org.gradle.api.logging.LogLevel
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName
@DisplayName("Build FUS statistics")
class BuildFusStatisticsIT : KGPBaseTest() {
@JvmGradlePluginTests
@DisplayName("works for project with buildSrc and kotlinDsl plugin")
@GradleTest
fun testCompatibilityBuildSrcWithKotlinDsl(gradleVersion: GradleVersion) {
project(
"buildSrcUsingKotlinCompilationAndKotlinPlugin",
gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
build("assemble") {
//register build service for buildSrc.
assertOutputContains("Instantiated class org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService: new instance")
assertOutputContains("Instantiated class org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService_v2: new instance")
//kotlin 1.4 in kotlinDsl does not create jmx service yet
assertOutputContains("Register JMX service for backward compatibility")
assertOutputDoesNotContain("[org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatHandler] Could not execute")
}
}
}
}
@@ -358,7 +358,7 @@ fun Project.getKotlinPluginVersion() = getKotlinPluginVersion(project.logger)
fun getKotlinPluginVersion(logger: Logger): String {
if (!kotlinPluginVersionFromResources.isInitialized()) {
logger.kotlinDebug("Loading version information")
logger.kotlinDebug("Found project version [${kotlinPluginVersionFromResources.value}")
logger.kotlinDebug("Found project version [${kotlinPluginVersionFromResources.value}]")
}
return kotlinPluginVersionFromResources.value
}
@@ -49,13 +49,24 @@ class KotlinBuildStatHandler {
}
fun buildFinished(
beanName: ObjectName,
) {
runSafe("${KotlinBuildStatHandler::class.java}.buildFinished") {
val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
if (mbs.isRegistered(beanName)) {
mbs.unregisterMBean(beanName)
}
}
}
fun reportGlobalMetricsAndBuildFinished(
gradle: Gradle?,
beanName: ObjectName,
sessionLogger: BuildSessionLogger,
action: String?,
failure: Throwable?
) {
runSafe("${KotlinBuildStatHandler::class.java}.buildFinished") {
runSafe("${KotlinBuildStatHandler::class.java}.reportGlobalMetrics") {
try {
try {
if (gradle != null) reportGlobalMetrics(gradle, sessionLogger)
@@ -63,10 +74,7 @@ class KotlinBuildStatHandler {
sessionLogger.finishBuildSession(action, failure)
}
} finally {
val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
if (mbs.isRegistered(beanName)) {
mbs.unregisterMBean(beanName)
}
buildFinished(beanName)
}
}
}
@@ -215,7 +223,7 @@ class KotlinBuildStatHandler {
weight: Long? = null
) = runSafe("report metric ${metric.name}") {
sessionLogger.report(metric, value, subprojectName, weight)
} as? Boolean ?: false
} ?: false
internal fun report(
sessionLogger: BuildSessionLogger,
@@ -224,6 +232,6 @@ class KotlinBuildStatHandler {
subprojectName: String?,
weight: Long? = null
) = runSafe("report metric ${metric.name}") {
sessionLogger.report(metric, value, subprojectName, weight)
} as? Boolean ?: false
sessionLogger.report(metric, value, subprojectName, weight)
} ?: false
}
@@ -9,10 +9,13 @@ import org.gradle.BuildAdapter
import org.gradle.BuildResult
import org.gradle.api.Project
import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.initialization.BuildRequestMetaData
import org.gradle.invocation.DefaultGradle
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatHandler.Companion.runSafe
import org.jetbrains.kotlin.gradle.plugin.statistics.old.Pre232IdeaKotlinBuildStatsMXBean
import org.jetbrains.kotlin.gradle.plugin.statistics.old.Pre232IdeaKotlinBuildStatsService
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
import org.jetbrains.kotlin.statistics.BuildSessionLogger
import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.STATISTICS_FOLDER_NAME
@@ -32,27 +35,25 @@ import kotlin.system.measureTimeMillis
* JMX could be used for reporting both from other JVMs, other versions
* of Kotlin Plugin and other classloaders
*/
interface KotlinBuildStatsMXBean {
fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean
fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean
fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean
//support Idea up to 2023.1 version, before KT-57371 fix
fun reportBoolean(name: String, value: Boolean, subprojectName: String?): Boolean
fun reportNumber(name: String, value: Long, subprojectName: String?): Boolean
fun reportString(name: String, value: String, subprojectName: String?): Boolean
}
internal abstract class KotlinBuildStatsService internal constructor() : BuildAdapter(), IStatisticsValuesConsumer {
companion object {
// Do not rename this bean otherwise compatibility with the older Kotlin Gradle Plugins would be lost
const val JMX_BEAN_NAME = "org.jetbrains.kotlin.gradle.plugin.statistics:type=StatsService"
private const val JMX_BEAN_NAME_BEFORE_232_IDEA = "org.jetbrains.kotlin.gradle.plugin.statistics:type=StatsService"
//update name when API changed
private const val SERVICE_NAME = "v2"
const val JMX_BEAN_NAME = "org.jetbrains.kotlin.gradle.plugin.statistics:type=StatsService,name=$SERVICE_NAME"
// Property name for disabling saving statistical information
const val ENABLE_STATISTICS_PROPERTY_NAME = "enable_kotlin_performance_profile"
@@ -80,6 +81,8 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
return instance
}
private fun getServiceName(): String = "${KotlinBuildStatsService::class.java}_$SERVICE_NAME"
/**
* Method for creating new instance of IStatisticsValuesConsumer
* It could be invoked only when applying Kotlin gradle plugin.
@@ -106,21 +109,23 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
val log = getLogger()
if (instance != null) {
log.debug("${KotlinBuildStatsService::class.java} is already instantiated. Current instance is $instance")
log.debug("${getServiceName()} is already instantiated. Current instance is $instance")
} else {
val beanName = ObjectName(JMX_BEAN_NAME)
val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
if (mbs.isRegistered(beanName)) {
log.debug(
"${KotlinBuildStatsService::class.java} is already instantiated in another classpath. Creating JMX-wrapper"
"${getServiceName()} is already instantiated in another classpath. Creating JMX-wrapper"
)
instance = JMXKotlinBuildStatsService(mbs, beanName)
} else {
val newInstance = DefaultKotlinBuildStatsService(gradle, beanName)
instance = newInstance
log.debug("Instantiated ${KotlinBuildStatsService::class.java}: new instance $instance")
log.debug("Instantiated ${getServiceName()}: new instance $instance")
mbs.registerMBean(StandardMBean(newInstance, KotlinBuildStatsMXBean::class.java), beanName)
registerPre232IdeaStatsBean(mbs, gradle, log)
}
if (!isConfigurationCacheAvailable(gradle)) {
@@ -132,6 +137,17 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
}
}
//To support backward compatibility with Idea before 232 version
private fun registerPre232IdeaStatsBean(mbs: MBeanServer, gradle: Gradle, log: Logger) {
val beanName = ObjectName(JMX_BEAN_NAME_BEFORE_232_IDEA)
if (!mbs.isRegistered(beanName)) {
val newInstance = Pre232IdeaKotlinBuildStatsService(gradle, beanName)
mbs.registerMBean(StandardMBean(newInstance, Pre232IdeaKotlinBuildStatsMXBean::class.java), beanName)
log.debug("Register JMX service for backward compatibility")
}
}
/**
* Invokes provided collector if the reporting service is initialised.
* The duration of collector's wall time is reported into overall overhead metric.
@@ -173,7 +189,7 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private val beanName: ObjectName) :
KotlinBuildStatsService() {
private fun callJmx_v2(method: String, type: String, metricName: String, value: Any, subprojectName: String?, weight: Long): Any? {
private fun callJmx(method: String, type: String, metricName: String, value: Any, subprojectName: String?, weight: Long?): Any? {
return mbs.invoke(
beanName,
method,
@@ -182,24 +198,6 @@ internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private
)
}
private fun callJmx_v1(method: String, type: String, metricName: String, value: Any, subprojectName: String?): Any? {
return mbs.invoke(
beanName,
method,
arrayOf(metricName, value, subprojectName),
arrayOf("java.lang.String", type, "java.lang.String")
)
}
//Temporary solution before KT-57371
private fun callJmx(method: String, type: String, metricName: String, value: Any, subprojectName: String?, weight: Long?): Any? {
return if (weight == null) {
callJmx_v1(method, type, metricName, value, subprojectName)
} else {
callJmx_v2(method, type, metricName, value, subprojectName, weight)
}
}
override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?) =
runSafe("report metric ${metric.name}") {
callJmx("reportBoolean", "boolean", metric.name, value, subprojectName, weight)
@@ -220,16 +218,16 @@ internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private
}
}
internal class DefaultKotlinBuildStatsService internal constructor(
internal abstract class AbstractKotlinBuildStatsService(
gradle: Gradle,
val beanName: ObjectName
) : KotlinBuildStatsService(), KotlinBuildStatsMXBean {
protected val beanName: ObjectName
) : KotlinBuildStatsService() {
private val forcePropertiesValidation = if (gradle.rootProject.hasProperty(FORCE_VALUES_VALIDATION)) {
gradle.rootProject.property(FORCE_VALUES_VALIDATION).toString().toBoolean()
} else {
false
}
private val sessionLogger = BuildSessionLogger(gradle.gradleUserHomeDir, forceValuesValidation = forcePropertiesValidation)
protected val sessionLogger = BuildSessionLogger(gradle.gradleUserHomeDir, forceValuesValidation = forcePropertiesValidation)
private fun gradleBuildStartTime(gradle: Gradle): Long? {
return (gradle as? DefaultGradle)?.services?.get(BuildRequestMetaData::class.java)?.startTime
@@ -248,9 +246,15 @@ internal class DefaultKotlinBuildStatsService internal constructor(
@Synchronized
override fun buildFinished(result: BuildResult) {
KotlinBuildStatHandler().buildFinished(result.gradle, beanName, sessionLogger, result.action, result.failure)
KotlinBuildStatHandler().buildFinished(beanName)
instance = null
}
}
internal class DefaultKotlinBuildStatsService internal constructor(
gradle: Gradle,
beanName: ObjectName
) : AbstractKotlinBuildStatsService(gradle, beanName), KotlinBuildStatsMXBean {
override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?): Boolean =
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName, weight)
@@ -270,15 +274,10 @@ internal class DefaultKotlinBuildStatsService internal constructor(
override fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean =
report(StringMetrics.valueOf(name), value, subprojectName, weight)
override fun reportBoolean(name: String, value: Boolean, subprojectName: String?): Boolean =
report(BooleanMetrics.valueOf(name), value, subprojectName, null)
override fun reportNumber(name: String, value: Long, subprojectName: String?): Boolean =
report(NumericalMetrics.valueOf(name), value, subprojectName, null)
override fun reportString(name: String, value: String, subprojectName: String?): Boolean =
report(StringMetrics.valueOf(name), value, subprojectName, null)
//only one jmx bean service should report global metrics
@Synchronized
override fun buildFinished(result: BuildResult) {
KotlinBuildStatHandler().reportGlobalMetricsAndBuildFinished(result.gradle, beanName, sessionLogger, result.action, result.failure)
instance = null
}
}
@@ -0,0 +1,20 @@
/*
* 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.plugin.statistics.old
internal interface Pre232IdeaKotlinBuildStatsMXBean {
fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean
fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean
fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean
fun reportBoolean(name: String, value: Boolean, subprojectName: String?): Boolean
fun reportNumber(name: String, value: Long, subprojectName: String?): Boolean
fun reportString(name: String, value: String, subprojectName: String?): Boolean
}
@@ -0,0 +1,50 @@
/*
* 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.plugin.statistics.old
import org.gradle.api.invocation.Gradle
import org.jetbrains.kotlin.gradle.plugin.statistics.AbstractKotlinBuildStatsService
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatHandler
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import javax.management.ObjectName
internal class Pre232IdeaKotlinBuildStatsService internal constructor(
gradle: Gradle,
beanName: ObjectName
) : AbstractKotlinBuildStatsService(gradle, beanName), Pre232IdeaKotlinBuildStatsMXBean {
override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?): Boolean =
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName, weight)
override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?, weight: Long?): Boolean =
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName, weight)
override fun report(metric: StringMetrics, value: String, subprojectName: String?, weight: Long?): Boolean =
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName, weight)
override fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean =
report(BooleanMetrics.valueOf(name), value, subprojectName, weight)
override fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean =
report(NumericalMetrics.valueOf(name), value, subprojectName, weight)
override fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean =
report(StringMetrics.valueOf(name), value, subprojectName, weight)
override fun reportBoolean(name: String, value: Boolean, subprojectName: String?): Boolean =
report(BooleanMetrics.valueOf(name), value, subprojectName, null)
override fun reportNumber(name: String, value: Long, subprojectName: String?): Boolean =
report(NumericalMetrics.valueOf(name), value, subprojectName, null)
override fun reportString(name: String, value: String, subprojectName: String?): Boolean =
report(StringMetrics.valueOf(name), value, subprojectName, null)
}
@@ -50,21 +50,6 @@ class BuildStatServiceTest {
return true
}
override fun reportBoolean(name: String, value: Boolean, subprojectName: String?): Boolean {
callsCount.incrementAndGet()
return true
}
override fun reportNumber(name: String, value: Long, subprojectName: String?): Boolean {
callsCount.incrementAndGet()
return true
}
override fun reportString(name: String, value: String, subprojectName: String?): Boolean {
callsCount.incrementAndGet()
return true
}
}
val beanName = ObjectName(KotlinBuildStatsService.JMX_BEAN_NAME)
@@ -5,18 +5,6 @@
package org.jetbrains.kotlin.statistics.metrics
interface ReportStatisticsValue<T> {
val name: String
val value: T
}
class ReportOnceStatisticsValue<T>(override val name: String, override val value: T) :
ReportStatisticsValue<T>
interface AdditiveStatisticsValue<T> : ReportStatisticsValue<T> {
fun addValue(t: T)
}
interface IStatisticsValuesConsumer {
fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String? = null, weight: Long? = null): Boolean