diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportImpl.kt index 4e71ca62f68..bac88ec7d3c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportImpl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportImpl.kt @@ -17,10 +17,12 @@ import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.re import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.* import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.Companion.logger import org.jetbrains.kotlin.tooling.core.Extras +import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult internal class IdeMultiplatformImportImpl( - private val extension: KotlinProjectExtension + private val extension: KotlinProjectExtension, + val statistics: IdeMultiplatformImportStatistics = IdeMultiplatformImportStatistics() ) : IdeMultiplatformImport { override fun resolveDependencies(sourceSetName: String): Set { @@ -59,7 +61,7 @@ internal class IdeMultiplatformImportImpl( level: DependencyResolutionLevel ) { registeredDependencyResolvers.add( - RegisteredDependencyResolver(resolver, constraint, phase, level) + RegisteredDependencyResolver(statistics, resolver, constraint, phase, level) ) if (resolver is IdeDependencyResolver.WithBuildDependencies) { @@ -159,28 +161,40 @@ internal class IdeMultiplatformImportImpl( val constraint: SourceSetConstraint, ) - private class RegisteredDependencyResolver( + private data class RegisteredDependencyResolver( + private val statistics: IdeMultiplatformImportStatistics, private val resolver: IdeDependencyResolver, val constraint: SourceSetConstraint, val phase: DependencyResolutionPhase, val level: DependencyResolutionLevel, ) : IdeDependencyResolver { + private class TimeMeasuredResult(val timeInMillis: Long, val dependencies: Set) + override fun resolve(sourceSet: KotlinSourceSet): Set { - return runCatching { resolver.resolve(sourceSet) } + return runCatching { resolveTimed(sourceSet) } .onFailure { error -> reportError(sourceSet, error) } - .onSuccess { dependencies -> reportSuccess(sourceSet, dependencies) } - .onSuccess { dependencies -> attachResolvedByExtra(dependencies) } - .getOrNull().orEmpty() + .onSuccess { result -> reportSuccess(sourceSet, result) } + .onSuccess { result -> attachResolvedByExtra(result.dependencies) } + .getOrNull()?.dependencies.orEmpty() + } + + private fun resolveTimed(sourceSet: KotlinSourceSet): TimeMeasuredResult { + val (time, result) = measureTimeMillisWithResult { resolver.resolve(sourceSet) } + statistics.addExecutionTime(resolver::class.java, time) + return TimeMeasuredResult(time, result) } private fun reportError(sourceSet: KotlinSourceSet, error: Throwable) { logger.error("e: ${resolver::class.java.name} failed on ${IdeaKotlinSourceCoordinates(sourceSet)}", error) } - private fun reportSuccess(sourceSet: KotlinSourceSet, dependencies: Set) { + private fun reportSuccess(sourceSet: KotlinSourceSet, result: TimeMeasuredResult) { if (!logger.isDebugEnabled) return - logger.debug("${resolver::class.java.name} resolved on ${IdeaKotlinSourceCoordinates(sourceSet)}: $dependencies") + logger.debug( + "${resolver::class.java.name} resolved on ${IdeaKotlinSourceCoordinates(sourceSet)}: " + + "${result.dependencies} (${result.timeInMillis} ms)" + ) } private fun attachResolvedByExtra(dependencies: Iterable) { @@ -189,5 +203,4 @@ internal class IdeMultiplatformImportImpl( } } } - } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportStatistics.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportStatistics.kt new file mode 100644 index 00000000000..ddb0c32526e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportStatistics.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2022 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.ide + +/** + * Simple implementation to track dependency resolution bottlenecks. + * This will later be replaced by properly tracing ide import. + */ +internal class IdeMultiplatformImportStatistics { + + private val times = mutableMapOf, Long>() + + fun addExecutionTime(clazz: Class<*>, timeInMillis: Long) { + times[clazz] = times.getOrDefault(clazz, 0) + timeInMillis + } + + fun getExecutionTimes(): Map, Long> { + return times.toMap() + } + + fun clear() { + times.clear() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeResolveDependenciesTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeResolveDependenciesTask.kt index 8f1fdc6cc55..7766590b8fb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeResolveDependenciesTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeResolveDependenciesTask.kt @@ -13,6 +13,7 @@ import org.gradle.api.tasks.TaskProvider import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependencyCoordinates import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask +import org.jetbrains.kotlin.gradle.utils.appendLine import org.jetbrains.kotlin.gradle.utils.notCompatibleWithConfigurationCacheCompat import org.jetbrains.kotlin.tooling.core.Extras import java.io.File @@ -57,6 +58,15 @@ internal open class IdeResolveDependenciesTask : DefaultTask() { protoOutput.writeBytes(proto) } } + + (project.kotlinIdeMultiplatformImport as? IdeMultiplatformImportImpl)?.statistics?.let { statistics -> + val timeStatisticsFile = outputDirectory.resolve("times.txt") + timeStatisticsFile.writeText(buildString { + statistics.getExecutionTimes().forEach { (clazz, time) -> + appendLine("${clazz.name} $time.ms") + } + }) + } } private object IdeDependencyResolverAdapter : JsonSerializer {