Introduce KotlinGradleBuildServices that is created once per build
This commit is contained in:
+40
-26
@@ -19,13 +19,13 @@ package org.jetbrains.kotlin.gradle.plugin
|
|||||||
import org.apache.commons.lang.SystemUtils
|
import org.apache.commons.lang.SystemUtils
|
||||||
import org.gradle.BuildAdapter
|
import org.gradle.BuildAdapter
|
||||||
import org.gradle.BuildResult
|
import org.gradle.BuildResult
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.invocation.Gradle
|
||||||
import org.gradle.api.logging.Logging
|
import org.gradle.api.logging.Logging
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.com.intellij.openapi.util.io.ZipFileCache
|
import org.jetbrains.kotlin.com.intellij.openapi.util.io.ZipFileCache
|
||||||
import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.ZipHandler
|
import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.ZipHandler
|
||||||
import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
|
import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||||
|
|
||||||
private fun comparableVersionStr(version: String) =
|
private fun comparableVersionStr(version: String) =
|
||||||
"(\\d+)\\.(\\d+).*"
|
"(\\d+)\\.(\\d+).*"
|
||||||
@@ -37,9 +37,26 @@ private fun comparableVersionStr(version: String) =
|
|||||||
?.let { if (it.all { (it?.value?.length ?: 0).let { it > 0 && it < 4 }}) it else null }
|
?.let { if (it.all { (it?.value?.length ?: 0).let { it > 0 && it < 4 }}) it else null }
|
||||||
?.joinToString(".", transform = { it!!.value.padStart(3, '0') })
|
?.joinToString(".", transform = { it!!.value.padStart(3, '0') })
|
||||||
|
|
||||||
class CleanUpBuildListener(private val project: Project) : BuildAdapter() {
|
class KotlinGradleBuildServices private constructor(): BuildAdapter() {
|
||||||
companion object {
|
companion object {
|
||||||
const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()"
|
const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()"
|
||||||
|
const val INIT_MESSAGE = "Initialized KotlinGradleBuildServices"
|
||||||
|
const val DISPOSE_MESSAGE = "Disposed KotlinGradleBuildServices"
|
||||||
|
private var initialized = false
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@Synchronized
|
||||||
|
fun init(gradle: Gradle) {
|
||||||
|
if (initialized) return
|
||||||
|
|
||||||
|
val listener = KotlinGradleBuildServices()
|
||||||
|
gradle.addBuildListener(listener)
|
||||||
|
initialized = true
|
||||||
|
val log = Logging.getLogger(KotlinGradleBuildServices::class.java)
|
||||||
|
log.kotlinDebug(INIT_MESSAGE)
|
||||||
|
|
||||||
|
listener.buildStarted()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val log = Logging.getLogger(this.javaClass)
|
private val log = Logging.getLogger(this.javaClass)
|
||||||
@@ -54,34 +71,31 @@ class CleanUpBuildListener(private val project: Project) : BuildAdapter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun buildFinished(result: BuildResult?) {
|
override fun buildFinished(result: BuildResult) {
|
||||||
val gradle = result?.gradle
|
val gradle = result.gradle!!
|
||||||
if (gradle != null) {
|
val kotlinCompilerCalled = gradle.rootProject.allprojects.flatMap { it.tasks }.any { it is AbstractKotlinCompile<*> && it.compilerCalled }
|
||||||
|
|
||||||
val kotlinCompilerCalled = project.tasks.filter { it.name.contains("kotlin", ignoreCase = true) }
|
if (kotlinCompilerCalled) {
|
||||||
.any { task -> task.hasProperty("compilerCalled") && task.property("compilerCalled") as? Boolean ?: false }
|
log.kotlinDebug("Cleanup after kotlin")
|
||||||
|
cleanup(gradle.gradleVersion)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.kotlinDebug("Skipping kotlin cleanup since compiler wasn't called")
|
||||||
|
}
|
||||||
|
|
||||||
if (kotlinCompilerCalled) {
|
if (kotlinCompilerCalled) {
|
||||||
log.kotlinDebug("Cleanup after kotlin")
|
startMemory?.let { startMemoryCopy ->
|
||||||
|
getUsedMemoryKb()?.let { endMemory ->
|
||||||
cleanup(gradle.gradleVersion)
|
// the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
|
||||||
}
|
// but on subsequent runs in the daemon it should be rather small, then the classes are actually reused by the daemon (see above)
|
||||||
else {
|
log.kotlinDebug("[PERF] Used memory after build: $endMemory kb (difference since build start: ${"%+d".format(endMemory - startMemoryCopy)} kb)")
|
||||||
log.kotlinDebug("Skipping kotlin cleanup since compiler wasn't called")
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.removeListener(this)
|
|
||||||
|
|
||||||
if (kotlinCompilerCalled) {
|
|
||||||
startMemory?.let { startMemoryCopy ->
|
|
||||||
getUsedMemoryKb()?.let { endMemory ->
|
|
||||||
// the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
|
|
||||||
// but on subsequent runs in the daemon it should be rather small, then the classes are actually reused by the daemon (see above)
|
|
||||||
log.kotlinDebug("[PERF] Used memory after build: $endMemory kb (difference since build start: ${"%+d".format(endMemory - startMemoryCopy)} kb)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gradle.removeListener(this)
|
||||||
|
initialized = false
|
||||||
|
log.kotlinDebug(DISPOSE_MESSAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUsedMemoryKb(): Long? {
|
private fun getUsedMemoryKb(): Long? {
|
||||||
+1
-3
@@ -23,9 +23,7 @@ abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver)
|
|||||||
val plugin = getPlugin()
|
val plugin = getPlugin()
|
||||||
plugin.apply(project)
|
plugin.apply(project)
|
||||||
|
|
||||||
val cleanUpBuildListener = CleanUpBuildListener(project)
|
KotlinGradleBuildServices.init(project.gradle)
|
||||||
cleanUpBuildListener.buildStarted()
|
|
||||||
project.gradle.addBuildListener(cleanUpBuildListener)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun getPlugin(): Plugin<Project>
|
protected abstract fun getPlugin(): Plugin<Project>
|
||||||
|
|||||||
+2
@@ -43,6 +43,7 @@ abstract class AbstractKotlinAndroidGradleTests(
|
|||||||
":compileFlavor1DebugUnitTestKotlin",
|
":compileFlavor1DebugUnitTestKotlin",
|
||||||
"InternalDummyTest PASSED",
|
"InternalDummyTest PASSED",
|
||||||
":compileFlavor1DebugAndroidTestKotlin")
|
":compileFlavor1DebugAndroidTestKotlin")
|
||||||
|
checkKotlinGradleBuildServices()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the build second time, assert everything is up-to-date
|
// Run the build second time, assert everything is up-to-date
|
||||||
@@ -69,6 +70,7 @@ abstract class AbstractKotlinAndroidGradleTests(
|
|||||||
":compileFlavor2Jnidebug",
|
":compileFlavor2Jnidebug",
|
||||||
":compileFlavor1Release",
|
":compileFlavor1Release",
|
||||||
":compileFlavor2Release")
|
":compileFlavor2Release")
|
||||||
|
checkKotlinGradleBuildServices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.gradle
|
|||||||
|
|
||||||
import org.gradle.api.logging.LogLevel
|
import org.gradle.api.logging.LogLevel
|
||||||
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil
|
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleBuildServices
|
||||||
import org.jetbrains.kotlin.gradle.util.createGradleCommand
|
import org.jetbrains.kotlin.gradle.util.createGradleCommand
|
||||||
import org.jetbrains.kotlin.gradle.util.runProcess
|
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
@@ -164,6 +165,16 @@ abstract class BaseGradleIT {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CompiledProject.assertSubstringCount(substring: String, expectedCount: Int) {
|
||||||
|
val actualCount = substring.toRegex().findAll(output).count()
|
||||||
|
assertEquals(expectedCount, actualCount, "Number of occurrences in output for substring '$substring'")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CompiledProject.checkKotlinGradleBuildServices() {
|
||||||
|
assertSubstringCount(KotlinGradleBuildServices.INIT_MESSAGE, expectedCount = 1)
|
||||||
|
assertSubstringCount(KotlinGradleBuildServices.DISPOSE_MESSAGE, expectedCount = 1)
|
||||||
|
}
|
||||||
|
|
||||||
fun CompiledProject.assertNotContains(vararg expected: String): CompiledProject {
|
fun CompiledProject.assertNotContains(vararg expected: String): CompiledProject {
|
||||||
for (str in expected) {
|
for (str in expected) {
|
||||||
assertFalse(output.contains(str.normalize()), "Output should not contain '$str'")
|
assertFalse(output.contains(str.normalize()), "Output should not contain '$str'")
|
||||||
|
|||||||
+4
-3
@@ -1,7 +1,7 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.gradle.api.logging.LogLevel
|
import org.gradle.api.logging.LogLevel
|
||||||
import org.jetbrains.kotlin.gradle.plugin.CleanUpBuildListener
|
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleBuildServices
|
||||||
import org.jetbrains.kotlin.gradle.tasks.USING_EXPERIMENTAL_INCREMENTAL_MESSAGE
|
import org.jetbrains.kotlin.gradle.tasks.USING_EXPERIMENTAL_INCREMENTAL_MESSAGE
|
||||||
import org.jetbrains.kotlin.gradle.util.getFileByName
|
import org.jetbrains.kotlin.gradle.util.getFileByName
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -108,12 +108,12 @@ class KotlinGradleIT: BaseGradleIT() {
|
|||||||
fun testLogLevelForceGC() {
|
fun testLogLevelForceGC() {
|
||||||
val debugProject = Project("simpleProject", GRADLE_VERSION, minLogLevel = LogLevel.DEBUG)
|
val debugProject = Project("simpleProject", GRADLE_VERSION, minLogLevel = LogLevel.DEBUG)
|
||||||
debugProject.build("build") {
|
debugProject.build("build") {
|
||||||
assertContains(CleanUpBuildListener.FORCE_SYSTEM_GC_MESSAGE)
|
assertContains(KotlinGradleBuildServices.FORCE_SYSTEM_GC_MESSAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
val infoProject = Project("simpleProject", GRADLE_VERSION, minLogLevel = LogLevel.INFO)
|
val infoProject = Project("simpleProject", GRADLE_VERSION, minLogLevel = LogLevel.INFO)
|
||||||
infoProject.build("clean", "build") {
|
infoProject.build("clean", "build") {
|
||||||
assertNotContains(CleanUpBuildListener.FORCE_SYSTEM_GC_MESSAGE)
|
assertNotContains(KotlinGradleBuildServices.FORCE_SYSTEM_GC_MESSAGE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +141,7 @@ class KotlinGradleIT: BaseGradleIT() {
|
|||||||
assertSuccessful()
|
assertSuccessful()
|
||||||
assertReportExists("subproject")
|
assertReportExists("subproject")
|
||||||
assertContains(":subproject:compileKotlin", ":subproject:compileTestKotlin")
|
assertContains(":subproject:compileKotlin", ":subproject:compileTestKotlin")
|
||||||
|
checkKotlinGradleBuildServices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user