IR: thread pool in PerformByIrFilePhase

This commit is contained in:
Georgy Bronnikov
2020-11-05 09:59:38 +03:00
parent eae416d739
commit 52b3cb362b
5 changed files with 32 additions and 21 deletions
@@ -115,10 +115,11 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
var doNotClearBindingContext: Boolean by FreezableVar(false) var doNotClearBindingContext: Boolean by FreezableVar(false)
@Argument( @Argument(
value = "-Xir-run-lowerings-in-parallel", value = "-Xir-threads-for-file-lowerings",
description = "When using the IR backend, run lowerings for each file in parallel" description = "When using the IR backend, run lowerings by file in N parallel threads.\n" +
"Default value is 1"
) )
var runLoweringsInParallel: Boolean by FreezableVar(false) var threadsForFileLowerings: String by FreezableVar("1")
@Argument(value = "-Xmodule-path", valueDescription = "<path>", description = "Paths where to find Java 9+ modules") @Argument(value = "-Xmodule-path", valueDescription = "<path>", description = "Paths where to find Java 9+ modules")
var javaModulePath: String? by NullableStringFreezableVar(null) var javaModulePath: String? by NullableStringFreezableVar(null)
@@ -292,7 +292,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) } arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
put(CommonConfigurationKeys.RUN_LOWERINGS_IN_PARALLEL, arguments.runLoweringsInParallel) put(CommonConfigurationKeys.THREADS_FOR_FILE_LOWERINGS, arguments.threadsForFileLowerings.toIntOrNull() ?: 1)
} }
fun CompilerConfiguration.configureKlibPaths(arguments: K2JVMCompilerArguments) { fun CompilerConfiguration.configureKlibPaths(arguments: K2JVMCompilerArguments) {
@@ -52,8 +52,8 @@ object CommonConfigurationKeys {
val USE_FIR_EXTENDED_CHECKERS = CompilerConfigurationKey.create<Boolean>("fir extended checkers") val USE_FIR_EXTENDED_CHECKERS = CompilerConfigurationKey.create<Boolean>("fir extended checkers")
@JvmField @JvmField
val RUN_LOWERINGS_IN_PARALLEL = val THREADS_FOR_FILE_LOWERINGS =
CompilerConfigurationKey.create<Boolean>("When using the IR backend, run lowerings for each file in parallel") CompilerConfigurationKey.create<Int>("When using the IR backend, run lowerings by file in N parallel threads")
} }
var CompilerConfiguration.languageVersionSettings: LanguageVersionSettings var CompilerConfiguration.languageVersionSettings: LanguageVersionSettings
@@ -13,8 +13,9 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import java.lang.IllegalStateException import java.util.concurrent.Executors
import kotlin.concurrent.thread import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
// Phase composition. // Phase composition.
private class CompositePhase<Context : CommonBackendContext, Input, Output>( private class CompositePhase<Context : CommonBackendContext, Input, Output>(
@@ -120,10 +121,13 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
phaserState: PhaserState<IrModuleFragment>, phaserState: PhaserState<IrModuleFragment>,
context: Context, context: Context,
input: IrModuleFragment input: IrModuleFragment
): IrModuleFragment = if (context.configuration.getBoolean(CommonConfigurationKeys.RUN_LOWERINGS_IN_PARALLEL)) ): IrModuleFragment {
invokeParallel(phaseConfig, phaserState, context, input) val nThreads = context.configuration.get(CommonConfigurationKeys.THREADS_FOR_FILE_LOWERINGS) ?: 1
else return if (nThreads > 1)
invokeSequential(phaseConfig, phaserState, context, input) invokeParallel(phaseConfig, phaserState, context, input, nThreads)
else
invokeSequential(phaseConfig, phaserState, context, input)
}
private fun invokeSequential( private fun invokeSequential(
phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment
@@ -144,31 +148,35 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
} }
private fun invokeParallel( private fun invokeParallel(
phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment, nThreads: Int
): IrModuleFragment { ): IrModuleFragment {
if (input.files.isEmpty()) return input if (input.files.isEmpty()) return input
// We can only report one exception through ISE // We can only report one exception through ISE
var thrownFromThread: Throwable? = null val thrownFromThread = AtomicReference<Pair<Throwable, IrFile>?>(null)
// Each thread needs its own copy of phaserState.alreadyDone // Each thread needs its own copy of phaserState.alreadyDone
val filesAndStates = input.files.map { it to phaserState.clone() } val filesAndStates = input.files.map { it to phaserState.clone() }
val threads = filesAndStates.map { (irFile, state) ->
thread { val executor = Executors.newFixedThreadPool(nThreads)
for ((irFile, state) in filesAndStates) {
executor.execute {
try { try {
val filePhaserState = state.changeType<IrModuleFragment, IrFile>() val filePhaserState = state.changeType<IrModuleFragment, IrFile>()
for (phase in lower) { for (phase in lower) {
phase.invoke(phaseConfig, filePhaserState, context, irFile) phase.invoke(phaseConfig, filePhaserState, context, irFile)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
thrownFromThread = e thrownFromThread.set(Pair(e, irFile))
} }
} }
} }
executor.shutdown()
executor.awaitTermination(1, TimeUnit.DAYS) // Wait long enough
threads.forEach { it.join() } thrownFromThread.get()?.let { (e, irFile) ->
CodegenUtil.reportBackendException(e, "IrLowering", irFile.fileEntry.name)
if (thrownFromThread != null) throw IllegalStateException("Exception in file lowering", thrownFromThread) }
// Presumably each thread has run through the same list of phases. // Presumably each thread has run through the same list of phases.
phaserState.alreadyDone.addAll(filesAndStates[0].second.alreadyDone) phaserState.alreadyDone.addAll(filesAndStates[0].second.alreadyDone)
+3 -1
View File
@@ -99,7 +99,6 @@ where advanced options include:
-Xsam-conversions={class|indy} Select code generation scheme for SAM conversions. -Xsam-conversions={class|indy} Select code generation scheme for SAM conversions.
-Xsam-conversions=indy Generate SAM conversions using `invokedynamic` with `LambdaMetafactory.metafactory`. Requires `-jvm-target 1.8` or greater. -Xsam-conversions=indy Generate SAM conversions using `invokedynamic` with `LambdaMetafactory.metafactory`. Requires `-jvm-target 1.8` or greater.
-Xsam-conversions=class Generate SAM conversions as explicit classes -Xsam-conversions=class Generate SAM conversions as explicit classes
-Xir-run-lowerings-in-parallel When using the IR backend, run lowerings for each file in parallel
-Xsanitize-parentheses Transform '(' and ')' in method names to some other character sequence. -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 This mode can BREAK BINARY COMPATIBILITY and is only supposed to be used to workaround
problems with parentheses in identifiers on certain platforms problems with parentheses in identifiers on certain platforms
@@ -123,6 +122,9 @@ where advanced options include:
Suppress deprecation warning about deprecated JVM target versions Suppress deprecation warning about deprecated JVM target versions
-Xsuppress-missing-builtins-error -Xsuppress-missing-builtins-error
Suppress the "cannot access built-in declaration" error (useful with -no-stdlib) Suppress the "cannot access built-in declaration" error (useful with -no-stdlib)
-Xir-threads-for-file-lowerings
When using the IR backend, run lowerings by file in N parallel threads.
Default value is 1
-Xuse-ir Use the IR backend -Xuse-ir Use the IR backend
-Xuse-javac Use javac for Java source and class files analysis -Xuse-javac Use javac for Java source and class files analysis
-Xuse-old-backend Use the old JVM backend -Xuse-old-backend Use the old JVM backend