diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt index 295d6c4f11d..65eb864bd66 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt @@ -191,22 +191,33 @@ class KotlinBuildStatHandler { } } - internal fun report(sessionLogger: BuildSessionLogger, metric: BooleanMetrics, value: Boolean, subprojectName: String?) { - runSafe("report metric ${metric.name}") { - sessionLogger.report(metric, value, subprojectName) - } + internal fun report( + sessionLogger: BuildSessionLogger, + metric: BooleanMetrics, + value: Boolean, + subprojectName: String?, + weight: Long? = null + ) = runSafe("report metric ${metric.name}") { + sessionLogger.report(metric, value, subprojectName, weight) + } ?: false - } + internal fun report( + sessionLogger: BuildSessionLogger, + metric: NumericalMetrics, + value: Long, + subprojectName: String?, + weight: Long? = null + ) = runSafe("report metric ${metric.name}") { + sessionLogger.report(metric, value, subprojectName, weight) + } as? Boolean ?: false - internal fun report(sessionLogger: BuildSessionLogger, metric: NumericalMetrics, value: Long, subprojectName: String?) { - runSafe("report metric ${metric.name}") { - sessionLogger.report(metric, value, subprojectName) - } - } - - internal fun report(sessionLogger: BuildSessionLogger, metric: StringMetrics, value: String, subprojectName: String?) { - runSafe("report metric ${metric.name}") { - sessionLogger.report(metric, value, subprojectName) - } - } + internal fun report( + sessionLogger: BuildSessionLogger, + metric: StringMetrics, + value: String, + subprojectName: String?, + weight: Long? = null + ) = runSafe("report metric ${metric.name}") { + sessionLogger.report(metric, value, subprojectName, weight) + } as? Boolean ?: false } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt index 883b8f12ae0..e2c6b53e404 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt @@ -33,11 +33,11 @@ import kotlin.system.measureTimeMillis * of Kotlin Plugin and other classloaders */ interface KotlinBuildStatsMXBean { - fun reportBoolean(name: String, value: Boolean, subprojectName: String?) + fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean - fun reportNumber(name: String, value: Long, subprojectName: String?) + fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean - fun reportString(name: String, value: String, subprojectName: String?) + fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean } @@ -158,32 +158,29 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private val beanName: ObjectName) : KotlinBuildStatsService() { - private fun callJmx(method: String, type: String, metricName: String, value: Any, subprojectName: String?) { - mbs.invoke( + private fun callJmx(method: String, type: String, metricName: String, value: Any, subprojectName: String?, weight: Long?): Any? { + return mbs.invoke( beanName, method, - arrayOf(metricName, value, subprojectName), - arrayOf("java.lang.String", type, "java.lang.String") + arrayOf(metricName, value, subprojectName, weight), + arrayOf("java.lang.String", type, "java.lang.String", "java.lang.Long") ) } - override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?) { + override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?) = runSafe("report metric ${metric.name}") { - callJmx("reportBoolean", "boolean", metric.name, value, subprojectName) - } - } + callJmx("reportBoolean", "boolean", metric.name, value, subprojectName, weight) + } as? Boolean ?: false - override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?) { + override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?, weight: Long?) = runSafe("report metric ${metric.name}") { - callJmx("reportNumber", "long", metric.name, value, subprojectName) - } - } + callJmx("reportNumber", "long", metric.name, value, subprojectName, weight) + } as? Boolean ?: false - override fun report(metric: StringMetrics, value: String, subprojectName: String?) { + override fun report(metric: StringMetrics, value: String, subprojectName: String?, weight: Long?) = runSafe("report metric ${metric.name}") { - callJmx("reportString", "java.lang.String", metric.name, value, subprojectName) - } - } + callJmx("reportString", "java.lang.String", metric.name, value, subprojectName, weight) + } as? Boolean ?: false override fun buildFinished(result: BuildResult) { instance = null @@ -217,27 +214,21 @@ internal class DefaultKotlinBuildStatsService internal constructor( instance = null } - override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?) { - KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName) - } + 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?) { - KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName) - } + 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?) { - KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName) - } + 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?) { - report(BooleanMetrics.valueOf(name), value, subprojectName) - } + 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?) { - report(NumericalMetrics.valueOf(name), value, subprojectName) - } + 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?) { - report(StringMetrics.valueOf(name), value, subprojectName) - } + override fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean = + report(StringMetrics.valueOf(name), value, subprojectName, weight) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildStatServiceTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildStatServiceTest.kt index 952075ca765..c3bd784c967 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildStatServiceTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildStatServiceTest.kt @@ -10,8 +10,12 @@ import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics import org.junit.Test import java.lang.management.ManagementFactory +import java.util.concurrent.atomic.AtomicInteger import javax.management.MBeanServer import javax.management.ObjectName +import javax.management.StandardMBean +import kotlin.test.assertEquals +import kotlin.test.assertTrue class BuildStatServiceTest { @@ -26,4 +30,41 @@ class BuildStatServiceTest { jmxService.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 10) jmxService.report(BooleanMetrics.ENABLED_DATABINDING, true) } + + @Test + fun testJmxServerWorks() { + val callsCount = AtomicInteger(0) + val instance = object : KotlinBuildStatsMXBean { + override fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean { + callsCount.incrementAndGet() + return true + } + + override fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean { + callsCount.incrementAndGet() + return true + } + + override fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean { + callsCount.incrementAndGet() + return true + } + + } + + val beanName = ObjectName(KotlinBuildStatsService.JMX_BEAN_NAME) + val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer() + mbs.registerMBean(StandardMBean(instance, KotlinBuildStatsMXBean::class.java), beanName) + + try { + val jmxService = JMXKotlinBuildStatsService(mbs, beanName) + assertTrue(jmxService.report(StringMetrics.KOTLIN_COMPILER_VERSION, "1.2.3")) + assertTrue(jmxService.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 10)) + assertTrue(jmxService.report(BooleanMetrics.ENABLED_DATABINDING, true)) + assertEquals(3, callsCount.get()) + } finally { + mbs.unregisterMBean(beanName) + } + + } } diff --git a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt index 2760fd4be42..37f164dc684 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt @@ -154,15 +154,12 @@ class BuildSessionLogger( closeTrackingFile() } - override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?) { - metricsContainer.report(metric, value, subprojectName) - } + override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?) = + metricsContainer.report(metric, value, subprojectName, weight) - override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?) { - metricsContainer.report(metric, value, subprojectName) - } + override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?, weight: Long?) = + metricsContainer.report(metric, value, subprojectName, weight) - override fun report(metric: StringMetrics, value: String, subprojectName: String?) { - metricsContainer.report(metric, value, subprojectName) - } + override fun report(metric: StringMetrics, value: String, subprojectName: String?, weight: Long?) = + metricsContainer.report(metric, value, subprojectName, weight) } diff --git a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt index e538ba31fb0..2c5ef4f59f8 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt @@ -104,31 +104,34 @@ class MetricsContainer : IStatisticsValuesConsumer { private fun getProjectHash(perProject: Boolean, subprojectName: String?) = if (subprojectName == null) null else processProjectName(subprojectName, perProject) - override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?) { + override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?): Boolean { val projectHash = getProjectHash(metric.perProject, subprojectName) synchronized(metricsLock) { val metricContainer = booleanMetrics[MetricDescriptor(metric.name, projectHash)] ?: metric.type.newMetricContainer() .also { booleanMetrics[MetricDescriptor(metric.name, projectHash)] = it } - metricContainer.addValue(metric.anonymization.anonymize(value)) + metricContainer.addValue(metric.anonymization.anonymize(value), weight) } + return true } - override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?) { + override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?, weight: Long?): Boolean { val projectHash = getProjectHash(metric.perProject, subprojectName) synchronized(metricsLock) { val metricContainer = numericalMetrics[MetricDescriptor(metric.name, projectHash)] ?: metric.type.newMetricContainer() .also { numericalMetrics[MetricDescriptor(metric.name, projectHash)] = it } - metricContainer.addValue(metric.anonymization.anonymize(value)) + metricContainer.addValue(metric.anonymization.anonymize(value), weight) } + return true } - override fun report(metric: StringMetrics, value: String, subprojectName: String?) { + override fun report(metric: StringMetrics, value: String, subprojectName: String?, weight: Long?): Boolean { val projectHash = getProjectHash(metric.perProject, subprojectName) synchronized(metricsLock) { val metricContainer = stringMetrics[MetricDescriptor(metric.name, projectHash)] ?: metric.type.newMetricContainer() .also { stringMetrics[MetricDescriptor(metric.name, projectHash)] = it } - metricContainer.addValue(metric.anonymization.anonymize(value)) + metricContainer.addValue(metric.anonymization.anonymize(value), weight) } + return true } fun flush(trackingFile: IRecordLogger?) { diff --git a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt index 99a80ac6b90..7c88f3378ab 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.statistics.metrics import java.util.* interface IMetricContainer { - fun addValue(t: T) + fun addValue(t: T, weight: Long? = null) fun toStringRepresentation(): String @@ -24,7 +24,7 @@ interface IMetricContainerFactory { open class OverrideMetricContainer() : IMetricContainer { internal var myValue: T? = null - override fun addValue(t: T) { + override fun addValue(t: T, weight: Long?) { myValue = t } @@ -44,7 +44,7 @@ class OverrideVersionMetricContainer() : OverrideMetricContainer() { myValue = v } - override fun addValue(t: String) { + override fun addValue(t: String, weight: Long?) { if (myValue == null || myValue == "0.0.0") { myValue = t } @@ -56,22 +56,24 @@ class SumMetricContainer() : OverrideMetricContainer() { myValue = v } - override fun addValue(t: Long) { + override fun addValue(t: Long, weight: Long?) { myValue = (myValue ?: 0) + t } } class AverageMetricContainer() : IMetricContainer { - private var count = 0 - private var myValue: Long? = null + private var totalWeight = 0L + private var totalSum: Long? = null constructor(v: Long) : this() { - myValue = v + totalSum = v + totalWeight = 1 } - override fun addValue(t: Long) { - myValue = (myValue ?: 0) + t - count++ + override fun addValue(t: Long, weight: Long?) { + val w = weight ?: 1 + totalSum = (totalSum ?: 0) + t * w + totalWeight += w } override fun toStringRepresentation(): String { @@ -79,7 +81,7 @@ class AverageMetricContainer() : IMetricContainer { } override fun getValue(): Long? { - return myValue?.div(count) + return totalSum?.div(if (totalWeight > 0) totalWeight else 1) } } @@ -88,7 +90,7 @@ class OrMetricContainer() : OverrideMetricContainer() { myValue = v } - override fun addValue(t: Boolean) { + override fun addValue(t: Boolean, weight: Long?) { myValue = (myValue ?: false) || t } } @@ -104,7 +106,7 @@ class ConcatMetricContainer() : IMetricContainer { myValues.addAll(values) } - override fun addValue(t: String) { + override fun addValue(t: String, weight: Long?) { myValues.add(t.replace(SEPARATOR, ",")) } diff --git a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt index aaacbdb40d6..f1d05b5cce9 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/common/kotlin/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt @@ -18,9 +18,9 @@ interface AdditiveStatisticsValue : ReportStatisticsValue { } interface IStatisticsValuesConsumer { - fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String? = null) + fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String? = null, weight: Long? = null): Boolean - fun report(metric: NumericalMetrics, value: Long, subprojectName: String? = null) + fun report(metric: NumericalMetrics, value: Long, subprojectName: String? = null, weight: Long? = null): Boolean - fun report(metric: StringMetrics, value: String, subprojectName: String? = null) + fun report(metric: StringMetrics, value: String, subprojectName: String? = null, weight: Long? = null): Boolean }