Profiling machinery.

This commit is contained in:
Alexander Gorshenev
2016-12-28 18:14:10 +03:00
committed by alexander-gorshenev
parent 3f65eeaeab
commit c15fb6833d
10 changed files with 97 additions and 39 deletions
@@ -1,6 +1,7 @@
package org.jetbrains.kotlin.cli.bc package org.jetbrains.kotlin.cli.bc
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.util.profile
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.CLICompiler
@@ -30,9 +31,6 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
rootDisposable: Disposable rootDisposable: Disposable
): ExitCode { ): ExitCode {
configuration.get(KonanConfigKeys.LIBRARY_FILES)?.forEach{ println(it) }
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, val environment = KotlinCoreEnvironment.createForProduction(rootDisposable,
configuration, Arrays.asList<String>("extensions/common.xml")) configuration, Arrays.asList<String>("extensions/common.xml"))
val project = environment.project val project = environment.project
@@ -101,6 +99,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(VERBOSE_PHASES, put(VERBOSE_PHASES,
arguments.verbosePhases.toNonNullList()) arguments.verbosePhases.toNonNullList())
put(LIST_PHASES, arguments.listPhases) put(LIST_PHASES, arguments.listPhases)
put(TIME_PHASES, arguments.timePhases)
}} }}
} }
@@ -110,7 +109,9 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
companion object { companion object {
@JvmStatic fun main(args: Array<String>) { @JvmStatic fun main(args: Array<String>) {
CLICompiler.doMain(K2Native(), args) profile("Total compiler main()") {
CLICompiler.doMain(K2Native(), args)
}
} }
} }
} }
@@ -62,5 +62,8 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments {
@Argument(value = "list", description = "List all backend phases") @Argument(value = "list", description = "List all backend phases")
public boolean listPhases; public boolean listPhases;
@Argument(value = "time", description = "Report execution time for compiler phases")
public boolean timePhases;
} }
@@ -19,11 +19,9 @@ import org.jetbrains.kotlin.backend.konan.llvm.verifyModule
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import java.lang.System.out import java.lang.System.out
internal final class Context(val config: KonanConfig, internal final class Context(val config: KonanConfig) : KonanBackendContext() {
// TODO: Need to eliminate when deserialization is fixed.
val bindingContext: BindingContext, var moduleDescriptor: ModuleDescriptor? = null
val moduleDescriptor: ModuleDescriptor
) : KonanBackendContext() {
var irModule: IrModuleFragment? = null var irModule: IrModuleFragment? = null
set(module: IrModuleFragment?) { set(module: IrModuleFragment?) {
@@ -53,6 +51,7 @@ internal final class Context(val config: KonanConfig,
lateinit var llvm: Llvm lateinit var llvm: Llvm
var phase: KonanPhase? = null var phase: KonanPhase? = null
var depth: Int = 0
protected fun separator(title: String) { protected fun separator(title: String) {
println("\n\n--- ${title} ----------------------\n") println("\n\n--- ${title} ----------------------\n")
@@ -63,8 +62,9 @@ internal final class Context(val config: KonanConfig,
} }
fun printDescriptors() { fun printDescriptors() {
if (moduleDescriptor == null) return
separator("Descriptors after: ${phase?.description}") separator("Descriptors after: ${phase?.description}")
moduleDescriptor.deepPrint() moduleDescriptor!!.deepPrint()
} }
fun verifyIr() { fun verifyIr() {
@@ -125,6 +125,10 @@ internal final class Context(val config: KonanConfig,
return config.configuration.getBoolean(KonanConfigKeys.PRINT_BITCODE) return config.configuration.getBoolean(KonanConfigKeys.PRINT_BITCODE)
} }
fun shouldProfilePhases(): Boolean {
return config.configuration.getBoolean(KonanConfigKeys.TIME_PHASES)
}
fun log(message: String) { fun log(message: String) {
if (phase?.verbose ?: false) { if (phase?.verbose ?: false) {
println(message) println(message)
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.konan.KonanPlatform import org.jetbrains.kotlin.backend.konan.KonanPlatform
import org.jetbrains.kotlin.backend.konan.util.profile
import org.jetbrains.kotlin.backend.konan.Distribution import org.jetbrains.kotlin.backend.konan.Distribution
import org.jetbrains.kotlin.backend.konan.llvm.loadMetadata import org.jetbrains.kotlin.backend.konan.llvm.loadMetadata
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
@@ -36,14 +37,15 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
for (path in libraries) { for (path in libraries) {
val filePath = File(path) val filePath = File(path)
if (!filePath.exists()) { if (!filePath.exists()) {
error("Path '" + path + "' does not exist"); error("Path '" + path + "' does not exist")
} }
val moduleDescriptor = loadMetadata(configuration, filePath); profile("Loading ${filePath}") {
val moduleDescriptor = loadMetadata(configuration, filePath)
allMetadata.add(moduleDescriptor); allMetadata.add(moduleDescriptor)
}
} }
return allMetadata; return allMetadata
} }
internal val moduleDescriptors: List<ModuleDescriptorImpl> by lazy { internal val moduleDescriptors: List<ModuleDescriptorImpl> by lazy {
@@ -53,6 +53,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("verbose backend phases"); = CompilerConfigurationKey.create("verbose backend phases");
val LIST_PHASES: CompilerConfigurationKey<Boolean> val LIST_PHASES: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("list backend phases"); = CompilerConfigurationKey.create("list backend phases");
val TIME_PHASES: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("time backend phases");
} }
} }
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM
import org.jetbrains.kotlin.backend.konan.util.profile
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
@@ -43,20 +44,22 @@ public fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEn
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector) val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector)
// Build AST and binding info. val context = Context(konanConfig)
analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles(), val phaser = PhaseManager(context)
NativeAnalyzer(environment, environment.getSourceFiles(), konanConfig))
phaser.phase(KonanPhase.FRONTEND) {
// Build AST and binding info.
analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles(),
NativeAnalyzer(environment, environment.getSourceFiles(), konanConfig))
context.moduleDescriptor = analyzerWithCompilerReport.analysisResult.moduleDescriptor
}
val bindingContext = analyzerWithCompilerReport.analysisResult.bindingContext val bindingContext = analyzerWithCompilerReport.analysisResult.bindingContext
val moduleDescriptor = analyzerWithCompilerReport.analysisResult.moduleDescriptor
val context = Context(konanConfig, bindingContext, moduleDescriptor)
val phaser = PhaseManager(context)
phaser.phase(KonanPhase.PSI_TO_IR) { phaser.phase(KonanPhase.PSI_TO_IR) {
// Translate AST to high level IR. // Translate AST to high level IR.
val translator = Psi2IrTranslator(Psi2IrConfiguration(false)) val translator = Psi2IrTranslator(Psi2IrConfiguration(false))
val module = translator.generateModule( moduleDescriptor, val module = translator.generateModule( context.moduleDescriptor!!,
environment.getSourceFiles(), bindingContext) environment.getSourceFiles(), bindingContext)
context.irModule = module context.irModule = module
@@ -1,10 +1,12 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.util.*
enum class KonanPhase(val description: String, enum class KonanPhase(val description: String,
var enabled: Boolean = true, var verbose: Boolean = false) { var enabled: Boolean = true, var verbose: Boolean = false) {
/* */ FRONTEND("Frontend builds AST"),
/* */ PSI_TO_IR("Psi to IR conversion"), /* */ PSI_TO_IR("Psi to IR conversion"),
/* */ BACKEND("All backend"), /* */ BACKEND("All backend"),
/* ... */ LOWER("IR Lowering"), /* ... */ LOWER("IR Lowering"),
@@ -24,19 +26,28 @@ enum class KonanPhase(val description: String,
object KonanPhases { object KonanPhases {
val phases = KonanPhase.values().associate { it.name.toLowerCase() to it } val phases = KonanPhase.values().associate { it.name.toLowerCase() to it }
fun config(config: KonanConfig) { fun known(name: String): String {
val disabled = config.configuration.get(KonanConfigKeys.DISABLED_PHASES) if (phases[name] == null) {
disabled?.forEach { phases[it]!!.enabled = false } error("Unknown phase: $name. Use -list to see the list of phases.")
val enabled = config.configuration.get(KonanConfigKeys.ENABLED_PHASES)
enabled?.forEach { phases[it]!!.enabled = true }
val verbose = config.configuration.get(KonanConfigKeys.VERBOSE_PHASES)
verbose?.forEach { phases[it]!!.verbose = true }
if (config.configuration.get(KonanConfigKeys.NOLINK) ?: false ) {
KonanPhase.LINKER.enabled = false
} }
return name
}
fun config(config: KonanConfig) {
with (config.configuration) { with (KonanConfigKeys) {
val disabled = get(DISABLED_PHASES)
disabled?.forEach { phases[known(it)]!!.enabled = false }
val enabled = get(ENABLED_PHASES)
enabled?.forEach { phases[known(it)]!!.enabled = true }
val verbose = get(VERBOSE_PHASES)
verbose?.forEach { phases[known(it)]!!.verbose = true }
if (get(NOLINK) ?: false ) {
KonanPhase.LINKER.enabled = false
}
}}
} }
fun list() { fun list() {
@@ -57,10 +68,13 @@ internal class PhaseManager(val context: Context) {
val savePhase = context.phase val savePhase = context.phase
context.phase = phase context.phase = phase
context.depth ++
body()
with (context) { with (context) {
profileIf(shouldProfilePhases(), "Phase ${nTabs(depth)} ${phase.name}") {
body()
}
if (shouldVerifyDescriptors()) { if (shouldVerifyDescriptors()) {
verifyDescriptors() verifyDescriptors()
} }
@@ -82,6 +96,7 @@ internal class PhaseManager(val context: Context) {
} }
} }
context.depth --
context.phase = savePhase context.phase = savePhase
} }
} }
@@ -1,6 +1,7 @@
package org.jetbrains.kotlin.backend.konan.descriptors package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.util.nTabs
import org.jetbrains.kotlin.renderer.* import org.jetbrains.kotlin.renderer.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -20,7 +21,7 @@ public class DeepPrintVisitor(worker: DeclarationDescriptorVisitor<Boolean, Int>
public class PrintVisitor: DeclarationDescriptorVisitor<Boolean, Int> { public class PrintVisitor: DeclarationDescriptorVisitor<Boolean, Int> {
fun printDescriptor(descriptor: DeclarationDescriptor, amount: Int): Boolean { fun printDescriptor(descriptor: DeclarationDescriptor, amount: Int): Boolean {
println(String.format("%1$-${(amount+1)*4}s", "") + descriptor.toString()) println("${nTabs(amount)} ${descriptor.toString()}")
return true; return true;
} }
@@ -0,0 +1,22 @@
package org.jetbrains.kotlin.backend.konan.util
import kotlin.system.measureTimeMillis
fun printMillisec(message: String, body: () -> Unit) {
val msec = measureTimeMillis{
body()
}
println("$message: $msec msec")
}
fun profile(message: String, body: () -> Unit) = profileIf(
System.getProperty("konan.profile")?.equals("true") ?: false,
message, body)
fun profileIf(condition: Boolean, message: String, body: () -> Unit) =
if (condition) printMillisec(message, body) else body()
fun nTabs(amount: Int): String {
return String.format("%1$-${(amount+1)*4}s", "")
}
+6 -1
View File
@@ -6,7 +6,6 @@ else
JAVACMD=java JAVACMD=java
fi fi
[ -n "$JAVACMD" ] || JAVACMD=java [ -n "$JAVACMD" ] || JAVACMD=java
[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx256M -Xms32M"
declare -a java_args declare -a java_args
declare -a konan_args declare -a konan_args
@@ -25,6 +24,12 @@ while [ $# -gt 0 ]; do
echo "TODO: need to pass arguments to all the tools somehow." echo "TODO: need to pass arguments to all the tools somehow."
shift shift
;; ;;
-time)
konan_args=("${konan_args[@]}" -time)
java_args=("${java_args[@]}" -agentlib:hprof=cpu=samples -Dkonan.profile=true)
JAVACMD="time $JAVACMD"
shift
;;
*) *)
konan_args=("${konan_args[@]}" "$1") konan_args=("${konan_args[@]}" "$1")
shift shift