diff --git a/compiler/fir/modularized-tests/build.gradle.kts b/compiler/fir/modularized-tests/build.gradle.kts
index a36d6f1e0e5..e4659887d9c 100644
--- a/compiler/fir/modularized-tests/build.gradle.kts
+++ b/compiler/fir/modularized-tests/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.cli.common.toBooleanLenient
+
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
@@ -8,13 +10,17 @@ plugins {
id("jps-compatible")
}
+repositories {
+ mavenLocal()
+}
+
dependencies {
Platform[193].orLower {
testCompileOnly(intellijDep()) { includeJars("openapi", rootProject = rootProject) }
}
testCompileOnly(intellijDep()) {
- includeJars("extensions", "idea_rt", "util", "asm-all", "platform-util-ex", rootProject = rootProject)
+ includeJars("extensions", "idea_rt", "util", "asm-all", "platform-util-ex", "jna", rootProject = rootProject)
}
testCompileOnly(intellijPluginDep("java")) { includeJars("java-api") }
diff --git a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/FirResolveModularizedTotalKotlinTest.kt b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/FirResolveModularizedTotalKotlinTest.kt
index 2637bb5350f..f2048c0bd51 100644
--- a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/FirResolveModularizedTotalKotlinTest.kt
+++ b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/FirResolveModularizedTotalKotlinTest.kt
@@ -9,6 +9,8 @@ import com.intellij.openapi.util.Disposer
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.ProjectScope
+import com.sun.jna.Library
+import com.sun.jna.Native
import com.sun.management.HotSpotDiagnosticMXBean
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.cli.common.profiling.AsyncProfilerHelper
@@ -26,10 +28,12 @@ import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.resolve.transformers.createAllCompilerResolveProcessors
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
+import sun.management.ManagementFactoryHelper
import java.io.File
import java.io.FileOutputStream
import java.io.PrintStream
import java.lang.management.ManagementFactory
+import java.text.DecimalFormat
private const val FAIL_FAST = true
@@ -52,6 +56,61 @@ private val ASYNC_PROFILER_START_CMD = System.getProperty("fir.bench.use.async.p
private val ASYNC_PROFILER_STOP_CMD = System.getProperty("fir.bench.use.async.profiler.cmd.stop")
private val PROFILER_SNAPSHOT_DIR = System.getProperty("fir.bench.snapshot.dir") ?: "tmp/snapshots"
+private val REPORT_PASS_EVENTS = System.getProperty("fir.bench.report.pass.events", "false").toBooleanLenient()!!
+
+private interface CLibrary : Library {
+ fun getpid(): Int
+ fun gettid(): Int
+
+ companion object {
+ val INSTANCE = Native.load("c", CLibrary::class.java) as CLibrary
+ }
+}
+
+internal fun isolate() {
+ val isolatedList = System.getenv("DOCKER_ISOLATED_CPUSET")
+ val othersList = System.getenv("DOCKER_CPUSET")
+ println("Trying to set affinity, other: '$othersList', isolated: '$isolatedList'")
+ if (othersList != null) {
+ println("Will move others affinity to '$othersList'")
+ ProcessBuilder().command("bash", "-c", "ps -ae -o pid= | xargs -n 1 taskset -cap $othersList ").inheritIO().start().waitFor()
+ }
+ if (isolatedList != null) {
+ val selfPid = CLibrary.INSTANCE.getpid()
+ val selfTid = CLibrary.INSTANCE.gettid()
+ println("Will pin self affinity, my pid: $selfPid, my tid: $selfTid")
+ ProcessBuilder().command("taskset", "-cp", isolatedList, "$selfTid").inheritIO().start().waitFor()
+ }
+ if (othersList == null && isolatedList == null) {
+ println("No affinity specified")
+ }
+}
+
+class PassEventReporter(private val stream: PrintStream) : AutoCloseable {
+
+ private val decimalFormat = DecimalFormat().apply {
+ this.maximumFractionDigits = 3
+ }
+
+ private fun formatStamp(): String {
+ val uptime = ManagementFactoryHelper.getRuntimeMXBean().uptime
+ return decimalFormat.format(uptime.toDouble() / 1000)
+ }
+
+ fun reportPassStart(num: Int) {
+ stream.println("")
+ }
+
+ fun reportPassEnd(num: Int) {
+ stream.println("")
+ stream.flush()
+ }
+
+ override fun close() {
+ stream.close()
+ }
+}
+
class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
private lateinit var dump: MultiModuleHtmlFirDump
@@ -59,6 +118,8 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
private var bestStatistics: FirResolveBench.TotalStatistics? = null
private var bestPass: Int = 0
+ private var passEventReporter: PassEventReporter? = null
+
private val asyncProfiler = if (ASYNC_PROFILER_LIB != null) {
try {
AsyncProfilerHelper.getInstance(ASYNC_PROFILER_LIB)
@@ -92,7 +153,6 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
val project = environment.project
val ktFiles = environment.getSourceFiles()
-
val scope = GlobalSearchScope.filesScope(project, ktFiles.map { it.virtualFile })
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
val librariesScope = ProjectScope.getLibrariesScope(project)
@@ -107,6 +167,7 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
}
val firProvider = session.firProvider as FirProviderImpl
+
val firFiles = if (USE_LIGHT_TREE) {
val lightTree2Fir = LightTree2Fir(session, firProvider.kotlinScopeProvider, stubMode = false)
@@ -125,9 +186,9 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
bench.buildFiles(builder, ktFiles)
}
- //println("Raw FIR up, files: ${firFiles.size}")
bench.processFiles(firFiles, processors)
+
createMemoryDump(moduleData)
val disambiguatedName = moduleData.disambiguatedName()
@@ -182,6 +243,7 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
override fun beforePass(pass: Int) {
if (DUMP_FIR) dump = MultiModuleHtmlFirDump(File(FIR_HTML_DUMP_PATH))
System.gc()
+ passEventReporter?.reportPassStart(pass)
executeAsyncProfilerCommand(ASYNC_PROFILER_START_CMD, pass)
}
@@ -202,6 +264,8 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
}
executeAsyncProfilerCommand(ASYNC_PROFILER_STOP_CMD, pass)
+
+ passEventReporter?.reportPassEnd(pass)
}
override fun afterAllPasses() {
@@ -237,10 +301,21 @@ class FirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
}
}
+ private fun beforeAllPasses() {
+ isolate()
+
+ if (REPORT_PASS_EVENTS) {
+ passEventReporter =
+ PassEventReporter(PrintStream(FileOutputStream(reportDir().resolve("pass-events-$reportDateStr.log"), true)))
+ }
+ }
+
fun testTotalKotlin() {
+
+ beforeAllPasses()
+
for (i in 0 until PASSES) {
println("Pass $i")
-
bench = FirResolveBench(withProgress = false)
runTestOnce(i)
}
diff --git a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/NonFirResolveModularizedTotalKotlinTest.kt b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/NonFirResolveModularizedTotalKotlinTest.kt
index fce570143f1..00e5739d56c 100644
--- a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/NonFirResolveModularizedTotalKotlinTest.kt
+++ b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/NonFirResolveModularizedTotalKotlinTest.kt
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir
import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
@@ -24,10 +25,13 @@ private val USE_NI = System.getProperty("fir.bench.oldfe.ni", "true") == "true"
class NonFirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
private var totalTime = 0L
private var files = 0
+ private var lines = 0
+ private var measure = FirResolveBench.Measure()
private val times = mutableListOf()
private fun runAnalysis(environment: KotlinCoreEnvironment) {
+ val vmBefore = vmStateSnapshot()
val time = measureNanoTime {
try {
KotlinToJVMBytecodeCompiler.analyze(environment)
@@ -40,9 +44,14 @@ class NonFirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
throw e
}
}
+ val vmAfter = vmStateSnapshot()
files += environment.getSourceFiles().size
+ lines += environment.getSourceFiles().sumBy { StringUtil.countNewLines(it.text) }
totalTime += time
+ measure.time += time
+ measure.vmCounters += vmAfter - vmBefore
+
println("Time is ${time * 1e-6} ms")
}
@@ -102,11 +111,19 @@ class NonFirResolveModularizedTotalKotlinTest : AbstractModularizedTest() {
return ProcessorAction.NEXT
}
-
override fun afterPass(pass: Int) {}
- override fun beforePass(pass: Int) {}
+
+ override fun beforePass(pass: Int) {
+ measure = FirResolveBench.Measure()
+ files = 0
+ lines = 0
+ totalTime = 0
+ }
fun testTotalKotlin() {
+
+ isolate()
+
writeMessageToLog("use_ni: $USE_NI")
for (i in 0 until PASSES) {
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt
index 8aa8f282457..f8d4db1c2bb 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt
@@ -44,7 +44,12 @@ fun checkFirProvidersConsistency(firFiles: List) {
private data class FailureInfo(val transformer: KClass<*>, val throwable: Throwable, val file: String)
data class ErrorTypeReport(val report: String, var count: Int = 0)
-class FirResolveBench(val withProgress: Boolean) {
+abstract class BenchListener {
+ abstract fun before()
+ abstract fun after(stageClass: KClass<*>)
+}
+
+class FirResolveBench(val withProgress: Boolean, val listener: BenchListener? = null) {
data class TotalStatistics(
val unresolvedTypes: Int,
val resolvedTypes: Int,
@@ -81,7 +86,8 @@ class FirResolveBench(val withProgress: Boolean) {
var cpu: Long = 0,
var gcTime: Long = 0,
var gcCollections: Int = 0,
- var files: Int = 0
+ var files: Int = 0,
+ var vmCounters: VMCounters = VMCounters()
)
val timePerTransformer = mutableMapOf, Measure>()
@@ -105,6 +111,7 @@ class FirResolveBench(val withProgress: Boolean) {
builder: RawFirBuilder,
ktFiles: List
): List {
+ listener?.before()
return ktFiles.map { file ->
val before = vmStateSnapshot()
val firFile: FirFile
@@ -118,6 +125,7 @@ class FirResolveBench(val withProgress: Boolean) {
totalLines += StringUtil.countNewLines(file.text)
firFile
}.also {
+ listener?.after(builder::class)
totalTime = timePerTransformer.values.sumByLong { it.time }
}
}
@@ -126,6 +134,7 @@ class FirResolveBench(val withProgress: Boolean) {
builder: LightTree2Fir,
files: List
): List {
+ listener?.before()
return files.map { file ->
val before = vmStateSnapshot()
val firFile: FirFile
@@ -141,6 +150,7 @@ class FirResolveBench(val withProgress: Boolean) {
totalLines += StringUtil.countNewLines(code)
firFile
}.also {
+ listener?.after(builder::class)
totalTime = timePerTransformer.values.sumByLong { it.time }
}
}
@@ -165,6 +175,7 @@ class FirResolveBench(val withProgress: Boolean) {
private fun runStage(processor: FirTransformerBasedResolveProcessor, firFileSequence: Sequence) {
val transformer = processor.transformer
+ listener?.before()
for (firFile in firFileSequence) {
processWithTimeMeasure(
transformer::class,
@@ -180,6 +191,7 @@ class FirResolveBench(val withProgress: Boolean) {
}
}
}
+ listener?.after(transformer::class)
}
private fun runStage(processor: FirGlobalResolveProcessor, firFiles: List) {
@@ -403,6 +415,24 @@ fun FirResolveBench.TotalStatistics.reportErrors(stream: PrintStream) {
}
}
+fun FirResolveBench.TotalStatistics.reportTimings(stream: PrintStream) {
+ printTable(stream) {
+ row {
+ cell("Stage", LEFT)
+ cells("Time", "Time per file", "Files: OK/E/T", "CPU", "User", "GC", "GC count", "L/S")
+ }
+ separator()
+ timePerTransformer.forEach { (transformer, measure) ->
+ printMeasureAsTable(measure, this@reportTimings, transformer)
+ }
+
+ if (timePerTransformer.keys.isNotEmpty()) {
+ separator()
+ printMeasureAsTable(totalMeasure, this@reportTimings, "Total time")
+ }
+ }
+}
+
fun FirResolveBench.TotalStatistics.report(stream: PrintStream, header: String) {
with(stream) {
infix fun Int.percentOf(other: Int): String {
@@ -419,21 +449,7 @@ fun FirResolveBench.TotalStatistics.report(stream: PrintStream, header: String)
println("Erroneously resolved implicit types: $implicitTypes (${implicitTypes percentOf resolvedTypes} of resolved)")
println("Unique error types: $uniqueErrorTypes")
- printTable(stream) {
- row {
- cell("Stage", LEFT)
- cells("Time", "Time per file", "Files: OK/E/T", "CPU", "User", "GC", "GC count", "L/S")
- }
- separator()
- timePerTransformer.forEach { (transformer, measure) ->
- printMeasureAsTable(measure, this@report, transformer)
- }
-
- if (timePerTransformer.keys.isNotEmpty()) {
- separator()
- printMeasureAsTable(totalMeasure, this@report, "Total time")
- }
- }
+ this@report.reportTimings(stream)
}
}
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt
index 5e34da4b055..d7900ca2a28 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt
@@ -17,19 +17,48 @@ data class GCInfo(val name: String, val gcTime: Long, val collections: Long) {
collections = collections - other.collections
)
}
+
+ operator fun plus(other: GCInfo): GCInfo {
+ return this.copy(
+ gcTime = gcTime + other.gcTime,
+ collections = collections + other.collections
+ )
+ }
}
-data class VMCounters(val userTime: Long, val cpuTime: Long, val gcInfo: Map) {
+data class VMCounters(
+ val userTime: Long = 0,
+ val cpuTime: Long = 0,
+ val gcInfo: Map = emptyMap(),
+
+ val safePointTotalTime: Long = 0,
+ val safePointSyncTime: Long = 0,
+ val safePointCount: Long = 0,
+) {
operator fun minus(other: VMCounters): VMCounters {
return VMCounters(
userTime - other.userTime,
cpuTime - other.cpuTime,
- merge(gcInfo, other.gcInfo) { a, b -> a - b }
+ merge(gcInfo, other.gcInfo) { a, b -> a - b },
+ safePointTotalTime - other.safePointTotalTime,
+ safePointSyncTime - other.safePointSyncTime,
+ safePointCount - other.safePointCount
)
}
+
+ operator fun plus(other: VMCounters): VMCounters {
+ return VMCounters(
+ userTime + other.userTime,
+ cpuTime + other.cpuTime,
+ merge(gcInfo, other.gcInfo) { a, b -> a + b },
+ safePointTotalTime + other.safePointTotalTime,
+ safePointSyncTime + other.safePointSyncTime,
+ safePointCount + other.safePointCount
+ )
+ }
}
@@ -50,9 +79,13 @@ object Init {
fun vmStateSnapshot(): VMCounters {
Init
val threadMXBean = ManagementFactoryHelper.getThreadMXBean()
+ val hotspotRuntimeMBean = ManagementFactoryHelper.getHotspotRuntimeMBean()
return VMCounters(
threadMXBean.threadUserTime(), threadMXBean.threadCpuTime(),
- ManagementFactoryHelper.getGarbageCollectorMXBeans().associate { it.name to GCInfo(it.name, it.collectionTime, it.collectionCount) }
+ ManagementFactoryHelper.getGarbageCollectorMXBeans().associate { it.name to GCInfo(it.name, it.collectionTime, it.collectionCount) },
+ hotspotRuntimeMBean.totalSafepointTime,
+ hotspotRuntimeMBean.safepointSyncTime,
+ hotspotRuntimeMBean.safepointCount
)
-}
+}
\ No newline at end of file