Report memory usage only when system property is set

This improves performance of Gradle builds with debug logging (--debug),
because System.gc is now forced only when the system property
'kotlin.gradle.test.report.memory.usage' is set.

    #KT-17960 fixed
This commit is contained in:
Alexey Tsvetkov
2017-05-29 00:25:41 +03:00
parent a6a829c272
commit d80a463735
2 changed files with 19 additions and 15 deletions
@@ -81,6 +81,7 @@ class KotlinGradleIT: BaseGradleIT() {
assertFileExists("build/classes/main/META-INF/kotlinProject_main.kotlin_module") assertFileExists("build/classes/main/META-INF/kotlinProject_main.kotlin_module")
assertReportExists() assertReportExists()
assertContains(":compileKotlin", ":compileTestKotlin") assertContains(":compileKotlin", ":compileTestKotlin")
assertNotContains("Forcing System.gc")
} }
project.build("build") { project.build("build") {
@@ -99,9 +100,11 @@ class KotlinGradleIT: BaseGradleIT() {
val userVariantArg = "-Duser.variant=$VARIANT_CONSTANT" val userVariantArg = "-Duser.variant=$VARIANT_CONSTANT"
val MEMORY_MAX_GROWTH_LIMIT_KB = 500 val MEMORY_MAX_GROWTH_LIMIT_KB = 500
val BUILD_COUNT = 15 val BUILD_COUNT = 15
val reportMemoryUsage = "-Dkotlin.gradle.test.report.memory.usage=true"
val options = BaseGradleIT.BuildOptions(withDaemon = true)
fun exitTestDaemon() { fun exitTestDaemon() {
project.build(userVariantArg, "exit", options = BaseGradleIT.BuildOptions(withDaemon = true)) { project.build(userVariantArg, reportMemoryUsage, "exit", options = options) {
assertFailed() assertFailed()
assertContains("The daemon has exited normally or was terminated in response to a user interrupt.") assertContains("The daemon has exited normally or was terminated in response to a user interrupt.")
} }
@@ -110,9 +113,10 @@ class KotlinGradleIT: BaseGradleIT() {
fun buildAndGetMemoryAfterBuild(): Int { fun buildAndGetMemoryAfterBuild(): Int {
var reportedMemory: Int? = null var reportedMemory: Int? = null
project.build(userVariantArg, "clean", "build", options = BaseGradleIT.BuildOptions(withDaemon = true)) { project.build(userVariantArg, reportMemoryUsage, "clean", "build", options = options) {
assertSuccessful() assertSuccessful()
val matches = "\\[PERF\\] Used memory after build: (\\d+) kb \\(difference since build start: ([+-]?\\d+) kb\\)".toRegex().find(output) val matches = "\\[KOTLIN\\]\\[PERF\\] Used memory after build: (\\d+) kb \\(difference since build start: ([+-]?\\d+) kb\\)"
.toRegex().find(output)
assert(matches != null && matches.groups.size == 3) { "Used memory after build is not reported by plugin" } assert(matches != null && matches.groups.size == 3) { "Used memory after build is not reported by plugin" }
reportedMemory = matches!!.groupValues[1].toInt() reportedMemory = matches!!.groupValues[1].toInt()
} }
@@ -37,6 +37,8 @@ internal class KotlinGradleBuildServices private constructor(gradle: Gradle): Bu
companion object { companion object {
private val CLASS_NAME = KotlinGradleBuildServices::class.java.simpleName private val CLASS_NAME = KotlinGradleBuildServices::class.java.simpleName
const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()" const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()"
const val SHOULD_REPORT_MEMORY_USAGE_PROPERTY = "kotlin.gradle.test.report.memory.usage"
val INIT_MESSAGE = "Initialized $CLASS_NAME" val INIT_MESSAGE = "Initialized $CLASS_NAME"
val DISPOSE_MESSAGE = "Disposed $CLASS_NAME" val DISPOSE_MESSAGE = "Disposed $CLASS_NAME"
val ALREADY_INITIALIZED_MESSAGE = "$CLASS_NAME is already initialized" val ALREADY_INITIALIZED_MESSAGE = "$CLASS_NAME is already initialized"
@@ -68,6 +70,7 @@ internal class KotlinGradleBuildServices private constructor(gradle: Gradle): Bu
private var startMemory: Long? = null private var startMemory: Long? = null
private val workingDir = File(gradle.rootProject.buildDir, "kotlin-build").apply { mkdirs() } private val workingDir = File(gradle.rootProject.buildDir, "kotlin-build").apply { mkdirs() }
private val buildCacheStorage = BuildCacheStorage(workingDir) private val buildCacheStorage = BuildCacheStorage(workingDir)
private val shouldReportMemoryUsage = System.getProperty(SHOULD_REPORT_MEMORY_USAGE_PROPERTY) != null
internal val artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider internal val artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider
get() = buildCacheStorage get() = buildCacheStorage
@@ -75,9 +78,7 @@ internal class KotlinGradleBuildServices private constructor(gradle: Gradle): Bu
// There is function with the same name in BuildAdapter, // There is function with the same name in BuildAdapter,
// but it is called before any plugin can attach build listener // but it is called before any plugin can attach build listener
fun buildStarted() { fun buildStarted() {
if (log.isDebugEnabled) { startMemory = getUsedMemoryKb()
startMemory = getUsedMemoryKb()!!
}
} }
override fun buildFinished(result: BuildResult) { override fun buildFinished(result: BuildResult) {
@@ -111,14 +112,13 @@ internal class KotlinGradleBuildServices private constructor(gradle: Gradle): Bu
} }
} }
if (kotlinCompilerCalled) { if (shouldReportMemoryUsage) {
startMemory?.let { startMemoryCopy -> val startMem = startMemory!!
getUsedMemoryKb()?.let { endMemory -> val endMem = getUsedMemoryKb()!!
// 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) // the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
log.kotlinDebug("[PERF] Used memory after build: $endMemory kb (difference since build start: ${"%+d".format(endMemory - startMemoryCopy)} kb)") // but on subsequent runs in the daemon it should be rather small, then the classes are actually reused by the daemon (see above)
} log.lifecycle("[KOTLIN][PERF] Used memory after build: $endMem kb (difference since build start: ${"%+d".format(endMem - startMem)} kb)")
}
} }
closeArtifactDifferenceRegistry() closeArtifactDifferenceRegistry()
@@ -161,7 +161,7 @@ internal class KotlinGradleBuildServices private constructor(gradle: Gradle): Bu
} }
private fun getUsedMemoryKb(): Long? { private fun getUsedMemoryKb(): Long? {
if (!log.isDebugEnabled) return null if (!shouldReportMemoryUsage) return null
log.lifecycle(FORCE_SYSTEM_GC_MESSAGE) log.lifecycle(FORCE_SYSTEM_GC_MESSAGE)
System.gc() System.gc()