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)
@Argument(
value = "-Xir-run-lowerings-in-parallel",
description = "When using the IR backend, run lowerings for each file in parallel"
value = "-Xir-threads-for-file-lowerings",
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")
var javaModulePath: String? by NullableStringFreezableVar(null)
@@ -292,7 +292,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
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) {
@@ -52,8 +52,8 @@ object CommonConfigurationKeys {
val USE_FIR_EXTENDED_CHECKERS = CompilerConfigurationKey.create<Boolean>("fir extended checkers")
@JvmField
val RUN_LOWERINGS_IN_PARALLEL =
CompilerConfigurationKey.create<Boolean>("When using the IR backend, run lowerings for each file in parallel")
val THREADS_FOR_FILE_LOWERINGS =
CompilerConfigurationKey.create<Int>("When using the IR backend, run lowerings by file in N parallel threads")
}
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.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import java.lang.IllegalStateException
import kotlin.concurrent.thread
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
// Phase composition.
private class CompositePhase<Context : CommonBackendContext, Input, Output>(
@@ -120,10 +121,13 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
phaserState: PhaserState<IrModuleFragment>,
context: Context,
input: IrModuleFragment
): IrModuleFragment = if (context.configuration.getBoolean(CommonConfigurationKeys.RUN_LOWERINGS_IN_PARALLEL))
invokeParallel(phaseConfig, phaserState, context, input)
else
invokeSequential(phaseConfig, phaserState, context, input)
): IrModuleFragment {
val nThreads = context.configuration.get(CommonConfigurationKeys.THREADS_FOR_FILE_LOWERINGS) ?: 1
return if (nThreads > 1)
invokeParallel(phaseConfig, phaserState, context, input, nThreads)
else
invokeSequential(phaseConfig, phaserState, context, input)
}
private fun invokeSequential(
phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment
@@ -144,31 +148,35 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
}
private fun invokeParallel(
phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment
phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment, nThreads: Int
): IrModuleFragment {
if (input.files.isEmpty()) return input
// 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
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 {
val filePhaserState = state.changeType<IrModuleFragment, IrFile>()
for (phase in lower) {
phase.invoke(phaseConfig, filePhaserState, context, irFile)
}
} catch (e: Throwable) {
thrownFromThread = e
thrownFromThread.set(Pair(e, irFile))
}
}
}
executor.shutdown()
executor.awaitTermination(1, TimeUnit.DAYS) // Wait long enough
threads.forEach { it.join() }
if (thrownFromThread != null) throw IllegalStateException("Exception in file lowering", thrownFromThread)
thrownFromThread.get()?.let { (e, irFile) ->
CodegenUtil.reportBackendException(e, "IrLowering", irFile.fileEntry.name)
}
// Presumably each thread has run through the same list of phases.
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=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
-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.
This mode can BREAK BINARY COMPATIBILITY and is only supposed to be used to workaround
problems with parentheses in identifiers on certain platforms
@@ -123,6 +122,9 @@ where advanced options include:
Suppress deprecation warning about deprecated JVM target versions
-Xsuppress-missing-builtins-error
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-javac Use javac for Java source and class files analysis
-Xuse-old-backend Use the old JVM backend