Add full-pipeline modularized tests for old frontend
This commit is contained in:
@@ -21,7 +21,7 @@ class CodeAnalysisMeasurement(private val lines: Int?, val milliseconds: Long) :
|
|||||||
override fun render(): String = formatMeasurement("ANALYZE", milliseconds, lines)
|
override fun render(): String = formatMeasurement("ANALYZE", milliseconds, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
class CodeGenerationMeasurement(private val lines: Int?, private val milliseconds: Long) : PerformanceMeasurement {
|
class CodeGenerationMeasurement(private val lines: Int?, val milliseconds: Long) : PerformanceMeasurement {
|
||||||
override fun render(): String = formatMeasurement("GENERATE", milliseconds, lines)
|
override fun render(): String = formatMeasurement("GENERATE", milliseconds, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+321
@@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fir
|
||||||
|
|
||||||
|
import com.intellij.util.io.delete
|
||||||
|
import org.jetbrains.kotlin.cli.common.*
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||||
|
import org.jetbrains.kotlin.config.Services
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
|
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
abstract class AbstractFullPipelineModularizedTest : AbstractModularizedTest() {
|
||||||
|
|
||||||
|
data class ModuleStatus(val data: ModuleData, val targetInfo: String) {
|
||||||
|
var compilationError: String? = null
|
||||||
|
var jvmInternalError: String? = null
|
||||||
|
var exceptionMessage: String = "NO MESSAGE"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val totalModules = mutableListOf<ModuleStatus>()
|
||||||
|
private val okModules = mutableListOf<ModuleStatus>()
|
||||||
|
private val errorModules = mutableListOf<ModuleStatus>()
|
||||||
|
private val crashedModules = mutableListOf<ModuleStatus>()
|
||||||
|
|
||||||
|
protected data class CumulativeTime(
|
||||||
|
val gcInfo: Map<String, GCInfo>,
|
||||||
|
val components: Map<String, Long>,
|
||||||
|
val files: Int,
|
||||||
|
val lines: Int
|
||||||
|
) {
|
||||||
|
constructor() : this(emptyMap(), emptyMap(), 0, 0)
|
||||||
|
|
||||||
|
operator fun plus(other: CumulativeTime): CumulativeTime {
|
||||||
|
return CumulativeTime(
|
||||||
|
(gcInfo.values + other.gcInfo.values).groupingBy { it.name }.reduce { key, accumulator, element ->
|
||||||
|
GCInfo(key, accumulator.gcTime + element.gcTime, accumulator.collections + element.collections)
|
||||||
|
},
|
||||||
|
(components.toList() + other.components.toList()).groupingBy { (name, _) -> name }.fold(0L) { a, b -> a + b.second },
|
||||||
|
files + other.files,
|
||||||
|
lines + other.lines
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun totalTime() = components.values.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected lateinit var totalPassResult: CumulativeTime
|
||||||
|
|
||||||
|
override fun beforePass(pass: Int) {
|
||||||
|
totalPassResult = CumulativeTime()
|
||||||
|
totalModules.clear()
|
||||||
|
okModules.clear()
|
||||||
|
errorModules.clear()
|
||||||
|
crashedModules.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterPass(pass: Int) {
|
||||||
|
createReport(finalReport = pass == PASSES - 1)
|
||||||
|
require(totalModules.isNotEmpty()) { "No modules were analyzed" }
|
||||||
|
require(okModules.isNotEmpty()) { "All of $totalModules is failed" }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun formatReportTable(stream: PrintStream) {
|
||||||
|
val total = totalPassResult
|
||||||
|
var totalGcTimeMs = 0L
|
||||||
|
var totalGcCount = 0L
|
||||||
|
printTable(stream) {
|
||||||
|
row("Name", "Time", "Count")
|
||||||
|
separator()
|
||||||
|
fun gcRow(name: String, timeMs: Long, count: Long) {
|
||||||
|
row {
|
||||||
|
cell(name, align = LEFT)
|
||||||
|
timeCell(timeMs, inputUnit = TableTimeUnit.MS)
|
||||||
|
cell(count.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (measurement in total.gcInfo.values) {
|
||||||
|
totalGcTimeMs += measurement.gcTime
|
||||||
|
totalGcCount += measurement.collections
|
||||||
|
gcRow(measurement.name, measurement.gcTime, measurement.collections)
|
||||||
|
}
|
||||||
|
separator()
|
||||||
|
gcRow("Total", totalGcTimeMs, totalGcCount)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
printTable(stream) {
|
||||||
|
row("Phase", "Time", "Files", "L/S")
|
||||||
|
separator()
|
||||||
|
|
||||||
|
fun phase(name: String, timeMs: Long, files: Int, lines: Int) {
|
||||||
|
row {
|
||||||
|
cell(name, align = LEFT)
|
||||||
|
timeCell(timeMs, inputUnit = TableTimeUnit.MS)
|
||||||
|
cell(files.toString())
|
||||||
|
linePerSecondCell(lines, timeMs, timeUnit = TableTimeUnit.MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (component in total.components) {
|
||||||
|
phase(component.key, component.value, total.files, total.lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
separator()
|
||||||
|
phase("Total", total.totalTime(), total.files, total.lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureBaseArguments(args: K2JVMCompilerArguments, moduleData: ModuleData, tmp: Path) {
|
||||||
|
args.reportPerf = true
|
||||||
|
args.jvmTarget = "1.8"
|
||||||
|
args.classpath = moduleData.classpath.joinToString(separator = ":") { it.absolutePath }
|
||||||
|
args.javaSourceRoots = moduleData.javaSourceRoots.map { it.absolutePath }.toTypedArray()
|
||||||
|
args.allowKotlinPackage = true
|
||||||
|
args.freeArgs = moduleData.sources.map { it.absolutePath }
|
||||||
|
args.destination = tmp.toAbsolutePath().toFile().toString()
|
||||||
|
args.friendPaths = moduleData.friendDirs.map { it.canonicalPath }.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun configureArguments(args: K2JVMCompilerArguments, moduleData: ModuleData)
|
||||||
|
|
||||||
|
protected open fun handleResult(result: ExitCode, moduleData: ModuleData, collector: TestMessageCollector, targetInfo: String): ProcessorAction {
|
||||||
|
val status = ModuleStatus(moduleData, targetInfo)
|
||||||
|
totalModules += status
|
||||||
|
|
||||||
|
return when (result) {
|
||||||
|
ExitCode.OK -> {
|
||||||
|
okModules += status
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
ExitCode.COMPILATION_ERROR -> {
|
||||||
|
errorModules += status
|
||||||
|
status.compilationError = collector.messages.firstOrNull {
|
||||||
|
it.severity == CompilerMessageSeverity.ERROR
|
||||||
|
}?.message
|
||||||
|
status.jvmInternalError = collector.messages.firstOrNull {
|
||||||
|
it.severity == CompilerMessageSeverity.EXCEPTION
|
||||||
|
}?.message
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
ExitCode.INTERNAL_ERROR -> {
|
||||||
|
crashedModules += status
|
||||||
|
status.exceptionMessage = collector.messages.firstOrNull {
|
||||||
|
it.severity == CompilerMessageSeverity.EXCEPTION
|
||||||
|
}?.message?.split("\n")?.let { exceptionLines ->
|
||||||
|
exceptionLines.lastOrNull { it.startsWith("Caused by: ") } ?: exceptionLines.firstOrNull()
|
||||||
|
} ?: "NO MESSAGE"
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
else -> ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun String.shorten(): String {
|
||||||
|
val split = split("\n")
|
||||||
|
return split.mapIndexedNotNull { index, s ->
|
||||||
|
if (index < 4 || index >= split.size - 6) s else null
|
||||||
|
}.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun formatReport(stream: PrintStream, finalReport: Boolean) {
|
||||||
|
stream.println("TOTAL MODULES: ${totalModules.size}")
|
||||||
|
stream.println("OK MODULES: ${okModules.size}")
|
||||||
|
|
||||||
|
formatReportTable(stream)
|
||||||
|
|
||||||
|
if (finalReport) {
|
||||||
|
with(stream) {
|
||||||
|
println()
|
||||||
|
println("SUCCESSFUL MODULES")
|
||||||
|
println("------------------")
|
||||||
|
println()
|
||||||
|
for (okModule in okModules) {
|
||||||
|
println("${okModule.data.qualifiedName}: ${okModule.targetInfo}")
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
println("COMPILATION ERRORS")
|
||||||
|
println("------------------")
|
||||||
|
println()
|
||||||
|
for (errorModule in errorModules.filter { it.jvmInternalError == null }) {
|
||||||
|
println("${errorModule.data.qualifiedName}: ${errorModule.targetInfo}")
|
||||||
|
println(" 1st error: ${errorModule.compilationError}")
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
println("JVM INTERNAL ERRORS")
|
||||||
|
println("------------------")
|
||||||
|
println()
|
||||||
|
for (errorModule in errorModules.filter { it.jvmInternalError != null }) {
|
||||||
|
println("${errorModule.data.qualifiedName}: ${errorModule.targetInfo}")
|
||||||
|
println(" 1st error: ${errorModule.jvmInternalError?.shorten()}")
|
||||||
|
}
|
||||||
|
val crashedModuleGroups = crashedModules.groupBy { it.exceptionMessage.take(60) }
|
||||||
|
for (modules in crashedModuleGroups.values) {
|
||||||
|
println()
|
||||||
|
println(modules.first().exceptionMessage)
|
||||||
|
println("--------------------------------------------------------")
|
||||||
|
println()
|
||||||
|
for (module in modules) {
|
||||||
|
println("${module.data.qualifiedName}: ${module.targetInfo}")
|
||||||
|
println(" ${module.exceptionMessage}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processModule(moduleData: ModuleData): ProcessorAction {
|
||||||
|
val compiler = K2JVMCompiler()
|
||||||
|
val args = compiler.createArguments()
|
||||||
|
val tmp = Files.createTempDirectory("compile-output")
|
||||||
|
configureBaseArguments(args, moduleData, tmp)
|
||||||
|
configureArguments(args, moduleData)
|
||||||
|
|
||||||
|
val manager = CompilerPerformanceManager()
|
||||||
|
val services = Services.Builder().register(CommonCompilerPerformanceManager::class.java, manager).build()
|
||||||
|
val collector = TestMessageCollector()
|
||||||
|
val result = try {
|
||||||
|
compiler.exec(collector, services, args)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
ExitCode.INTERNAL_ERROR
|
||||||
|
}
|
||||||
|
val resultTime = manager.reportCumulativeTime()
|
||||||
|
PerformanceCounter.resetAllCounters()
|
||||||
|
|
||||||
|
tmp.delete(recursively = true)
|
||||||
|
if (result == ExitCode.OK) {
|
||||||
|
totalPassResult += resultTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return handleResult(result, moduleData, collector, manager.getTargetInfo())
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createReport(finalReport: Boolean) {
|
||||||
|
formatReport(System.out, finalReport)
|
||||||
|
|
||||||
|
PrintStream(
|
||||||
|
FileOutputStream(
|
||||||
|
reportDir().resolve("report-$reportDateStr.log"),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
).use { stream ->
|
||||||
|
formatReport(stream, finalReport)
|
||||||
|
stream.println()
|
||||||
|
stream.println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private inner class CompilerPerformanceManager : CommonCompilerPerformanceManager("Modularized test performance manager") {
|
||||||
|
|
||||||
|
fun reportCumulativeTime(): CumulativeTime {
|
||||||
|
val gcInfo = measurements.filterIsInstance<GarbageCollectionMeasurement>()
|
||||||
|
.associate { it.garbageCollectionKind to GCInfo(it.garbageCollectionKind, it.milliseconds, it.count) }
|
||||||
|
|
||||||
|
val analysisMeasurement = measurements.filterIsInstance<CodeAnalysisMeasurement>().firstOrNull()
|
||||||
|
val initMeasurement = measurements.filterIsInstance<CompilerInitializationMeasurement>().firstOrNull()
|
||||||
|
val irMeasurements = measurements.filterIsInstance<IRMeasurement>()
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
val components = buildMap<String, Long> {
|
||||||
|
put("Init", initMeasurement?.milliseconds ?: 0)
|
||||||
|
put("Analysis", analysisMeasurement?.milliseconds ?: 0)
|
||||||
|
|
||||||
|
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.TRANSLATION }?.milliseconds?.let { put("Translation", it) }
|
||||||
|
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.LOWERING }?.milliseconds?.let { put("Lowering", it) }
|
||||||
|
|
||||||
|
val generationTime =
|
||||||
|
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.GENERATION }?.milliseconds ?:
|
||||||
|
measurements.filterIsInstance<CodeGenerationMeasurement>().firstOrNull()?.milliseconds
|
||||||
|
|
||||||
|
if (generationTime != null) {
|
||||||
|
put("Generation", generationTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CumulativeTime(
|
||||||
|
gcInfo,
|
||||||
|
components,
|
||||||
|
files ?: 0,
|
||||||
|
lines ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class TestMessageCollector : MessageCollector {
|
||||||
|
|
||||||
|
data class Message(val severity: CompilerMessageSeverity, val message: String, val location: CompilerMessageSourceLocation?)
|
||||||
|
|
||||||
|
val messages = arrayListOf<Message>()
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
messages.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
|
||||||
|
messages.add(Message(severity, message, location))
|
||||||
|
if (severity in CompilerMessageSeverity.VERBOSE) return
|
||||||
|
println(MessageRenderer.GRADLE_STYLE.render(severity, message, location))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasErrors(): Boolean = messages.any {
|
||||||
|
it.severity == CompilerMessageSeverity.EXCEPTION || it.severity == CompilerMessageSeverity.ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
-4
@@ -38,10 +38,6 @@ data class ModuleData(
|
|||||||
val sources = rawSources.map { it.fixPath() }
|
val sources = rawSources.map { it.fixPath() }
|
||||||
val javaSourceRoots = rawJavaSourceRoots.map { it.fixPath() }
|
val javaSourceRoots = rawJavaSourceRoots.map { it.fixPath() }
|
||||||
val friendDirs = rawFriendDirs.map { it.fixPath() }
|
val friendDirs = rawFriendDirs.map { it.fixPath() }
|
||||||
lateinit var targetInfo: String
|
|
||||||
var compilationError: String? = null
|
|
||||||
var jvmInternalError: String? = null
|
|
||||||
var exceptionMessage: String = "NO MESSAGE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.fixPath(): File = File(ROOT_PATH_PREFIX, this.removePrefix("/"))
|
private fun String.fixPath(): File = File(ROOT_PATH_PREFIX, this.removePrefix("/"))
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||||
|
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||||
|
|
||||||
|
|
||||||
|
private val USE_BE_IR = System.getProperty("fir.bench.fe1.useIR", "false").toBooleanLenient()!!
|
||||||
|
|
||||||
|
class FE1FullPipelineModularizedTest : AbstractFullPipelineModularizedTest() {
|
||||||
|
override fun configureArguments(args: K2JVMCompilerArguments, moduleData: ModuleData) {
|
||||||
|
args.useIR = USE_BE_IR
|
||||||
|
args.useOldBackend = !USE_BE_IR
|
||||||
|
args.useFir = false
|
||||||
|
args.jvmDefault = "compatibility"
|
||||||
|
args.optIn = arrayOf("kotlin.RequiresOptIn")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testTotalKotlin() {
|
||||||
|
for (i in 0 until PASSES) {
|
||||||
|
println("Pass $i")
|
||||||
|
runTestOnce(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-271
@@ -5,280 +5,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
import com.intellij.util.io.delete
|
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||||
import org.jetbrains.kotlin.cli.common.*
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.*
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
|
||||||
import org.jetbrains.kotlin.config.Services
|
|
||||||
import org.jetbrains.kotlin.fir.TableTimeUnit.MS
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
|
||||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.PrintStream
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
class FullPipelineModularizedTest : AbstractModularizedTest() {
|
class FullPipelineModularizedTest : AbstractFullPipelineModularizedTest() {
|
||||||
override fun beforePass(pass: Int) {
|
|
||||||
totalPassResult = CumulativeTime()
|
|
||||||
totalModules.clear()
|
|
||||||
okModules.clear()
|
|
||||||
errorModules.clear()
|
|
||||||
crashedModules.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class CumulativeTime(
|
override fun configureArguments(args: K2JVMCompilerArguments, moduleData: ModuleData) {
|
||||||
val gcInfo: Map<String, GCInfo>,
|
|
||||||
val init: Long,
|
|
||||||
val analysis: Long,
|
|
||||||
val translation: Long,
|
|
||||||
val lowering: Long,
|
|
||||||
val generation: Long,
|
|
||||||
val files: Int,
|
|
||||||
val lines: Int
|
|
||||||
) {
|
|
||||||
constructor() : this(emptyMap(), 0, 0, 0, 0, 0, 0, 0)
|
|
||||||
|
|
||||||
operator fun plus(other: CumulativeTime): CumulativeTime {
|
|
||||||
return CumulativeTime(
|
|
||||||
(gcInfo.values + other.gcInfo.values).groupingBy { it.name }.reduce { key, accumulator, element ->
|
|
||||||
GCInfo(key, accumulator.gcTime + element.gcTime, accumulator.collections + element.collections)
|
|
||||||
},
|
|
||||||
init + other.init,
|
|
||||||
analysis + other.analysis,
|
|
||||||
translation + other.translation,
|
|
||||||
lowering + other.lowering,
|
|
||||||
generation + other.generation,
|
|
||||||
files + other.files,
|
|
||||||
lines + other.lines
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun totalTime() = init + analysis + translation + lowering + generation
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var totalPassResult: CumulativeTime
|
|
||||||
private val totalModules = mutableListOf<ModuleData>()
|
|
||||||
private val okModules = mutableListOf<ModuleData>()
|
|
||||||
private val errorModules = mutableListOf<ModuleData>()
|
|
||||||
private val crashedModules = mutableListOf<ModuleData>()
|
|
||||||
|
|
||||||
override fun afterPass(pass: Int) {
|
|
||||||
createReport(finalReport = pass == PASSES - 1)
|
|
||||||
require(totalModules.isNotEmpty()) { "No modules were analyzed" }
|
|
||||||
require(okModules.isNotEmpty()) { "All of $totalModules is failed" }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createReport(finalReport: Boolean) {
|
|
||||||
formatReport(System.out, finalReport)
|
|
||||||
|
|
||||||
PrintStream(
|
|
||||||
FileOutputStream(
|
|
||||||
reportDir().resolve("report-$reportDateStr.log"),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
).use { stream ->
|
|
||||||
formatReport(stream, finalReport)
|
|
||||||
stream.println()
|
|
||||||
stream.println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.shorten(): String {
|
|
||||||
val split = split("\n")
|
|
||||||
return split.mapIndexedNotNull { index, s ->
|
|
||||||
if (index < 4 || index >= split.size - 6) s else null
|
|
||||||
}.joinToString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun formatReport(stream: PrintStream, finalReport: Boolean) {
|
|
||||||
stream.println("TOTAL MODULES: ${totalModules.size}")
|
|
||||||
stream.println("OK MODULES: ${okModules.size}")
|
|
||||||
val total = totalPassResult
|
|
||||||
var totalGcTimeMs = 0L
|
|
||||||
var totalGcCount = 0L
|
|
||||||
printTable(stream) {
|
|
||||||
row("Name", "Time", "Count")
|
|
||||||
separator()
|
|
||||||
fun gcRow(name: String, timeMs: Long, count: Long) {
|
|
||||||
row {
|
|
||||||
cell(name, align = LEFT)
|
|
||||||
timeCell(timeMs, inputUnit = MS)
|
|
||||||
cell(count.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (measurement in total.gcInfo.values) {
|
|
||||||
totalGcTimeMs += measurement.gcTime
|
|
||||||
totalGcCount += measurement.collections
|
|
||||||
gcRow(measurement.name, measurement.gcTime, measurement.collections)
|
|
||||||
}
|
|
||||||
separator()
|
|
||||||
gcRow("Total", totalGcTimeMs, totalGcCount)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
printTable(stream) {
|
|
||||||
row("Phase", "Time", "Files", "L/S")
|
|
||||||
separator()
|
|
||||||
|
|
||||||
fun phase(name: String, timeMs: Long, files: Int, lines: Int) {
|
|
||||||
row {
|
|
||||||
cell(name, align = LEFT)
|
|
||||||
timeCell(timeMs, inputUnit = MS)
|
|
||||||
cell(files.toString())
|
|
||||||
linePerSecondCell(lines, timeMs, timeUnit = MS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
phase("Init", total.init, total.files, total.lines)
|
|
||||||
phase("Analysis", total.analysis, total.files, total.lines)
|
|
||||||
phase("Translation", total.translation, total.files, total.lines)
|
|
||||||
phase("Lowering", total.lowering, total.files, total.lines)
|
|
||||||
phase("Generation", total.generation, total.files, total.lines)
|
|
||||||
|
|
||||||
separator()
|
|
||||||
phase("Total", total.totalTime(), total.files, total.lines)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finalReport) {
|
|
||||||
with(stream) {
|
|
||||||
println()
|
|
||||||
println("SUCCESSFUL MODULES")
|
|
||||||
println("------------------")
|
|
||||||
println()
|
|
||||||
for (okModule in okModules) {
|
|
||||||
println("${okModule.qualifiedName}: ${okModule.targetInfo}")
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
println("COMPILATION ERRORS")
|
|
||||||
println("------------------")
|
|
||||||
println()
|
|
||||||
for (errorModule in errorModules.filter { it.jvmInternalError == null }) {
|
|
||||||
println("${errorModule.qualifiedName}: ${errorModule.targetInfo}")
|
|
||||||
println(" 1st error: ${errorModule.compilationError}")
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
println("JVM INTERNAL ERRORS")
|
|
||||||
println("------------------")
|
|
||||||
println()
|
|
||||||
for (errorModule in errorModules.filter { it.jvmInternalError != null }) {
|
|
||||||
println("${errorModule.qualifiedName}: ${errorModule.targetInfo}")
|
|
||||||
println(" 1st error: ${errorModule.jvmInternalError?.shorten()}")
|
|
||||||
}
|
|
||||||
val crashedModuleGroups = crashedModules.groupBy { it.exceptionMessage.take(60) }
|
|
||||||
for (modules in crashedModuleGroups.values) {
|
|
||||||
println()
|
|
||||||
println(modules.first().exceptionMessage)
|
|
||||||
println("--------------------------------------------------------")
|
|
||||||
println()
|
|
||||||
for (module in modules) {
|
|
||||||
println("${module.qualifiedName}: ${module.targetInfo}")
|
|
||||||
println(" ${module.exceptionMessage}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestMessageCollector : MessageCollector {
|
|
||||||
|
|
||||||
data class Message(val severity: CompilerMessageSeverity, val message: String, val location: CompilerMessageSourceLocation?)
|
|
||||||
|
|
||||||
val messages = arrayListOf<Message>()
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
messages.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
|
|
||||||
messages.add(Message(severity, message, location))
|
|
||||||
if (severity in CompilerMessageSeverity.VERBOSE) return
|
|
||||||
println(MessageRenderer.GRADLE_STYLE.render(severity, message, location))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasErrors(): Boolean = messages.any {
|
|
||||||
it.severity == CompilerMessageSeverity.EXCEPTION || it.severity == CompilerMessageSeverity.ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun processModule(moduleData: ModuleData): ProcessorAction {
|
|
||||||
val compiler = K2JVMCompiler()
|
|
||||||
val args = compiler.createArguments()
|
|
||||||
args.reportPerf = true
|
|
||||||
args.jvmTarget = "1.8"
|
|
||||||
args.useFir = true
|
args.useFir = true
|
||||||
args.classpath = moduleData.classpath.joinToString(separator = ":") { it.absolutePath }
|
args.useIR = true
|
||||||
args.javaSourceRoots = moduleData.javaSourceRoots.map { it.absolutePath }.toTypedArray()
|
|
||||||
args.allowKotlinPackage = true
|
|
||||||
args.freeArgs = moduleData.sources.map { it.absolutePath }
|
|
||||||
val tmp = Files.createTempDirectory("compile-output")
|
|
||||||
args.destination = tmp.toAbsolutePath().toFile().toString()
|
|
||||||
args.friendPaths = moduleData.friendDirs.map { it.canonicalPath }.toTypedArray()
|
|
||||||
val manager = CompilerPerformanceManager()
|
|
||||||
val services = Services.Builder().register(CommonCompilerPerformanceManager::class.java, manager).build()
|
|
||||||
val collector = TestMessageCollector()
|
|
||||||
val result = try {
|
|
||||||
compiler.exec(collector, services, args)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
ExitCode.INTERNAL_ERROR
|
|
||||||
}
|
|
||||||
val resultTime = manager.reportCumulativeTime()
|
|
||||||
|
|
||||||
PerformanceCounter.resetAllCounters()
|
|
||||||
|
|
||||||
tmp.delete(recursively = true)
|
|
||||||
totalModules += moduleData
|
|
||||||
moduleData.targetInfo = manager.getTargetInfo()
|
|
||||||
|
|
||||||
return when (result) {
|
|
||||||
ExitCode.OK -> {
|
|
||||||
totalPassResult += resultTime
|
|
||||||
okModules += moduleData
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
ExitCode.COMPILATION_ERROR -> {
|
|
||||||
errorModules += moduleData
|
|
||||||
moduleData.compilationError = collector.messages.firstOrNull {
|
|
||||||
it.severity == CompilerMessageSeverity.ERROR
|
|
||||||
}?.message
|
|
||||||
moduleData.jvmInternalError = collector.messages.firstOrNull {
|
|
||||||
it.severity == CompilerMessageSeverity.EXCEPTION
|
|
||||||
}?.message
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
ExitCode.INTERNAL_ERROR -> {
|
|
||||||
crashedModules += moduleData
|
|
||||||
moduleData.exceptionMessage = collector.messages.firstOrNull {
|
|
||||||
it.severity == CompilerMessageSeverity.EXCEPTION
|
|
||||||
}?.message?.split("\n")?.let { exceptionLines ->
|
|
||||||
exceptionLines.lastOrNull { it.startsWith("Caused by: ") } ?: exceptionLines.firstOrNull()
|
|
||||||
} ?: "NO MESSAGE"
|
|
||||||
ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
else -> ProcessorAction.NEXT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private inner class CompilerPerformanceManager : CommonCompilerPerformanceManager("Modularized test performance manager") {
|
|
||||||
fun reportCumulativeTime(): CumulativeTime {
|
|
||||||
val gcInfo = measurements.filterIsInstance<GarbageCollectionMeasurement>()
|
|
||||||
.associate { it.garbageCollectionKind to GCInfo(it.garbageCollectionKind, it.milliseconds, it.count) }
|
|
||||||
|
|
||||||
val analysisMeasurement = measurements.filterIsInstance<CodeAnalysisMeasurement>().firstOrNull()
|
|
||||||
val initMeasurement = measurements.filterIsInstance<CompilerInitializationMeasurement>().firstOrNull()
|
|
||||||
val irMeasurements = measurements.filterIsInstance<IRMeasurement>()
|
|
||||||
|
|
||||||
return CumulativeTime(
|
|
||||||
gcInfo,
|
|
||||||
initMeasurement?.milliseconds ?: 0,
|
|
||||||
analysisMeasurement?.milliseconds ?: 0,
|
|
||||||
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.TRANSLATION }?.milliseconds ?: 0,
|
|
||||||
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.LOWERING }?.milliseconds ?: 0,
|
|
||||||
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.GENERATION }?.milliseconds ?: 0,
|
|
||||||
files ?: 0,
|
|
||||||
lines ?: 0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testTotalKotlin() {
|
fun testTotalKotlin() {
|
||||||
|
|||||||
Reference in New Issue
Block a user