[FIR] Add full compiler pipeline modularized test

Fixup: allow kotlin package
This commit is contained in:
simon.ogorodnik
2020-06-29 23:12:43 +03:00
parent b48dfe9b3d
commit 6bc654ee49
4 changed files with 221 additions and 16 deletions
@@ -20,13 +20,13 @@ class CompilerInitializationMeasurement(private val milliseconds: Long) : Perfor
}
class CodeAnalysisMeasurement(private val files: Int, val lines: Int, private val milliseconds: Long, private val description: String?) :
class CodeAnalysisMeasurement(val files: Int, val lines: Int, val milliseconds: Long, private val description: String?) :
PerformanceMeasurement {
private val speed: Double = lines.toDouble() * 1000 / milliseconds
val lps: Double = lines.toDouble() * 1000 / milliseconds
override fun render(): String =
"ANALYZE: $files files ($lines lines) ${description ?: ""}in $milliseconds ms - ${"%.3f".format(speed)} loc/s"
"ANALYZE: $files files ($lines lines) ${description ?: ""}in $milliseconds ms - ${"%.3f".format(lps)} loc/s"
}
@@ -40,8 +40,8 @@ class CodeGenerationMeasurement(private val files: Int, val lines: Int, private
}
class GarbageCollectionMeasurement(private val garbageCollectionKind: String, private val milliseconds: Long) : PerformanceMeasurement {
override fun render(): String = "GC time for $garbageCollectionKind is $milliseconds ms"
class GarbageCollectionMeasurement(val garbageCollectionKind: String, val milliseconds: Long, val count: Long) : PerformanceMeasurement {
override fun render(): String = "GC time for $garbageCollectionKind is $milliseconds ms, $count collections"
}
@@ -0,0 +1,188 @@
/*
* Copyright 2010-2020 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.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
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.TableTimeUnit.S
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() {
override fun beforePass() {
totalPassResult = CumulativeTime()
totalModules = 0
okModules = 0
}
private data class CumulativeTime(
val gcInfo: Map<String, GCInfo>,
val analysis: Long,
val translation: Long,
val generation: Long,
val files: Int,
val lines: Int
) {
constructor() : this(emptyMap(), 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)
},
analysis + other.analysis,
translation + other.translation,
generation + other.generation,
files + other.files,
lines + other.lines
)
}
fun totalTime() = analysis + translation + generation
}
private lateinit var totalPassResult: CumulativeTime
private var totalModules = 0
private var okModules = 0
override fun afterPass(pass: Int) {
createReport()
}
private fun createReport() {
formatReport(System.out)
PrintStream(
FileOutputStream(
reportDir().resolve("report-$reportDateStr.log"),
true
)
).use { stream ->
formatReport(stream)
stream.println()
stream.println()
}
}
private fun formatReport(stream: PrintStream) {
stream.println("TOTAL MODULES: $totalModules")
stream.println("OK MODULES: $okModules")
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("Analysis", total.analysis, total.files, total.lines)
phase("Translation", total.translation, total.files, total.lines)
phase("Generation", total.generation, total.files, total.lines)
separator()
phase("Total", total.totalTime(), total.files, total.lines)
}
}
override fun processModule(moduleData: ModuleData): ProcessorAction {
val compiler = K2JVMCompiler()
val args = compiler.createArguments()
args.reportPerf = true
args.jvmTarget = "1.8"
args.useFir = true
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 }
val tmp = Files.createTempDirectory("compile-output")
args.destination = tmp.toAbsolutePath().toFile().toString()
val manager = CompilerPerformanceManager()
val services = Services.Builder().register(CommonCompilerPerformanceManager::class.java, manager).build()
val result = try {
compiler.exec(PrintingMessageCollector(System.out, MessageRenderer.GRADLE_STYLE, false), services, args)
} catch (e: Exception) {
e.printStackTrace()
ExitCode.INTERNAL_ERROR
}
val resultTime = manager.reportCumulativeTime()
PerformanceCounter.resetAllCounters()
tmp.delete(recursively = true)
totalModules++
return when (result) {
ExitCode.OK -> {
totalPassResult += resultTime
okModules++
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 irMeasurements = measurements.filterIsInstance<IRMeasurement>()
return CumulativeTime(
gcInfo,
analysisMeasurement?.milliseconds ?: 0,
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.Translation }?.milliseconds ?: 0,
irMeasurements.firstOrNull { it.kind == IRMeasurement.Kind.Generation }?.milliseconds ?: 0,
analysisMeasurement?.files ?: 0,
analysisMeasurement?.lines ?: 0
)
}
}
fun testTotalKotlin() {
for (i in 0 until PASSES) {
println("Pass $i")
runTestOnce(i)
}
}
}
@@ -452,15 +452,23 @@ private fun RTableContext.printMeasureAsTable(measure: FirResolveBench.Measure,
timeCell(measure.gcTime, inputUnit = TableTimeUnit.MS)
cell(measure.gcCollections.toString())
run {
val linePerSec = statistics.totalLines / TableTimeUnit.S.convert(time, TableTimeUnit.NS)
val df = DecimalFormat().apply {
maximumFractionDigits = 1
isGroupingUsed = true
}
cell(df.format(linePerSec))
}
linePerSecondCell(statistics.totalLines, time, timeUnit = TableTimeUnit.NS)
}
}
fun RTableContext.RTableRowContext.linePerSecondCell(linePerSec: Double) {
val df = DecimalFormat().apply {
maximumFractionDigits = 1
isGroupingUsed = true
}
cell(df.format(linePerSec))
}
fun RTableContext.RTableRowContext.linePerSecondCell(lines: Int, time: Long, timeUnit: TableTimeUnit = TableTimeUnit.NS) {
val linePerSec = lines / TableTimeUnit.S.convert(time, from = timeUnit)
linePerSecondCell(linePerSec)
}
class FirRuntimeException(override val message: String, override val cause: Throwable) : RuntimeException(message, cause)
@@ -120,7 +120,7 @@ class RTableContext {
}
internal enum class TableTimeUnit(val postfixText: String, val nsMultiplier: Double, val fractionDigits: Int) {
enum class TableTimeUnit(val postfixText: String, val nsMultiplier: Double, val fractionDigits: Int) {
NS("ns", 1.0, 0),
MICS("mcs", 1e-3, 3),
MS("ms", 1e-6, 6),
@@ -131,7 +131,16 @@ internal enum class TableTimeUnit(val postfixText: String, val nsMultiplier: Dou
}
}
internal inline fun RTableContext.RTableRowContext.timeCell(
inline class TableTimeUnitConversion(val value: Double) {
infix fun to(dest: TableTimeUnit): Double {
return value * dest.nsMultiplier
}
}
infix fun Long.from(from: TableTimeUnit) = TableTimeUnitConversion(this / from.nsMultiplier)
inline fun RTableContext.RTableRowContext.timeCell(
time: Long,
outputUnit: TableTimeUnit = TableTimeUnit.MS,
inputUnit: TableTimeUnit = TableTimeUnit.NS,
@@ -144,6 +153,6 @@ internal inline fun RTableContext.RTableRowContext.timeCell(
cell("${df.format(outputUnit.convert(time, inputUnit))} ${outputUnit.postfixText}")
}
internal inline fun printTable(out: Appendable = System.out, body: RTableContext.() -> Unit) {
inline fun printTable(out: Appendable = System.out, body: RTableContext.() -> Unit) {
RTableContext().apply(body).printout(out)
}