[FIR] Add full compiler pipeline modularized test
Fixup: allow kotlin package
This commit is contained in:
@@ -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 {
|
PerformanceMeasurement {
|
||||||
|
|
||||||
private val speed: Double = lines.toDouble() * 1000 / milliseconds
|
val lps: Double = lines.toDouble() * 1000 / milliseconds
|
||||||
|
|
||||||
override fun render(): String =
|
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 {
|
class GarbageCollectionMeasurement(val garbageCollectionKind: String, val milliseconds: Long, val count: Long) : PerformanceMeasurement {
|
||||||
override fun render(): String = "GC time for $garbageCollectionKind is $milliseconds ms"
|
override fun render(): String = "GC time for $garbageCollectionKind is $milliseconds ms, $count collections"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+188
@@ -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)
|
timeCell(measure.gcTime, inputUnit = TableTimeUnit.MS)
|
||||||
cell(measure.gcCollections.toString())
|
cell(measure.gcCollections.toString())
|
||||||
|
|
||||||
run {
|
linePerSecondCell(statistics.totalLines, time, timeUnit = TableTimeUnit.NS)
|
||||||
val linePerSec = statistics.totalLines / TableTimeUnit.S.convert(time, TableTimeUnit.NS)
|
|
||||||
val df = DecimalFormat().apply {
|
|
||||||
maximumFractionDigits = 1
|
|
||||||
isGroupingUsed = true
|
|
||||||
}
|
|
||||||
cell(df.format(linePerSec))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
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),
|
NS("ns", 1.0, 0),
|
||||||
MICS("mcs", 1e-3, 3),
|
MICS("mcs", 1e-3, 3),
|
||||||
MS("ms", 1e-6, 6),
|
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,
|
time: Long,
|
||||||
outputUnit: TableTimeUnit = TableTimeUnit.MS,
|
outputUnit: TableTimeUnit = TableTimeUnit.MS,
|
||||||
inputUnit: TableTimeUnit = TableTimeUnit.NS,
|
inputUnit: TableTimeUnit = TableTimeUnit.NS,
|
||||||
@@ -144,6 +153,6 @@ internal inline fun RTableContext.RTableRowContext.timeCell(
|
|||||||
cell("${df.format(outputUnit.convert(time, inputUnit))} ${outputUnit.postfixText}")
|
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)
|
RTableContext().apply(body).printout(out)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user