diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/FUSEventGroups.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/FUSEventGroups.kt index 8894a088ea5..f734d82250e 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/FUSEventGroups.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/statistics/FUSEventGroups.kt @@ -21,11 +21,26 @@ enum class FUSEventGroups(groupIdSuffix: String, val events: Set = setOf Debug("ide.debugger"), J2K("ide.j2k"), Editor("ide.editor"), - Settings("ide.settings"); + Settings("ide.settings"), + GradlePerformance("gradle.performance"); val GROUP_ID: String = "kotlin.$groupIdSuffix" } +@Suppress("EnumEntryName") +enum class GradleStatisticsEvents { + Environment, + Kapt, + CompilerPlugins, + MPP, + Libraries, + GradleConfiguration, + ComponentVersions, + KotlinFeatures, + GradlePerformance, + UseScenarios +} + val gradleTargetEvents = setOf( "kotlin-android", "kotlin-platform-common", diff --git a/idea/idea-gradle/build.gradle.kts b/idea/idea-gradle/build.gradle.kts index 0b452f548cd..cb45813e31e 100644 --- a/idea/idea-gradle/build.gradle.kts +++ b/idea/idea-gradle/build.gradle.kts @@ -26,6 +26,8 @@ dependencies { compileOnly(intellijPluginDep("junit")) compileOnly(intellijPluginDep("testng")) + compileOnly(project(":kotlin-gradle-statistics")) + Platform[192].orHigher { compileOnly(intellijPluginDep("java")) testCompileOnly(intellijPluginDep("java")) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt index 7f8b87e0eab..1256994d631 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.util.NotNullableCopyableDataNodeUserDataPropert import org.jetbrains.kotlin.idea.util.PsiPrecedences import org.jetbrains.kotlin.idea.statistics.FUSEventGroups import org.jetbrains.kotlin.idea.statistics.KotlinFUSLogger +import org.jetbrains.kotlin.idea.statistics.KotlinGradleFUSLogger import org.jetbrains.plugins.gradle.model.ExternalProjectDependency import org.jetbrains.plugins.gradle.model.ExternalSourceSet import org.jetbrains.plugins.gradle.model.FileCollectionDependency @@ -294,6 +295,7 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() nextResolver.populateModuleContentRoots(gradleModule, ideModule) val moduleNamePrefix = GradleProjectResolverUtil.getModuleId(resolverCtx, gradleModule) resolverCtx.getExtraProject(gradleModule, KotlinGradleModel::class.java)?.let { gradleModel -> + KotlinGradleFUSLogger.populateGradleUserDir(gradleModel.gradleUserHome) ideModule.pureKotlinSourceFolders = gradleModel.kotlinTaskProperties.flatMap { it.value.pureKotlinSourceFolders ?: emptyList() }.map { it.absolutePath } val gradleSourceSets = ideModule.children.filter { it.data is GradleSourceSetData } as Collection> diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt index 94be7888214..4f4f74c0828 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.idea.configuration +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.externalSystem.model.DataNode import com.intellij.openapi.externalSystem.model.ProjectKeys @@ -54,6 +55,7 @@ import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion import org.jetbrains.kotlin.idea.inspections.gradle.getResolvedVersionByModuleData import org.jetbrains.kotlin.idea.platform.tooling import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders +import org.jetbrains.kotlin.idea.statistics.KotlinGradleFUSLogger import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION import org.jetbrains.kotlin.platform.IdePlatformKind import org.jetbrains.kotlin.platform.impl.isCommon @@ -153,6 +155,10 @@ class KotlinGradleProjectDataService : AbstractProjectDataService() + fun putIfNotNull(key: String, value: String?) { + if (value != null) { + data[key.toLowerCase()] = value + } + } + + for (metric in metrics) { + when (metric) { + is BooleanMetrics -> putIfNotNull(metric.name, this.getMetric(metric)?.toStringRepresentation()) + is StringMetrics -> putIfNotNull(metric.name, this.getMetric(metric)?.toStringRepresentation()) + is NumericalMetrics -> putIfNotNull(metric.name, this.getMetric(metric)?.toStringRepresentation()) + is Pair<*, *> -> putIfNotNull(metric.first.toString(), metric.second.toString()) + } + } + if (data.size > 0) { + KotlinFUSLogger.log(FUSEventGroups.GradlePerformance, event.name, data) + } + } + + private fun processMetricsContainer(container: MetricsContainer, previous: MetricsContainer?) { + container.log( + GradleStatisticsEvents.Environment, + NumericalMetrics.CPU_NUMBER_OF_CORES, + StringMetrics.GRADLE_VERSION, + NumericalMetrics.ARTIFACTS_DOWNLOAD_SPEED, + StringMetrics.IDES_INSTALLED, + BooleanMetrics.EXECUTED_FROM_IDEA + ) + container.log( + GradleStatisticsEvents.Kapt, + BooleanMetrics.ENABLED_KAPT, + BooleanMetrics.ENABLED_DAGGER, + BooleanMetrics.ENABLED_DATABINDING + ) + + container.log( + GradleStatisticsEvents.CompilerPlugins, + BooleanMetrics.ENABLED_COMPILER_PLUGIN_ALL_OPEN, + BooleanMetrics.ENABLED_COMPILER_PLUGIN_NO_ARG, + BooleanMetrics.ENABLED_COMPILER_PLUGIN_JPA_SUPPORT, + BooleanMetrics.ENABLED_COMPILER_PLUGIN_SAM_WITH_RECEIVER + ) + + container.log( + GradleStatisticsEvents.MPP, + StringMetrics.MPP_PLATFORMS, + BooleanMetrics.ENABLED_HMPP + ) + + container.log( + GradleStatisticsEvents.Libraries, + StringMetrics.LIBRARY_SPRING_VERSION, + StringMetrics.LIBRARY_VAADIN_VERSION, + StringMetrics.LIBRARY_GWT_VERSION, + StringMetrics.LIBRARY_HIBERNATE_VERSION + ) + + container.log( + GradleStatisticsEvents.GradleConfiguration, + NumericalMetrics.GRADLE_DAEMON_HEAP_SIZE, + NumericalMetrics.GRADLE_BUILD_NUMBER_IN_CURRENT_DAEMON, + NumericalMetrics.CONFIGURATION_API_COUNT, + NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, + NumericalMetrics.CONFIGURATION_COMPILE_COUNT, + NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, + NumericalMetrics.GRADLE_NUMBER_OF_TASKS, + NumericalMetrics.GRADLE_NUMBER_OF_UNCONFIGURED_TASKS, + NumericalMetrics.GRADLE_NUMBER_OF_INCREMENTAL_TASKS + ) + + container.log( + GradleStatisticsEvents.ComponentVersions, + StringMetrics.KOTLIN_COMPILER_VERSION, + StringMetrics.KOTLIN_STDLIB_VERSION, + StringMetrics.KOTLIN_REFLECT_VERSION, + StringMetrics.KOTLIN_COROUTINES_VERSION, + StringMetrics.KOTLIN_SERIALIZATION_VERSION, + StringMetrics.ANDROID_GRADLE_PLUGIN_VERSION + ) + + container.log( + GradleStatisticsEvents.KotlinFeatures, + StringMetrics.KOTLIN_LANGUAGE_VERSION, + StringMetrics.KOTLIN_API_VERSION, + BooleanMetrics.BUILD_SRC_EXISTS, + NumericalMetrics.BUILD_SRC_COUNT, + BooleanMetrics.GRADLE_BUILD_CACHE_USED, + BooleanMetrics.GRADLE_WORKER_API_USED, + BooleanMetrics.KOTLIN_OFFICIAL_CODESTYLE, + BooleanMetrics.KOTLIN_PROGRESSIVE_MODE, + BooleanMetrics.KOTLIN_KTS_USED + ) + + container.log( + GradleStatisticsEvents.GradlePerformance, + NumericalMetrics.GRADLE_BUILD_DURATION, + NumericalMetrics.GRADLE_EXECUTION_DURATION, + NumericalMetrics.NUMBER_OF_SUBPROJECTS, + NumericalMetrics.STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD + ) + + val finishTime = container.getMetric(NumericalMetrics.BUILD_FINISH_TIME)?.getValue() + val prevFinishTime = previous?.getMetric(NumericalMetrics.BUILD_FINISH_TIME)?.getValue() + + val betweenBuilds = if (finishTime != null && prevFinishTime != null) finishTime - prevFinishTime else null + container.log( + GradleStatisticsEvents.UseScenarios, + Pair("time_between_builds", betweenBuilds), + BooleanMetrics.DEBUGGER_ENABLED, + BooleanMetrics.COMPILATION_STARTED, + BooleanMetrics.TESTS_EXECUTED, + BooleanMetrics.MAVEN_PUBLISH_EXECUTED, + BooleanMetrics.BUILD_FAILED + ) + } + + fun reportStatistics() { + if (isRunning.compareAndSet(false, true)) { + try { + for (gradleUserHome in gradleUserDirs) { + BuildSessionLogger.listProfileFiles(File(gradleUserHome, STATISTICS_FOLDER_NAME))?.forEach { statisticFile -> + try { + var previousEvent: MetricsContainer? = null + MetricsContainer.readFromFile(statisticFile) { metricContainer -> + processMetricsContainer(metricContainer, previousEvent) + previousEvent = metricContainer + } + } catch (e: Exception) { + Logger.getInstance(KotlinFUSLogger::class.java) + .info("Failed to process file ${statisticFile.absolutePath}: ${e.message}", e) + } finally { + if (!statisticFile.delete()) { + Logger.getInstance(KotlinFUSLogger::class.java) + .warn("[FUS] Failed to delete file ${statisticFile.absolutePath}") + } + } + } + } + } finally { + isRunning.set(false) + } + } + } + + private var gradleUserDirs: Array + set(value) = PropertiesComponent.getInstance().setValues( + GRADLE_USER_DIRS_PROPERTY_NAME, value + ) + get() = PropertiesComponent.getInstance().getValues(GRADLE_USER_DIRS_PROPERTY_NAME) ?: emptyArray() + + fun populateGradleUserDir(path: String) { + val currentState = gradleUserDirs + if (path in currentState) return + + val result = ArrayList() + result.add(path) + result.addAll(currentState) + + gradleUserDirs = + result.filter { filePath -> File(filePath).exists() }.take(MAXIMUM_USER_DIRS).toTypedArray() + } + } +} \ No newline at end of file diff --git a/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt index fa7c4b64801..84a7f303c79 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt @@ -54,6 +54,7 @@ interface KotlinGradleModel : Serializable { val implements: List val kotlinTarget: String? val kotlinTaskProperties: KotlinTaskPropertiesBySourceSet + val gradleUserHome: String } data class KotlinGradleModelImpl( @@ -63,7 +64,8 @@ data class KotlinGradleModelImpl( override val platformPluginId: String?, override val implements: List, override val kotlinTarget: String? = null, - override val kotlinTaskProperties: KotlinTaskPropertiesBySourceSet + override val kotlinTaskProperties: KotlinTaskPropertiesBySourceSet, + override val gradleUserHome: String ) : KotlinGradleModel abstract class AbstractKotlinGradleModelBuilder : ModelBuilderService { @@ -189,7 +191,8 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder() { platform, implementedProjects.map { it.pathOrName() }, platform ?: kotlinPluginId, - extraProperties + extraProperties, + project.gradle.gradleUserHomeDir.absolutePath ) } } diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index 0c0bc7d68f7..d996c1dbb6e 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -880,6 +880,8 @@ + + diff --git a/idea/resources/META-INF/plugin.xml b/idea/resources/META-INF/plugin.xml index 138d2b046f5..9d143c4d653 100644 --- a/idea/resources/META-INF/plugin.xml +++ b/idea/resources/META-INF/plugin.xml @@ -78,6 +78,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources/META-INF/plugin.xml.191 b/idea/resources/META-INF/plugin.xml.191 index e17d04b65a2..f2b7b3b0a89 100644 --- a/idea/resources/META-INF/plugin.xml.191 +++ b/idea/resources/META-INF/plugin.xml.191 @@ -78,6 +78,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/idea/resources/META-INF/plugin.xml.192 b/idea/resources/META-INF/plugin.xml.192 index 51a54214aeb..2610a203b30 100644 --- a/idea/resources/META-INF/plugin.xml.192 +++ b/idea/resources/META-INF/plugin.xml.192 @@ -78,6 +78,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 6290f28fab5..84bf9ee47a2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -28,12 +28,14 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements +import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget.* import org.jetbrains.kotlin.konan.target.presetName +import org.jetbrains.kotlin.statistics.metrics.StringMetrics class KotlinMultiplatformPlugin( private val kotlinPluginVersion: String, @@ -261,6 +263,8 @@ class KotlinMultiplatformPlugin( target.compilations.findByName(KotlinCompilation.TEST_COMPILATION_NAME)?.let { testCompilation -> sourceSets.findByName(testCompilation.defaultSourceSetName)?.dependsOn(test) } + + KotlinBuildStatsService.getInstance()?.report(StringMetrics.MPP_PLATFORMS, target.targetName) } UnusedSourceSetsChecker.checkSourceSets(project) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/DaemonReusageCounter.kt.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/DaemonReusageCounter.kt similarity index 99% rename from libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/DaemonReusageCounter.kt.kt rename to libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/DaemonReusageCounter.kt index 87219aa1039..667b823e1ca 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/DaemonReusageCounter.kt.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/DaemonReusageCounter.kt @@ -12,11 +12,9 @@ import javax.management.ObjectName import javax.management.StandardMBean interface IDaemonReuseCounterMXBean { - fun getOrdinal(): Long fun incrementAndGetOrdinal(): Long - } /** diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt index 8d337418d9f..f517fba3dc5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt @@ -7,9 +7,9 @@ package org.jetbrains.kotlin.gradle.plugin.statistics import org.gradle.BuildAdapter import org.gradle.BuildResult +import org.gradle.api.artifacts.DependencySet import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logging -import org.gradle.initialization.BuildCompletionListener import org.gradle.initialization.BuildRequestMetaData import org.gradle.invocation.DefaultGradle import org.jetbrains.kotlin.statistics.BuildSessionLogger @@ -20,6 +20,7 @@ import java.lang.management.ManagementFactory import javax.management.MBeanServer import javax.management.ObjectName import javax.management.StandardMBean +import kotlin.system.measureTimeMillis /** * Interface for populating statistics collection method via JXM interface @@ -27,21 +28,16 @@ import javax.management.StandardMBean * of Kotlin Plugin and other classloaders */ interface KotlinBuildStatsMXBean { - fun reportBoolean(name: String, value: Boolean, subprojectName: String?) fun reportNumber(name: String, value: Long, subprojectName: String?) fun reportString(name: String, value: String, subprojectName: String?) - } -internal abstract class KotlinBuildStatsService internal constructor() : BuildAdapter(), IStatisticsValuesConsumer, - BuildCompletionListener { - +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" @@ -54,7 +50,6 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd // "emergency file" collecting statistics is disabled it the file exists const val DISABLE_STATISTICS_FILE_NAME = "${STATISTICS_FOLDER_NAME}/.disable" - /** * Method for getting IStatisticsValuesConsumer for reporting some statistics * Could be invoked during any build phase after applying first Kotlin plugin and @@ -145,16 +140,11 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd } } } - - } internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private val beanName: ObjectName) : KotlinBuildStatsService() { - override fun buildFinished(result: BuildResult) { - } - private fun callJmx(method: String, type: String, metricName: String, value: Any, subprojectName: String?) { mbs.invoke( beanName, @@ -182,50 +172,89 @@ internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private } } - override fun completed() { + override fun buildFinished(result: BuildResult) { instance = null } - } internal class DefaultKotlinBuildStatsService internal constructor( gradle: Gradle, val beanName: ObjectName ) : KotlinBuildStatsService(), KotlinBuildStatsMXBean { - private val sessionLogger = BuildSessionLogger(gradle.gradleUserHomeDir) private fun gradleBuildStartTime(gradle: Gradle): Long? { return (gradle as? DefaultGradle)?.services?.get(BuildRequestMetaData::class.java)?.startTime } + private fun reportLibrariesVersions(dependencies: DependencySet?) { + dependencies?.forEach { dependency -> + when { + dependency.group?.startsWith("org.springframework") ?: false -> sessionLogger.report( + StringMetrics.LIBRARY_SPRING_VERSION, + dependency.version ?: "0.0.0" + ) + dependency.group?.startsWith("com.vaadin") ?: false -> sessionLogger.report( + StringMetrics.LIBRARY_VAADIN_VERSION, + dependency.version ?: "0.0.0" + ) + dependency.group?.startsWith("com.google.gwt") ?: false -> sessionLogger.report( + StringMetrics.LIBRARY_GWT_VERSION, + dependency.version ?: "0.0.0" + ) + dependency.group?.startsWith("org.hibernate") ?: false -> sessionLogger.report( + StringMetrics.LIBRARY_HIBERNATE_VERSION, + dependency.version ?: "0.0.0" + ) + } + } + } + private fun reportGlobalMetrics(gradle: Gradle) { System.getProperty("os.name")?.also { - sessionLogger.report(StringMetrics.OS_TYPE, gradle.gradleVersion) + sessionLogger.report(StringMetrics.OS_TYPE, System.getProperty("os.name")) } sessionLogger.report(NumericalMetrics.CPU_NUMBER_OF_CORES, Runtime.getRuntime().availableProcessors().toLong()) sessionLogger.report(StringMetrics.GRADLE_VERSION, gradle.gradleVersion) sessionLogger.report(BooleanMetrics.EXECUTED_FROM_IDEA, System.getProperty("idea.active") != null) + val statisticOverhead = measureTimeMillis { + gradle.allprojects { project -> + for (configuration in project.configurations) { + val configurationName = configuration.name + val dependencies = configuration.dependencies - gradle.allprojects { project -> - for (configuration in project.configurations) { - val configurationName = configuration.name - val dependencies = configuration.dependencies - - when (configurationName) { - "kapt" -> { - sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true) - dependencies.forEach { dependency -> - when (dependency.group) { - "com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true) - "com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true) + when (configurationName) { + "kapt" -> { + sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true) + dependencies?.forEach { dependency -> + when (dependency.group) { + "com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true) + "com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true) + } } } + "api" -> { + sessionLogger.report(NumericalMetrics.CONFIGURATION_API_COUNT, 1) + reportLibrariesVersions(dependencies) + } + "implementation" -> { + sessionLogger.report(NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, 1) + reportLibrariesVersions(dependencies) + } + "compile" -> { + sessionLogger.report(NumericalMetrics.CONFIGURATION_COMPILE_COUNT, 1) + reportLibrariesVersions(dependencies) + } + "runtime" -> { + sessionLogger.report(NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, 1) + reportLibrariesVersions(dependencies) + } } } } } + sessionLogger.report(NumericalMetrics.STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD, statisticOverhead) } override fun projectsEvaluated(gradle: Gradle) { @@ -243,16 +272,8 @@ internal class DefaultKotlinBuildStatsService internal constructor( @Synchronized override fun buildFinished(result: BuildResult) { runSafe("${DefaultKotlinBuildStatsService::class.java}.buildFinished") { - sessionLogger.finishBuildSession(result.action, result.failure) - } - } - - - @Synchronized - override fun completed() { - runSafe("${DefaultKotlinBuildStatsService::class.java}.completed") { try { - sessionLogger.unlockJournalFile() + sessionLogger.finishBuildSession(result.action, result.failure) } finally { val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer() if (mbs.isRegistered(beanName)) { 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 990621cacbe..952075ca765 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 @@ -25,7 +25,5 @@ class BuildStatServiceTest { jmxService.report(StringMetrics.KOTLIN_COMPILER_VERSION, "1.2.3") jmxService.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 10) jmxService.report(BooleanMetrics.ENABLED_DATABINDING, true) - - jmxService.completed() } } diff --git a/libraries/tools/kotlin-gradle-statistics/build.gradle.kts b/libraries/tools/kotlin-gradle-statistics/build.gradle.kts index 7d98a6bf440..45608643fba 100644 --- a/libraries/tools/kotlin-gradle-statistics/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-statistics/build.gradle.kts @@ -7,7 +7,7 @@ plugins { dependencies { compileOnly(kotlinStdlib()) - testCompile(project(":kotlin-test::kotlin-test-junit")) + testCompile(project(":kotlin-test:kotlin-test-junit")) testCompile("junit:junit:4.12") } @@ -19,5 +19,3 @@ sourceSets { projectTest { workingDir = rootDir } - -runtimeJar(rewriteDefaultJarDepsToShadedCompiler()) diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/AnonymizerUtils.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/AnonymizerUtils.kt index e06c933196f..ed5485ede98 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/AnonymizerUtils.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/AnonymizerUtils.kt @@ -21,8 +21,9 @@ internal val salt: String by lazy { fun anonymizeComponentVersion(version: String): String { return version.replace('-', '.') .split(".") - .filterIndexed { i, _ -> i < 3 } - .map { s -> s.toIntOrNull() ?: "?" } + .plus(listOf("0", "0")) // pad with zeros + .take(3) + .map { s -> s.toIntOrNull() ?: "0" } .joinToString(".") } diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSession.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSession.kt index 3a147ea1de3..dff2adc093c 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSession.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSession.kt @@ -6,7 +6,5 @@ package org.jetbrains.kotlin.statistics class BuildSession(val buildStartedTime: Long?) { - val projectEvaluatedTime = System.currentTimeMillis() - -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt index 52086357baa..3e977c87ea7 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt @@ -16,17 +16,23 @@ import java.time.LocalDateTime import java.time.format.DateTimeFormatter class BuildSessionLogger( - private val rootPath: File, + rootPath: File, private val maxProfileFiles: Int = DEFAULT_MAX_PROFILE_FILES, - private val maxFileSize: Long = DEFAULT_MAX_PROFILE_FILE_SIZE + private val maxFileSize: Long = DEFAULT_MAX_PROFILE_FILE_SIZE, + private val maxFileAge: Long = DEFAULT_MAX_FILE_AGE ) : IStatisticsValuesConsumer { companion object { const val STATISTICS_FOLDER_NAME = "kotlin-profile" - const val STATISTICS_FILE_NAME_PATTERN = "\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{3}.profile" + internal const val STATISTICS_FILE_NAME_PATTERN = "\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{3}.profile" private const val DEFAULT_MAX_PROFILE_FILES = 1_000 private const val DEFAULT_MAX_PROFILE_FILE_SIZE = 100_000L + private const val DEFAULT_MAX_FILE_AGE = 30 * 24 * 3600 * 1000L //30 days + + fun listProfileFiles(statisticsFolder: File): List? { + return statisticsFolder.listFiles()?.filterTo(ArrayList()) { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }?.sorted() + } } private val profileFileNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HH-mm-ss-SSS'.profile'") @@ -53,29 +59,44 @@ class BuildSessionLogger( @Synchronized private fun closeTrackingFile() { - metricsContainer.flush(trackingFile) - trackingFile?.close() - trackingFile = null + trackingFile?.let { + metricsContainer.flush(it) + it.close() + trackingFile = null + } } + /** + * Initializes a new tracking file + * The following contracts are implemented: + * - number of tracking files should not be more than maxProfileFiles (the earlier file created the earlier deleted) + * - files with age (current time - last modified) more than maxFileAge should be deleted (if we trust lastModified returned by FS) + * - files are ordered on the basis of name (creation timestamp) + * - if the last file has size less then maxFileSize, the next record will be append to it (new file created otherwise) + * - + */ @Synchronized private fun initTrackingFile() { closeTrackingFile() // Get list of existing files. Try to create folder if possible, return from function if failed to create folder - val fileCandidates = - statisticsFolder.listFiles()?.filter { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }?.toMutableList() - ?: if (statisticsFolder.mkdirs()) emptyList() else return + val fileCandidates = listProfileFiles(statisticsFolder) ?: if (statisticsFolder.mkdirs()) emptyList() else return - for (i in 0 until fileCandidates.size - maxProfileFiles) { - val file2delete = fileCandidates[i] - if (file2delete.isFile) { - file2delete.delete() + for ((index, file) in fileCandidates.withIndex()) { + val toDelete = if (index < fileCandidates.size - maxProfileFiles) + true + else { + val lastModified = file.lastModified() + (lastModified > 0) && (System.currentTimeMillis() - maxFileAge > lastModified) + } + if (toDelete) { + file.delete() } } // emergency check. What if a lot of files are locked due to some reason - if (statisticsFolder.listFiles()?.size ?: 0 > maxProfileFiles * 2) { + if (listProfileFiles(statisticsFolder)?.size ?: 0 > maxProfileFiles * 2) { + trackingFile = NullRecordLogger() return } @@ -99,20 +120,24 @@ class BuildSessionLogger( @Synchronized fun finishBuildSession(action: String?, failure: Throwable?) { - // nanotime could not be used as build start time in nanotime is unknown. As result, the measured duration - // could be affected by system clock correction - val finishTime = System.currentTimeMillis() - buildSession?.also { - if (it.buildStartedTime != null) { - report(NumericalMetrics.GRADLE_BUILD_DURATION, finishTime - it.buildStartedTime) + try { + // nanotime could not be used as build start time in nanotime is unknown. As result, the measured duration + // could be affected by system clock correction + val finishTime = System.currentTimeMillis() + buildSession?.also { + if (it.buildStartedTime != null) { + report(NumericalMetrics.GRADLE_BUILD_DURATION, finishTime - it.buildStartedTime) + } + report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime) } - report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime) + buildSession = null + } finally { + unlockJournalFile() } - buildSession = null } @Synchronized - fun unlockJournalFile() { + private fun unlockJournalFile() { closeTrackingFile() } diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/FileRecordLogger.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/FileRecordLogger.kt index 42099a3e7bd..610ec7bbf43 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/FileRecordLogger.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/FileRecordLogger.kt @@ -15,7 +15,6 @@ import java.nio.file.Paths import java.nio.file.StandardOpenOption class FileRecordLogger(file: File) : IRecordLogger { - private val channel: FileChannel = FileChannel.open(Paths.get(file.toURI()), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND) ?: throw IOException("Could not open file $file") diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/IRecordLogger.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/IRecordLogger.kt index 64820392e69..c8ada96c370 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/IRecordLogger.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/IRecordLogger.kt @@ -8,7 +8,5 @@ package org.jetbrains.kotlin.statistics.fileloggers import java.io.Closeable interface IRecordLogger : Closeable { - fun append(s: String) - -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt index 32e46283fe0..cf25013b1ae 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/fileloggers/MetricsContainer.kt @@ -15,11 +15,11 @@ import java.nio.file.StandardOpenOption import java.util.* class MetricsContainer : IStatisticsValuesConsumer { - data class MetricDescriptor(val name: String, val projectHash: String?) : Comparable { override fun compareTo(other: MetricDescriptor): Int { + val compareNames = name.compareTo(other.name) return when { - name.compareTo(other.name) != 0 -> name.compareTo(other.name) + compareNames != 0 -> compareNames projectHash == other.projectHash -> 0 else -> (projectHash ?: "").compareTo(other.projectHash ?: "") } @@ -33,16 +33,15 @@ class MetricsContainer : IStatisticsValuesConsumer { private val stringMetrics = TreeMap>() companion object { - private const val BUILD_SESSION_SEPARATOR = "BUILD FINISHED" val ENCODING = Charsets.UTF_8 - private val stringMetricsMap = StringMetrics.values().map { m -> m.name to m }.toMap() + private val stringMetricsMap = StringMetrics.values().associateBy(StringMetrics::name) - private val booleanMetricsMap = BooleanMetrics.values().map { m -> m.name to m }.toMap() + private val booleanMetricsMap = BooleanMetrics.values().associateBy(BooleanMetrics::name) - private val numericalMetricsMap = NumericalMetrics.values().map { m -> m.name to m }.toMap() + private val numericalMetricsMap = NumericalMetrics.values().associateBy(NumericalMetrics::name) fun readFromFile(file: File, consumer: (MetricsContainer) -> Unit) { val channel = FileChannel.open(Paths.get(file.toURI()), StandardOpenOption.WRITE, StandardOpenOption.READ) diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt index 9633c82c168..99a80ac6b90 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricContainers.kt @@ -13,7 +13,6 @@ interface IMetricContainer { fun toStringRepresentation(): String fun getValue(): T? - } interface IMetricContainerFactory { @@ -23,7 +22,6 @@ interface IMetricContainerFactory { } open class OverrideMetricContainer() : IMetricContainer { - internal var myValue: T? = null override fun addValue(t: T) { @@ -41,8 +39,19 @@ open class OverrideMetricContainer() : IMetricContainer { override fun getValue() = myValue } -class SumMetricContainer() : OverrideMetricContainer() { +class OverrideVersionMetricContainer() : OverrideMetricContainer() { + constructor(v: String) : this() { + myValue = v + } + override fun addValue(t: String) { + if (myValue == null || myValue == "0.0.0") { + myValue = t + } + } +} + +class SumMetricContainer() : OverrideMetricContainer() { constructor(v: Long) : this() { myValue = v } @@ -85,7 +94,6 @@ class OrMetricContainer() : OverrideMetricContainer() { } class ConcatMetricContainer() : IMetricContainer { - private val myValues = TreeSet() companion object { @@ -101,9 +109,8 @@ class ConcatMetricContainer() : IMetricContainer { } override fun toStringRepresentation(): String { - return myValues.joinToString(SEPARATOR) + return myValues.sorted().joinToString(SEPARATOR) } override fun getValue() = toStringRepresentation() } - diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricPolicies.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricPolicies.kt index 483f898daa9..26c1b88dc37 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricPolicies.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/MetricPolicies.kt @@ -16,6 +16,11 @@ enum class StringOverridePolicy: IMetricContainerFactory { override fun fromStringRepresentation(state: String): IMetricContainer? = OverrideMetricContainer(state) }, + OVERRIDE_VERSION_IF_NOT_SET { + override fun newMetricContainer(): IMetricContainer = OverrideVersionMetricContainer() + + override fun fromStringRepresentation(state: String): IMetricContainer? = OverrideVersionMetricContainer(state) + }, CONCAT { override fun newMetricContainer(): IMetricContainer = ConcatMetricContainer() diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt index 498b701bb09..1c01df8bf69 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt @@ -47,6 +47,8 @@ enum class NumericalMetrics(val type: NumberOverridePolicy, val anonymization: N NUMBER_OF_SUBPROJECTS(OVERRIDE, RANDOM_10_PERCENT), + STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD(SUM, RANDOM_10_PERCENT), + // User scenarios // this value is not reported, only time intervals from the previous build are used diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt index 62f666a2423..aaacbdb40d6 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StatisticsValues.kt @@ -18,11 +18,9 @@ interface AdditiveStatisticsValue : ReportStatisticsValue { } interface IStatisticsValuesConsumer { - fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String? = null) fun report(metric: NumericalMetrics, value: Long, subprojectName: String? = null) fun report(metric: StringMetrics, value: String, subprojectName: String? = null) - -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt index c9136f1d96e..31848350a68 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt @@ -23,10 +23,10 @@ enum class StringMetrics(val type: StringOverridePolicy, val anonymization: Stri MPP_PLATFORMS(CONCAT, SAFE), // Component versions - LIBRARY_SPRING_VERSION(OVERRIDE, COMPONENT_VERSION), - LIBRARY_VAADIN_VERSION(OVERRIDE, COMPONENT_VERSION), - LIBRARY_GWT_VERSION(OVERRIDE, COMPONENT_VERSION), - LIBRARY_HYBERNATE_VERSION(OVERRIDE, COMPONENT_VERSION), + LIBRARY_SPRING_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION), + LIBRARY_VAADIN_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION), + LIBRARY_GWT_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION), + LIBRARY_HIBERNATE_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION), KOTLIN_COMPILER_VERSION(OVERRIDE, COMPONENT_VERSION), KOTLIN_STDLIB_VERSION(OVERRIDE, COMPONENT_VERSION), @@ -39,9 +39,4 @@ enum class StringMetrics(val type: StringOverridePolicy, val anonymization: Stri // Features KOTLIN_LANGUAGE_VERSION(OVERRIDE, COMPONENT_VERSION), KOTLIN_API_VERSION(OVERRIDE, COMPONENT_VERSION), - - - } - - diff --git a/libraries/tools/kotlin-gradle-statistics/test/org/jetbrains/kotlin/statistics/BuildSessionLoggerTest.kt b/libraries/tools/kotlin-gradle-statistics/test/org/jetbrains/kotlin/statistics/BuildSessionLoggerTest.kt index 9104654ceac..946c178eab7 100644 --- a/libraries/tools/kotlin-gradle-statistics/test/org/jetbrains/kotlin/statistics/BuildSessionLoggerTest.kt +++ b/libraries/tools/kotlin-gradle-statistics/test/org/jetbrains/kotlin/statistics/BuildSessionLoggerTest.kt @@ -5,25 +5,21 @@ package org.jetbrains.kotlin.statistics -import com.sun.javafx.font.Metrics import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.STATISTICS_FILE_NAME_PATTERN +import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.listProfileFiles import org.jetbrains.kotlin.statistics.fileloggers.MetricsContainer import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics -import org.jetbrains.kotlin.statistics.metrics.OverrideMetricContainer import org.jetbrains.kotlin.statistics.metrics.StringMetrics import org.junit.After import org.junit.Before import java.io.File import java.lang.IllegalStateException -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.test.fail +import kotlin.test.* class BuildSessionLoggerTest { - lateinit var rootFolder: File + private lateinit var rootFolder: File private fun statFilesCount() = rootFolder.listFiles().single().listFiles().size @@ -74,7 +70,6 @@ class BuildSessionLoggerTest { val logger = BuildSessionLogger(rootFolder, 100, maxFileSize.toLong()) logger.startBuildSession(0, null) logger.finishBuildSession("", null) - logger.unlockJournalFile() assertEquals(1, statFilesCount()) @@ -82,7 +77,6 @@ class BuildSessionLoggerTest { logger.startBuildSession(0, 0) logger.finishBuildSession("", null) - logger.unlockJournalFile() //new file should not be created assertEquals(1, statFilesCount()) @@ -90,7 +84,6 @@ class BuildSessionLoggerTest { logger.startBuildSession(0, 0) logger.finishBuildSession("", null) - logger.unlockJournalFile() // a new file should be created as maximal file size assertEquals(2, statFilesCount()) @@ -102,7 +95,6 @@ class BuildSessionLoggerTest { val logger = BuildSessionLogger(rootFolder, maxFiles) logger.startBuildSession(0, null) logger.finishBuildSession("", null) - logger.unlockJournalFile() assertEquals(1, statFilesCount()) val statsFolder = rootFolder.listFiles().single() @@ -116,7 +108,6 @@ class BuildSessionLoggerTest { logger.startBuildSession(0, 0) logger.finishBuildSession("", null) - logger.unlockJournalFile() assertTrue( statsFolder.listFiles().filter { it.name == singleStatFile.name }.count() == 1, @@ -135,6 +126,10 @@ class BuildSessionLoggerTest { statsFolder.listFiles().filter { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }.count(), "Some files which should not be affected, were removed" ) + assertEquals( + statsFolder.listFiles().filter { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }.sorted(), + listProfileFiles(statsFolder) + ) } @Test @@ -142,10 +137,9 @@ class BuildSessionLoggerTest { val logger = BuildSessionLogger(rootFolder) logger.report(StringMetrics.KOTLIN_COMPILER_VERSION, "1.2.3.4-snapshot") - val startTime = System.currentTimeMillis() - 1000 + val startTime = System.currentTimeMillis() - 1001 logger.startBuildSession(1, startTime) logger.finishBuildSession("Build", null) - logger.unlockJournalFile() assertEquals(1, statFilesCount()) val statFile = rootFolder.listFiles().single().listFiles().single() @@ -165,7 +159,6 @@ class BuildSessionLoggerTest { logger.finishBuildSession("", null) - logger.unlockJournalFile() val metrics = ArrayList() MetricsContainer.readFromFile(statFile) { @@ -186,4 +179,33 @@ class BuildSessionLoggerTest { val buildDuration = metrics[0].getMetric(NumericalMetrics.GRADLE_BUILD_DURATION)?.getValue() ?: 0L assertTrue(buildDuration > 1000, "It was expected that build duration is > 1000, but got $buildDuration") } + + @Test + fun testSaveAndReadAllMetrics() { + val logger = BuildSessionLogger(rootFolder) + logger.startBuildSession(1, 1) + for (metric in StringMetrics.values()) { + logger.report(metric, "value") + logger.report(metric, metric.name) + } + for (metric in BooleanMetrics.values()) { + logger.report(metric, true) + } + for (metric in NumericalMetrics.values()) { + logger.report(metric, System.currentTimeMillis()) + } + logger.finishBuildSession("Build", null) + + MetricsContainer.readFromFile(rootFolder.listFiles().single().listFiles().single()) { + for (metric in StringMetrics.values()) { + assertNotNull(it.getMetric(metric), "Could not find metric ${metric.name}") + } + for (metric in BooleanMetrics.values()) { + assertTrue(it.getMetric(metric)?.getValue() ?: false, "Could not find metric ${metric.name}") + } + for (metric in NumericalMetrics.values()) { + assertNotNull(it.getMetric(metric), "Could not find metric ${metric.name}") + } + } + } } diff --git a/prepare/idea-plugin/build.gradle.kts b/prepare/idea-plugin/build.gradle.kts index 6ff5903e9ad..0b6458aff89 100644 --- a/prepare/idea-plugin/build.gradle.kts +++ b/prepare/idea-plugin/build.gradle.kts @@ -67,6 +67,7 @@ val projectsToShadow by extra(listOf( ":js:js.translator", ":kotlin-native:kotlin-native-utils", ":kotlin-native:kotlin-native-library-reader", + ":kotlin-gradle-statistics", ":compiler:light-classes", ":compiler:plugin-api", ":kotlin-preloader",