diff --git a/README.md b/README.md index 935bc21..169f407 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Apply the plugin in the main `build.gradle(.kts)` configuration file: Using the plugins DSL: ``` groovy plugins { - id("io.github.cdsap.kotlinprocess") version "0.1.3" + id("io.github.cdsap.kotlinprocess") version "0.1.4" } ``` @@ -20,7 +20,7 @@ buildscript { gradlePluginPortal() } dependencies { - classpath("io.github.cdsap:infokotlinprocess:0.1.3") + classpath("io.github.cdsap:infokotlinprocess:0.1.4") } } @@ -31,7 +31,7 @@ apply(plugin = "io.github.cdsap.kotlinprocess") Using the plugins DSL: ``` groovy plugins { - id "io.github.cdsap.kotlinprocess" version "0.1.3" + id "io.github.cdsap.kotlinprocess" version "0.1.4" } ``` @@ -43,7 +43,7 @@ buildscript { gradlePluginPortal() } dependencies { - classpath "io.github.cdsap:infokotlinprocess:0.1.3" + classpath "io.github.cdsap:infokotlinprocess:0.1.4" } } diff --git a/build.gradle.kts b/build.gradle.kts index a027fe9..02391b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "io.github.cdsap" -version = "0.1.3" +version = "0.1.4" java { toolchain { diff --git a/src/main/kotlin/io/github/cdsap/kotlinprocess/ConsolidateProcesses.kt b/src/main/kotlin/io/github/cdsap/kotlinprocess/ConsolidateProcesses.kt index 616fb8c..deb6a7d 100644 --- a/src/main/kotlin/io/github/cdsap/kotlinprocess/ConsolidateProcesses.kt +++ b/src/main/kotlin/io/github/cdsap/kotlinprocess/ConsolidateProcesses.kt @@ -26,6 +26,7 @@ class ConsolidateProcesses { capacity = jStatData[it.key]?.capacity?.toGigsFromKb()!!, gcTime = jStatData[it.key]?.gcTime?.toMinutes()!!, uptime = jStatData[it.key]?.uptime?.toMinutes()!!, + type = jStatData[it.key]?.typeGC!! ) ) } diff --git a/src/main/kotlin/io/github/cdsap/kotlinprocess/model/Process.kt b/src/main/kotlin/io/github/cdsap/kotlinprocess/model/Process.kt index 51f70c1..e668573 100644 --- a/src/main/kotlin/io/github/cdsap/kotlinprocess/model/Process.kt +++ b/src/main/kotlin/io/github/cdsap/kotlinprocess/model/Process.kt @@ -7,5 +7,6 @@ data class Process( val usage: Double, val capacity: Double, val gcTime: Double, - val uptime: Double + val uptime: Double, + val type: String ) diff --git a/src/main/kotlin/io/github/cdsap/kotlinprocess/model/ProcessJstat.kt b/src/main/kotlin/io/github/cdsap/kotlinprocess/model/ProcessJstat.kt index d0c95eb..f32b11d 100644 --- a/src/main/kotlin/io/github/cdsap/kotlinprocess/model/ProcessJstat.kt +++ b/src/main/kotlin/io/github/cdsap/kotlinprocess/model/ProcessJstat.kt @@ -4,5 +4,6 @@ data class ProcessJstat( val usage: Double, val capacity: Double, val gcTime: Double, - val uptime: Double + val uptime: Double, + val typeGC: String ) diff --git a/src/main/kotlin/io/github/cdsap/kotlinprocess/output/BuildScanOutput.kt b/src/main/kotlin/io/github/cdsap/kotlinprocess/output/BuildScanOutput.kt index fe30b09..716c50b 100644 --- a/src/main/kotlin/io/github/cdsap/kotlinprocess/output/BuildScanOutput.kt +++ b/src/main/kotlin/io/github/cdsap/kotlinprocess/output/BuildScanOutput.kt @@ -30,6 +30,10 @@ class BuildScanOutput( "Kotlin-Process-${it.pid}-gcTime", "${it.gcTime} minutes" ) + buildScanExtension.value( + "Kotlin-Process-${it.pid}-gcType", + it.type + ) } } } diff --git a/src/main/kotlin/io/github/cdsap/kotlinprocess/output/ConsoleOutput.kt b/src/main/kotlin/io/github/cdsap/kotlinprocess/output/ConsoleOutput.kt index ce36448..9afe53c 100644 --- a/src/main/kotlin/io/github/cdsap/kotlinprocess/output/ConsoleOutput.kt +++ b/src/main/kotlin/io/github/cdsap/kotlinprocess/output/ConsoleOutput.kt @@ -18,7 +18,7 @@ class ConsoleOutput(private val processes: List) { body { row { cell("Kotlin processes") { - columnSpan = 6 + columnSpan = 7 } } row { @@ -27,6 +27,7 @@ class ConsoleOutput(private val processes: List) { cell("Usage") cell("Capacity") cell("GC Time") + cell("GC Type") cell("Uptime") } @@ -37,6 +38,7 @@ class ConsoleOutput(private val processes: List) { cell("${it.usage} Gb") cell("${it.capacity} Gb") cell("${it.gcTime} minutes") + cell(it.type) cell("${it.uptime} minutes") } } diff --git a/src/main/kotlin/io/github/cdsap/kotlinprocess/parser/JStatData.kt b/src/main/kotlin/io/github/cdsap/kotlinprocess/parser/JStatData.kt index 8c587da..2248eaa 100644 --- a/src/main/kotlin/io/github/cdsap/kotlinprocess/parser/JStatData.kt +++ b/src/main/kotlin/io/github/cdsap/kotlinprocess/parser/JStatData.kt @@ -22,7 +22,9 @@ class JStatData { val rawHeaders = lines[currentIndex].split("\\s+".toRegex()).filter { it != "" } val rawValues = lines[++currentIndex].split("\\s+".toRegex()).filter { it != "" } - val (headers, value) = removeConcurrentGCTimes(rawHeaders, rawValues) + val typeOfCollector = getCollector(rawHeaders, rawValues) + + val (headers, value) = preparePairsByCollector(typeOfCollector, rawHeaders, rawValues) if (headers.size == value.size && checkValuesAraValid(value)) { val process = lines[++currentIndex].split("\\s+".toRegex()) @@ -35,10 +37,11 @@ class JStatData { aux++ } processes[process.first()] = ProcessJstat( - capacity = totalCapacity(jspMapValues), - usage = usage(jspMapValues), + capacity = totalCapacity(typeOfCollector, jspMapValues), + usage = usage(typeOfCollector, jspMapValues), gcTime = gcTime(jspMapValues), - uptime = uptime(jspMapValues) + uptime = uptime(jspMapValues), + typeGC = typeOfCollector.name ) } @@ -46,28 +49,82 @@ class JStatData { return processes } - // When using ParallelGC argument concurrent gc times are not informed, generating an output like - //Timestamp S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT CGC CGCT GCT - // 298.0 22.0 20.0 0.0 0.0 1.0 1.8 1.0 0.9 4.0 8.3 6.0 5.0 4 0.3 4 0.7 - - 1 - // We need to remove the entries CGC and CGCT from the headers and values - private fun removeConcurrentGCTimes( + private fun getCollector(rawHeaders: List, rawValues: List): TypeCollector { + val socHeaderPosition = rawHeaders.indexOf("S0C") + val soc = rawValues[socHeaderPosition] + if (soc == "-") { + return TypeCollector.Z + } else { + val socCGC = rawHeaders.indexOf("CGC") + val cgc = rawValues[socCGC] + if (cgc == "-") { + return TypeCollector.PARALLEL + } else { + return TypeCollector.G1 + } + } + } + + private fun preparePairsByCollector( + typeOfCollector: TypeCollector, rawHeaders: List, rawValues: List ): Pair, List> { - return if (rawHeaders.contains("CGC") && rawHeaders.contains("CGCT") - && rawHeaders.size == rawValues.size ) { - val concurrentGCTime = rawHeaders.indexOf("CGC") - val concurrentGCTimeTotal = rawHeaders.indexOf("CGCT") - - val headers = rawHeaders.toMutableList() - headers.removeAt(concurrentGCTime) - headers.removeAt(concurrentGCTimeTotal - 1) - val value = rawValues.toMutableList() - value.removeAt(concurrentGCTime) - value.removeAt(concurrentGCTimeTotal - 1) - Pair(headers.toList(), value.toList()) - } else { - Pair(rawHeaders, rawValues) + when (typeOfCollector) { + TypeCollector.G1 -> { + return Pair(rawHeaders, rawValues) + } + + TypeCollector.PARALLEL -> { + val concurrentGCTime = rawHeaders.indexOf("CGC") + val concurrentGCTimeTotal = rawHeaders.indexOf("CGCT") + + val headers = rawHeaders.toMutableList() + headers.removeAt(concurrentGCTime) + headers.removeAt(concurrentGCTimeTotal - 1) + val value = rawValues.toMutableList() + value.removeAt(concurrentGCTime) + value.removeAt(concurrentGCTimeTotal - 1) + return Pair(headers.toList(), value.toList()) + } + + TypeCollector.Z -> { + val soc = rawHeaders.indexOf("S0C") + val s1c = rawHeaders.indexOf("S1C") + val sou = rawHeaders.indexOf("S0U") + val s1u = rawHeaders.indexOf("S1U") + val ec = rawHeaders.indexOf("EC") + val eu = rawHeaders.indexOf("EU") + val ygc = rawHeaders.indexOf("YGC") + val ygct = rawHeaders.indexOf("YGCT") + val fgc = rawHeaders.indexOf("FGC") + val fgct = rawHeaders.indexOf("FGCT") + + val headers = rawHeaders.toMutableList() + headers.removeAt(soc) + headers.removeAt(s1c - 1) + headers.removeAt(sou - 2) + headers.removeAt(s1u - 3) + headers.removeAt(ec - 4) + headers.removeAt(eu - 5) + headers.removeAt(ygc - 6) + headers.removeAt(ygct - 7) + headers.removeAt(fgc - 8) + headers.removeAt(fgct - 9) + + val value = rawValues.toMutableList() + value.removeAt(soc) + value.removeAt(s1c - 1) + value.removeAt(sou - 2) + value.removeAt(s1u - 3) + value.removeAt(ec - 4) + value.removeAt(eu - 5) + value.removeAt(ygc - 6) + value.removeAt(ygct - 7) + value.removeAt(fgc - 8) + value.removeAt(fgct - 9) + return Pair(headers.toList(), value.toList()) + } } } @@ -82,12 +139,20 @@ class JStatData { return true } - private fun totalCapacity(jspMapValues: Map): Double { - return jspMapValues["EC"]!! + jspMapValues["OC"]!! + jspMapValues["S0C"]!! + jspMapValues["S1C"]!! + private fun totalCapacity(typeOfCollector: TypeCollector, jspMapValues: Map): Double { + if(typeOfCollector == TypeCollector.Z) { + return jspMapValues["OC"]!! + jspMapValues["MC"]!! + } else { + return jspMapValues["EC"]!! + jspMapValues["OC"]!! + jspMapValues["S0C"]!! + jspMapValues["S1C"]!! + } } - private fun usage(jspMapValues: Map): Double { - return jspMapValues["S0U"]!! + jspMapValues["S1U"]!! + jspMapValues["EU"]!! + jspMapValues["OU"]!! + private fun usage(typeOfCollector: TypeCollector, jspMapValues: Map): Double { + if(typeOfCollector == TypeCollector.Z) { + return jspMapValues["OU"]!! + jspMapValues["MU"]!! + } else { + return jspMapValues["S0U"]!! + jspMapValues["S1U"]!! + jspMapValues["EU"]!! + jspMapValues["OU"]!! + } } private fun gcTime(jspMapValues: Map): Double { @@ -98,3 +163,9 @@ class JStatData { return jspMapValues["Timestamp"]!! } } + +enum class TypeCollector { + G1, + PARALLEL, + Z +} diff --git a/src/test/kotlin/io/github/cdsap/kotlinprocess/InfoKotlinProcessPluginTest.kt b/src/test/kotlin/io/github/cdsap/kotlinprocess/InfoKotlinProcessPluginTest.kt index 7b700e7..08ba4c0 100644 --- a/src/test/kotlin/io/github/cdsap/kotlinprocess/InfoKotlinProcessPluginTest.kt +++ b/src/test/kotlin/io/github/cdsap/kotlinprocess/InfoKotlinProcessPluginTest.kt @@ -3,6 +3,7 @@ package io.github.cdsap.kotlinprocess import junit.framework.TestCase.assertTrue import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner +import org.junit.Assume import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -31,7 +32,7 @@ class InfoKotlinProcessPluginTest { fun testPluginIsCompatibleWithConfigurationCacheWithoutGradleEnterprise() { createBuildGradle() - gradleVersions.forEach { + gradleVersions.forEach { val firstBuild = GradleRunner.create() .withProjectDir(testProjectDir.root) .withArguments("compileKotlin", "--configuration-cache") @@ -52,9 +53,12 @@ class InfoKotlinProcessPluginTest { @Test fun testOutputIsGeneratedWhenPluginIsAppliedWithJvmArgs() { - testProjectDir.newFile("gradle.properties").appendText(""" + testProjectDir.newFile("gradle.properties").writeText( + """ org.gradle.jvmargs=-Xmx256m -Dfile.encoding=UTF-8 - """.trimIndent()) + """.trimIndent() + ) + createBuildGradle() createKotlinClass() @@ -66,10 +70,12 @@ class InfoKotlinProcessPluginTest { @Test fun testOutputIsGeneratedWhenPluginIsAppliedWithJvmArgsAndKotlinJvm() { - testProjectDir.newFile("gradle.properties").appendText(""" + testProjectDir.newFile("gradle.properties").writeText( + """ org.gradle.jvmargs=-Xmx256m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx128m - """.trimIndent()) + """.trimIndent() + ) createBuildGradle() createKotlinClass() @@ -81,10 +87,12 @@ class InfoKotlinProcessPluginTest { @Test fun testOutputIsGeneratedWhenPluginIsAppliedWithJvmArgsAndKotlinGCJvm() { - testProjectDir.newFile("gradle.properties").appendText(""" + testProjectDir.newFile("gradle.properties").writeText( + """ org.gradle.jvmargs=-Xmx256m -Dfile.encoding=UTF-8 kotlin.daemon.jvmargs=-Xmx128m -XX:+UseParallelGC - """.trimIndent()) + """.trimIndent() + ) createBuildGradle() createKotlinClass() @@ -96,30 +104,58 @@ class InfoKotlinProcessPluginTest { @Test fun testOutputIsGeneratedWhenPluginIsAppliedWithJvmGCArgsAndKotlinJvm() { - testProjectDir.newFile("gradle.properties").appendText(""" + testProjectDir.newFile("gradle.properties").writeText( + """ org.gradle.jvmargs=-Xmx256m -XX:+UseParallelGC -Dfile.encoding=UTF-8 - """.trimIndent()) + """.trimIndent() + ) createBuildGradle() createKotlinClass() gradleVersions.forEach { val build = simpleKotlinCompileBuild(it) assertTerminalOutput(build) + assertTrue(build.output.contains("G1")) } } @Test fun testOutputIsGeneratedWhenPluginIsAppliedWithJvmGCArgsAndKotlinGCJvm() { - testProjectDir.newFile("gradle.properties").appendText(""" - org.gradle.jvmargs=-Xmx256m -XX:+UseParallelGC -Dfile.encoding=UTF-8 - kotlin.daemon.jvmargs=-Xmx128m -XX:+UseParallelGC - """.trimIndent()) + testProjectDir.newFile("gradle.properties").writeText( + """ + org.gradle.jvmargs=-Xmx258m -XX:+UseParallelGC -Dfile.encoding=UTF-8 + kotlin.daemon.jvmargs=-Xmx600m -XX:+UseParallelGC + """.trimIndent() + ) createBuildGradle() createKotlinClass() gradleVersions.forEach { val build = simpleKotlinCompileBuild(it) assertTerminalOutput(build) + assertTrue(build.output.contains("PARALLEL")) + } + } + + @Test + fun testOutputIsGeneratedWhenPluginIsAppliedWithJvmGCArgsAndKotlinZ1Jvm() { + Assume.assumeTrue(Runtime.version().feature() >= 15) + + testProjectDir.newFile("gradle.properties").writeText( + """ + org.gradle.jvmargs=-Xmx256m -XX:+UseParallelGC -Dfile.encoding=UTF-8 + kotlin.daemon.jvmargs=-Xmx750m -XX:+UnlockExperimentalVMOptions -XX:+UseZGC + """.trimIndent() + ) + + createBuildGradle17() + createKotlinClass() + + gradleVersions.forEach { + val build = simpleKotlinCompileBuild(it) + assertTerminalOutput(build) + assertTrue(build.output.contains("Z")) + } } @@ -152,6 +188,27 @@ class InfoKotlinProcessPluginTest { repositories { mavenCentral() } + + """.trimIndent() + ) + } + + private fun createBuildGradle17() { + testProjectDir.newFile("build.gradle").appendText( + """ + plugins { + id 'org.jetbrains.kotlin.jvm' version '1.7.21' + id 'application' + id 'io.github.cdsap.kotlinprocess' + } + repositories { + mavenCentral() + } + java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } + } """.trimIndent() ) }