Profiling and repeat support for JVM CLI Compiler
This commit is contained in:
+17
@@ -352,6 +352,23 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
var noKotlinNothingValueException: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(
|
||||
value = "-Xprofile",
|
||||
valueDescription = "<profilerPath:command:outputDir>",
|
||||
description = "Debug option: Run compiler with async profiler, save snapshots to outputDir, command is passed to async-profiler on start\n" +
|
||||
"You'll have to provide async-profiler.jar on classpath to use this\n" +
|
||||
"profilerPath is a path to libasyncProfiler.so\n" +
|
||||
"Example: -Xprofile=<PATH_TO_ASYNC_PROFILER>/async-profiler/build/libasyncProfiler.so:event=cpu,interval=1ms,threads,start,framebuf=50000000:<SNAPSHOT_DIR_PATH>"
|
||||
)
|
||||
var profileCompilerCommand: String? by NullableStringFreezableVar(null)
|
||||
|
||||
@Argument(
|
||||
value = "-Xrepeat",
|
||||
valueDescription = "<number>",
|
||||
description = "Debug option: Repeats modules compilation <number> times"
|
||||
)
|
||||
var repeatCompileModules: String? by NullableStringFreezableVar(null)
|
||||
|
||||
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
||||
val result = super.configureAnalysisFlags(collector)
|
||||
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
|
||||
|
||||
@@ -45,6 +45,8 @@ abstract class CLICompiler<A : CommonCompilerArguments> : CLITool<A>() {
|
||||
|
||||
protected abstract val performanceManager: CommonCompilerPerformanceManager
|
||||
|
||||
protected open fun createPerformanceManager(arguments: A): CommonCompilerPerformanceManager = performanceManager
|
||||
|
||||
// Used in CompilerRunnerUtil#invokeExecMethod, in Eclipse plugin (KotlinCLICompiler) and in kotlin-gradle-plugin (GradleCompilerRunner)
|
||||
fun execAndOutputXml(errStream: PrintStream, services: Services, vararg args: String): ExitCode {
|
||||
return exec(errStream, services, MessageRenderer.XML, args)
|
||||
@@ -56,7 +58,7 @@ abstract class CLICompiler<A : CommonCompilerArguments> : CLITool<A>() {
|
||||
}
|
||||
|
||||
public override fun execImpl(messageCollector: MessageCollector, services: Services, arguments: A): ExitCode {
|
||||
val performanceManager = performanceManager
|
||||
val performanceManager = createPerformanceManager(arguments)
|
||||
if (arguments.reportPerf || arguments.dumpPerf != null) {
|
||||
performanceManager.enableCollectingPerformanceStatistics()
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ public class CLIConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<PhaseConfig> PHASE_CONFIG =
|
||||
CompilerConfigurationKey.create("phase configuration");
|
||||
|
||||
public static final CompilerConfigurationKey<Integer> REPEAT_COMPILE_MODULES =
|
||||
CompilerConfigurationKey.create("debug key for profiling, repeats compileModules");
|
||||
|
||||
private CLIConfigurationKeys() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,4 +87,6 @@ abstract class CommonCompilerPerformanceManager(private val presentableName: Str
|
||||
appendln("$presentableName performance report")
|
||||
measurements.map { it.render() }.sorted().forEach { appendln(it) }
|
||||
}.toByteArray()
|
||||
|
||||
open fun notifyRepeat(total: Int, number: Int) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.cli.common.profiling
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
|
||||
interface AsyncProfilerReflected {
|
||||
fun execute(command: String): String
|
||||
fun stop()
|
||||
val version: String
|
||||
}
|
||||
|
||||
|
||||
|
||||
object AsyncProfilerHelper {
|
||||
private val profilerClass = Class.forName("one.profiler.AsyncProfiler")
|
||||
private val getInstanceHandle =
|
||||
MethodHandles.lookup().findStatic(profilerClass, "getInstance", MethodType.methodType(profilerClass, String::class.java))
|
||||
private val executeHandle =
|
||||
MethodHandles.lookup().findVirtual(
|
||||
profilerClass,
|
||||
"execute",
|
||||
MethodType.methodType(String::class.java, String::class.java)
|
||||
)
|
||||
private val stopHandle =
|
||||
MethodHandles.lookup().findVirtual(profilerClass, "stop", MethodType.methodType(Void.TYPE))
|
||||
private val getVersionHandle =
|
||||
MethodHandles.lookup().findVirtual(profilerClass, "getVersion", MethodType.methodType(String::class.java))
|
||||
|
||||
fun getInstance(libPath: String?): AsyncProfilerReflected {
|
||||
val instance = getInstanceHandle.invokeWithArguments(libPath)
|
||||
return object : AsyncProfilerReflected {
|
||||
private val boundExecute = executeHandle.bindTo(instance)
|
||||
private val boundStop = stopHandle.bindTo(instance)
|
||||
private val boundGetVersion = getVersionHandle.bindTo(instance)
|
||||
|
||||
override fun execute(command: String): String {
|
||||
return boundExecute.invokeWithArguments(command) as String
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
boundStop.invokeWithArguments()
|
||||
}
|
||||
|
||||
override val version: String
|
||||
get() = boundGetVersion.invokeWithArguments() as String
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.cli.common.profiling
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.CommonCompilerPerformanceManager
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class ProfilingCompilerPerformanceManager(
|
||||
profilerPath: String,
|
||||
val command: String,
|
||||
val outputDir: File
|
||||
) : CommonCompilerPerformanceManager("Profiling") {
|
||||
private val profiler = AsyncProfilerHelper.getInstance(profilerPath)
|
||||
|
||||
private val runDate = Date()
|
||||
private val formatter = SimpleDateFormat("yyyy-MM-dd__HH-mm")
|
||||
private var active = false
|
||||
|
||||
init {
|
||||
startProfiling()
|
||||
}
|
||||
|
||||
private fun startProfiling() {
|
||||
profiler.execute(command)
|
||||
active = true
|
||||
}
|
||||
|
||||
private fun stopProfiling() {
|
||||
if (active) profiler.stop()
|
||||
active = false
|
||||
}
|
||||
|
||||
private fun restartProfiling() {
|
||||
stopProfiling()
|
||||
startProfiling()
|
||||
}
|
||||
|
||||
private fun dumpProfile(postfix: String) {
|
||||
outputDir.mkdirs()
|
||||
val outputFile = outputDir.resolve("snapshot-${formatter.format(runDate)}-$postfix.collapsed")
|
||||
outputFile.writeText(profiler.execute("collapsed"))
|
||||
active = false
|
||||
}
|
||||
|
||||
override fun notifyRepeat(total: Int, number: Int) {
|
||||
dumpProfile("repeat$number")
|
||||
restartProfiling()
|
||||
}
|
||||
|
||||
override fun notifyCompilationFinished() {
|
||||
dumpProfile("final")
|
||||
stopProfiling()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(profileCompilerArgument: String): ProfilingCompilerPerformanceManager {
|
||||
val (path, command, outputDir) = profileCompilerArgument.split(":", limit = 3)
|
||||
return ProfilingCompilerPerformanceManager(path, command, File(outputDir))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageUtil
|
||||
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleChunk
|
||||
import org.jetbrains.kotlin.cli.common.profiling.ProfilingCompilerPerformanceManager
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.CompileEnvironmentUtil
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
@@ -50,8 +51,6 @@ import java.io.File
|
||||
|
||||
class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
|
||||
override val performanceManager = K2JVMCompilerPerformanceManager()
|
||||
|
||||
override fun doExecute(
|
||||
arguments: K2JVMCompilerArguments,
|
||||
configuration: CompilerConfiguration,
|
||||
@@ -60,6 +59,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
): ExitCode {
|
||||
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
|
||||
configuration.putIfNotNull(CLIConfigurationKeys.REPEAT_COMPILE_MODULES, arguments.repeatCompileModules?.toIntOrNull())
|
||||
configuration.put(CLIConfigurationKeys.PHASE_CONFIG, createPhaseConfig(jvmPhases, arguments, messageCollector))
|
||||
|
||||
if (!configuration.configureJdkHome(arguments)) return COMPILATION_ERROR
|
||||
@@ -219,7 +219,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
|
||||
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
|
||||
performanceManager.notifyCompilerInitialized()
|
||||
configuration[CLIConfigurationKeys.PERF_MANAGER]?.notifyCompilerInitialized()
|
||||
|
||||
return if (messageCollector.hasErrors()) null else environment
|
||||
}
|
||||
@@ -263,6 +263,14 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override val performanceManager: CommonCompilerPerformanceManager
|
||||
get() = error("Unsupported")
|
||||
|
||||
override fun createPerformanceManager(arguments: K2JVMCompilerArguments): CommonCompilerPerformanceManager {
|
||||
val argument = arguments.profileCompilerCommand ?: return K2JVMCompilerPerformanceManager()
|
||||
return ProfilingCompilerPerformanceManager.create(argument)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+27
-5
@@ -162,9 +162,24 @@ object KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun compileModules(environment: KotlinCoreEnvironment, buildFile: File?, chunk: List<Module>): Boolean {
|
||||
internal fun compileModules(
|
||||
environment: KotlinCoreEnvironment,
|
||||
buildFile: File?,
|
||||
chunk: List<Module>,
|
||||
repeat: Boolean = false
|
||||
): Boolean {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
val repeats = environment.configuration[CLIConfigurationKeys.REPEAT_COMPILE_MODULES]
|
||||
if (repeats != null && !repeat) {
|
||||
val performanceManager = environment.configuration[CLIConfigurationKeys.PERF_MANAGER]
|
||||
return (0 until repeats).map {
|
||||
val result = compileModules(environment, buildFile, chunk, repeat = true)
|
||||
performanceManager?.notifyRepeat(repeats, it)
|
||||
result
|
||||
}.last()
|
||||
}
|
||||
|
||||
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project)
|
||||
for (module in chunk) {
|
||||
moduleVisibilityManager.addModule(module)
|
||||
@@ -289,6 +304,8 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
private fun compileModulesUsingFrontendIR(environment: KotlinCoreEnvironment, buildFile: File?, chunk: List<Module>): Boolean {
|
||||
val project = environment.project
|
||||
val performanceManager = environment.configuration.get(CLIConfigurationKeys.PERF_MANAGER)
|
||||
|
||||
Extensions.getArea(project)
|
||||
.getExtensionPoint(PsiElementFinder.EP_NAME)
|
||||
.unregisterExtension(JavaElementFinder::class.java)
|
||||
@@ -297,6 +314,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
val outputs = newLinkedHashMapWithExpectedSize<Module, GenerationState>(chunk.size)
|
||||
for (module in chunk) {
|
||||
performanceManager?.notifyAnalysisStarted()
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
val ktFiles = module.getSourceFiles(environment, localFileSystem, chunk.size > 1, buildFile)
|
||||
@@ -349,6 +367,11 @@ object KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
val debugTargetDescription = "target " + module.getModuleName() + "-" + module.getModuleType() + " "
|
||||
val codeLines = environment.countLinesOfCode(ktFiles)
|
||||
performanceManager?.notifyAnalysisFinished(ktFiles.size, codeLines, debugTargetDescription)
|
||||
|
||||
performanceManager?.notifyGenerationStarted()
|
||||
val signaturer = IdSignatureDescriptor(JvmManglerDesc())
|
||||
|
||||
val (moduleFragment, symbolTable, sourceManager, components) =
|
||||
@@ -379,8 +402,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
val performanceManager = environment.configuration.get(CLIConfigurationKeys.PERF_MANAGER)
|
||||
performanceManager?.notifyGenerationStarted()
|
||||
|
||||
generationState.beforeCompile()
|
||||
codegenFactory.generateModuleInFrontendIRMode(
|
||||
generationState, moduleFragment, symbolTable, sourceManager
|
||||
@@ -391,8 +413,8 @@ object KotlinToJVMBytecodeCompiler {
|
||||
generationState.factory.done()
|
||||
performanceManager?.notifyGenerationFinished(
|
||||
ktFiles.size,
|
||||
environment.countLinesOfCode(ktFiles),
|
||||
additionalDescription = "target " + module.getModuleName() + "-" + module.getModuleType() + " "
|
||||
codeLines,
|
||||
additionalDescription = debugTargetDescription
|
||||
)
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
+6
@@ -74,6 +74,12 @@ where advanced options include:
|
||||
-Xno-param-assertions Don't generate not-null assertions on parameters of methods accessible from Java
|
||||
-Xno-receiver-assertions Don't generate not-null assertion for extension receiver arguments of platform types
|
||||
-Xno-use-ir Do not use the IR backend. Useful for a custom-built compiler where IR backend is enabled by default
|
||||
-Xprofile=<profilerPath:command:outputDir>
|
||||
Debug option: Run compiler with async profiler, save snapshots to outputDir, command is passed to async-profiler on start
|
||||
You'll have to provide async-profiler.jar on classpath to use this
|
||||
profilerPath is a path to libasyncProfiler.so
|
||||
Example: -Xprofile=<PATH_TO_ASYNC_PROFILER>/async-profiler/build/libasyncProfiler.so:event=cpu,interval=1ms,threads,start,framebuf=50000000:<SNAPSHOT_DIR_PATH>
|
||||
-Xrepeat=<number> Debug option: Repeats modules compilation <number> times
|
||||
-Xsanitize-parentheses Transform '(' and ')' in method names to some other character sequence.
|
||||
This mode can BREAK BINARY COMPATIBILITY and is only supposed to be used to workaround
|
||||
problems with parentheses in identifiers on certain platforms
|
||||
|
||||
Reference in New Issue
Block a user