[K/N] Incremental compilation of per-file caches
This commit is contained in:
+9
@@ -167,6 +167,14 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
var autoCacheDir: String? = null
|
var autoCacheDir: String? = null
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
value = INCREMENTAL_CACHE_DIR,
|
||||||
|
valueDescription = "<path>",
|
||||||
|
description = "Path to the directory where to put incremental build caches",
|
||||||
|
delimiter = ""
|
||||||
|
)
|
||||||
|
var incrementalCacheDir: String? = null
|
||||||
|
|
||||||
@Argument(value="-Xcheck-dependencies", deprecatedName = "--check_dependencies", description = "Check dependencies and download the missing ones")
|
@Argument(value="-Xcheck-dependencies", deprecatedName = "--check_dependencies", description = "Check dependencies and download the missing ones")
|
||||||
var checkDependencies: Boolean = false
|
var checkDependencies: Boolean = false
|
||||||
|
|
||||||
@@ -485,6 +493,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
const val INCLUDE_ARG = "-Xinclude"
|
const val INCLUDE_ARG = "-Xinclude"
|
||||||
const val CACHED_LIBRARY = "-Xcached-library"
|
const val CACHED_LIBRARY = "-Xcached-library"
|
||||||
const val ADD_CACHE = "-Xadd-cache"
|
const val ADD_CACHE = "-Xadd-cache"
|
||||||
|
const val INCREMENTAL_CACHE_DIR = "-Xic-cache-dir"
|
||||||
const val SHORT_MODULE_NAME_ARG = "-Xshort-module-name"
|
const val SHORT_MODULE_NAME_ARG = "-Xshort-module-name"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+235
-61
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.FingerprintHash
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.SerializedIrFileFingerprint
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
@@ -13,6 +15,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary
|
|||||||
import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder
|
import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder
|
||||||
import org.jetbrains.kotlin.library.uniqueName
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
|
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
|
||||||
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.library.unresolvedDependencies
|
import org.jetbrains.kotlin.library.unresolvedDependencies
|
||||||
|
|
||||||
internal fun KotlinLibrary.getAllTransitiveDependencies(allLibraries: Map<String, KotlinLibrary>): List<KotlinLibrary> {
|
internal fun KotlinLibrary.getAllTransitiveDependencies(allLibraries: Map<String, KotlinLibrary>): List<KotlinLibrary> {
|
||||||
@@ -32,85 +35,256 @@ internal fun KotlinLibrary.getAllTransitiveDependencies(allLibraries: Map<String
|
|||||||
return allDependencies.toList()
|
return allDependencies.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: deleteRecursively might throw an exception!
|
||||||
class CacheBuilder(
|
class CacheBuilder(
|
||||||
val konanConfig: KonanConfig,
|
val konanConfig: KonanConfig,
|
||||||
val spawnCompilation: (List<String>, CompilerConfiguration.() -> Unit) -> Unit
|
val spawnCompilation: (List<String>, CompilerConfiguration.() -> Unit) -> Unit
|
||||||
) {
|
) {
|
||||||
private val configuration = konanConfig.configuration
|
private val configuration = konanConfig.configuration
|
||||||
private val autoCacheableFrom = configuration.get(KonanConfigKeys.AUTO_CACHEABLE_FROM)!!.map { File(it) }
|
private val autoCacheableFrom = configuration.get(KonanConfigKeys.AUTO_CACHEABLE_FROM)!!.map { File(it) }
|
||||||
|
private val icEnabled = configuration.get(CommonConfigurationKeys.INCREMENTAL_COMPILATION)!!
|
||||||
|
private val includedLibraries = configuration.get(KonanConfigKeys.INCLUDED_LIBRARIES).orEmpty().toSet()
|
||||||
|
private val generateTestRunner = configuration.getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER)
|
||||||
|
|
||||||
fun needToBuild() = konanConfig.isFinalBinary && konanConfig.ignoreCacheReason == null && autoCacheableFrom.isNotEmpty()
|
fun needToBuild() = konanConfig.isFinalBinary && konanConfig.ignoreCacheReason == null && (autoCacheableFrom.isNotEmpty() || icEnabled)
|
||||||
|
|
||||||
|
private val allLibraries by lazy { konanConfig.resolvedLibraries.getFullList(TopologicalLibraryOrder) }
|
||||||
|
private val uniqueNameToLibrary by lazy { allLibraries.associateBy { it.uniqueName } }
|
||||||
|
|
||||||
|
private val caches = mutableMapOf<KotlinLibrary, CachedLibraries.Cache>()
|
||||||
|
private val cacheRootDirectories = mutableMapOf<KotlinLibrary, String>()
|
||||||
|
|
||||||
|
// If libA depends on libB, then dependableLibraries[libB] contains libA.
|
||||||
|
private val dependableLibraries = mutableMapOf<KotlinLibrary, MutableList<KotlinLibrary>>()
|
||||||
|
|
||||||
|
private fun findAllDependable(libraries: List<KotlinLibrary>): Set<KotlinLibrary> {
|
||||||
|
val visited = mutableSetOf<KotlinLibrary>()
|
||||||
|
|
||||||
|
fun dfs(library: KotlinLibrary) {
|
||||||
|
visited.add(library)
|
||||||
|
dependableLibraries[library]?.forEach {
|
||||||
|
if (it !in visited) dfs(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libraries.forEach { if (it !in visited) dfs(it) }
|
||||||
|
return visited
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class LibraryFile(val library: KotlinLibrary, val file: String) {
|
||||||
|
override fun toString() = "${library.uniqueName}|$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val KotlinLibrary.isExternal
|
||||||
|
get() = autoCacheableFrom.any { libraryFile.absolutePath.startsWith(it.absolutePath) }
|
||||||
|
|
||||||
fun build() {
|
fun build() {
|
||||||
val allLibraries = konanConfig.resolvedLibraries.getFullList(TopologicalLibraryOrder)
|
val externalLibrariesToCache = mutableListOf<KotlinLibrary>()
|
||||||
val uniqueNameToLibrary = allLibraries.associateBy { it.uniqueName }
|
val icedLibraries = mutableListOf<KotlinLibrary>()
|
||||||
val caches = mutableMapOf<KotlinLibrary, String>()
|
|
||||||
|
|
||||||
allLibraries.forEach librariesLoop@{ library ->
|
allLibraries.forEach { library ->
|
||||||
konanConfig.cachedLibraries.getLibraryCache(library)?.let {
|
val isDefaultOrExternal = library.isDefault || library.isExternal
|
||||||
caches[library] = it.rootDirectory
|
val cache = konanConfig.cachedLibraries.getLibraryCache(library, !isDefaultOrExternal)
|
||||||
return@librariesLoop
|
cache?.let {
|
||||||
|
caches[library] = it
|
||||||
|
cacheRootDirectories[library] = it.rootDirectory
|
||||||
}
|
}
|
||||||
val libraryPath = library.libraryFile.absolutePath
|
if (isDefaultOrExternal) {
|
||||||
val isLibraryAutoCacheable = library.isDefault || autoCacheableFrom.any { libraryPath.startsWith(it.absolutePath) }
|
if (cache == null) externalLibrariesToCache += library
|
||||||
if (!isLibraryAutoCacheable)
|
} else {
|
||||||
return@librariesLoop
|
icedLibraries += library
|
||||||
|
}
|
||||||
|
library.unresolvedDependencies.forEach {
|
||||||
|
val dependency = uniqueNameToLibrary[it.path]!!
|
||||||
|
dependableLibraries.getOrPut(dependency) { mutableListOf() }.add(library)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val dependencies = library.getAllTransitiveDependencies(uniqueNameToLibrary)
|
externalLibrariesToCache.forEach { buildLibraryCache(it, true, emptyList()) }
|
||||||
val dependencyCaches = dependencies.map {
|
|
||||||
caches[it] ?: run {
|
if (!icEnabled) return
|
||||||
configuration.report(CompilerMessageSeverity.LOGGING,
|
|
||||||
"SKIPPING ${library.libraryName} as some of the dependencies aren't cached")
|
// Every library dependable on one of the changed external libraries needs its cache to be fully rebuilt.
|
||||||
return@librariesLoop
|
val needFullRebuild = findAllDependable(externalLibrariesToCache)
|
||||||
}
|
|
||||||
|
val libraryFilesWithFqNames = mutableMapOf<KotlinLibrary, List<FileWithFqName>>()
|
||||||
|
|
||||||
|
val changedFiles = mutableListOf<LibraryFile>()
|
||||||
|
val removedFiles = mutableListOf<LibraryFile>()
|
||||||
|
val addedFiles = mutableListOf<LibraryFile>()
|
||||||
|
val reversedPerFileDependencies = mutableMapOf<LibraryFile, MutableList<LibraryFile>>()
|
||||||
|
val reversedWholeLibraryDependencies = mutableMapOf<KotlinLibrary, MutableList<LibraryFile>>()
|
||||||
|
for (library in icedLibraries) {
|
||||||
|
if (library in needFullRebuild) continue
|
||||||
|
val cache = caches[library] ?: continue
|
||||||
|
if (cache !is CachedLibraries.Cache.PerFile) {
|
||||||
|
require(library.isInteropLibrary())
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Uncomment after making per-file caches default.
|
val libraryCacheRootDir = File(cache.path)
|
||||||
val makePerFileCache = false//!library.isInteropLibrary()
|
val cachedFiles = libraryCacheRootDir.listFiles.map { it.name }
|
||||||
configuration.report(CompilerMessageSeverity.LOGGING, "CACHING ${library.libraryName}")
|
|
||||||
val libraryCacheDirectory = if (library.isDefault)
|
|
||||||
konanConfig.systemCacheDirectory
|
|
||||||
else
|
|
||||||
CachedLibraries.computeVersionedCacheDirectory(konanConfig.autoCacheDirectory, library, uniqueNameToLibrary)
|
|
||||||
val libraryCache = libraryCacheDirectory.child(
|
|
||||||
if (makePerFileCache)
|
|
||||||
CachedLibraries.getPerFileCachedLibraryName(library)
|
|
||||||
else
|
|
||||||
CachedLibraries.getCachedLibraryName(library)
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
// TODO: Run monolithic cache builds in parallel.
|
|
||||||
libraryCacheDirectory.mkdirs()
|
|
||||||
spawnCompilation(konanConfig.additionalCacheFlags /* TODO: Some way to put them directly to CompilerConfiguration? */) {
|
|
||||||
val libraries = dependencies.filter { !it.isDefault }.map { it.libraryFile.absolutePath }
|
|
||||||
val cachedLibraries = dependencies.zip(dependencyCaches).associate { it.first.libraryFile.absolutePath to it.second }
|
|
||||||
configuration.report(CompilerMessageSeverity.LOGGING, " dependencies:\n " +
|
|
||||||
libraries.joinToString("\n "))
|
|
||||||
configuration.report(CompilerMessageSeverity.LOGGING, " caches used:\n " +
|
|
||||||
cachedLibraries.entries.joinToString("\n ") { "${it.key}: ${it.value}" })
|
|
||||||
configuration.report(CompilerMessageSeverity.LOGGING, " cache dir: " +
|
|
||||||
libraryCacheDirectory.absolutePath)
|
|
||||||
|
|
||||||
setupCommonOptionsForCaches(konanConfig)
|
val actualFilesWithFqNames = library.getFilesWithFqNames()
|
||||||
put(KonanConfigKeys.PRODUCE, CompilerOutputKind.STATIC_CACHE)
|
libraryFilesWithFqNames[library] = actualFilesWithFqNames
|
||||||
put(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE, libraryPath)
|
val actualFiles = actualFilesWithFqNames.withIndex()
|
||||||
put(KonanConfigKeys.NODEFAULTLIBS, true)
|
.associate { CacheSupport.cacheFileId(it.value.fqName, it.value.filePath) to it.index }
|
||||||
put(KonanConfigKeys.NOENDORSEDLIBS, true)
|
.toMutableMap()
|
||||||
put(KonanConfigKeys.NOSTDLIB, true)
|
|
||||||
put(KonanConfigKeys.LIBRARY_FILES, libraries)
|
for (cachedFile in cachedFiles) {
|
||||||
put(KonanConfigKeys.CACHED_LIBRARIES, cachedLibraries)
|
val libraryFile = LibraryFile(library, cachedFile)
|
||||||
put(KonanConfigKeys.CACHE_DIRECTORIES, listOf(libraryCacheDirectory.absolutePath))
|
val fileIndex = actualFiles[cachedFile]
|
||||||
put(KonanConfigKeys.MAKE_PER_FILE_CACHE, makePerFileCache)
|
if (fileIndex == null) {
|
||||||
|
removedFiles.add(libraryFile)
|
||||||
|
} else {
|
||||||
|
actualFiles.remove(cachedFile)
|
||||||
|
val actualContentHash = SerializedIrFileFingerprint(library, fileIndex).fileFingerprint
|
||||||
|
val previousContentHash = FingerprintHash.fromByteArray(cache.getFileHash(cachedFile))
|
||||||
|
if (previousContentHash != actualContentHash)
|
||||||
|
changedFiles.add(libraryFile)
|
||||||
|
|
||||||
|
val dependencies = cache.getFileDependencies(cachedFile)
|
||||||
|
for (dependency in dependencies) {
|
||||||
|
val dependentLibrary = uniqueNameToLibrary[dependency.libName]
|
||||||
|
?: error("Unknown dependent library ${dependency.libName}")
|
||||||
|
when (val kind = dependency.kind) {
|
||||||
|
is DependenciesTracker.DependencyKind.WholeModule ->
|
||||||
|
reversedWholeLibraryDependencies.getOrPut(dependentLibrary) { mutableListOf() }.add(libraryFile)
|
||||||
|
is DependenciesTracker.DependencyKind.CertainFiles ->
|
||||||
|
kind.files.forEach {
|
||||||
|
reversedPerFileDependencies.getOrPut(LibraryFile(dependentLibrary, it)) { mutableListOf() }.add(libraryFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
caches[library] = libraryCache.absolutePath
|
}
|
||||||
} catch (t: Throwable) {
|
for (newFile in actualFiles.keys)
|
||||||
configuration.report(CompilerMessageSeverity.LOGGING, "${t.message}\n${t.stackTraceToString()}")
|
addedFiles.add(LibraryFile(library, newFile))
|
||||||
configuration.report(CompilerMessageSeverity.WARNING,
|
}
|
||||||
"Failed to build cache: ${t.message}\n${t.stackTraceToString()}\n" +
|
|
||||||
"Falling back to not use cache for ${library.libraryName}")
|
|
||||||
|
|
||||||
libraryCache.deleteRecursively()
|
configuration.report(CompilerMessageSeverity.LOGGING, "IC analysis results")
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " CACHED:")
|
||||||
|
icedLibraries.filter { caches[it] != null }.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " ${it.libraryName}") }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " CLEAN BUILD:")
|
||||||
|
icedLibraries.filter { caches[it] == null }.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " ${it.libraryName}") }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " FULL REBUILD:")
|
||||||
|
icedLibraries.filter { it in needFullRebuild }.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " ${it.libraryName}") }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " ADDED FILES:")
|
||||||
|
addedFiles.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " $it") }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " REMOVED FILES:")
|
||||||
|
removedFiles.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " $it") }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " CHANGED FILES:")
|
||||||
|
changedFiles.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " $it") }
|
||||||
|
|
||||||
|
val dirtyFiles = mutableSetOf<LibraryFile>()
|
||||||
|
|
||||||
|
fun dfs(libraryFile: LibraryFile) {
|
||||||
|
dirtyFiles += libraryFile
|
||||||
|
reversedPerFileDependencies[libraryFile]?.forEach {
|
||||||
|
if (it !in dirtyFiles) dfs(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removedFiles.forEach {
|
||||||
|
if (it !in dirtyFiles) dfs(it)
|
||||||
|
}
|
||||||
|
changedFiles.forEach {
|
||||||
|
if (it !in dirtyFiles) dfs(it)
|
||||||
|
}
|
||||||
|
dirtyFiles.addAll(addedFiles)
|
||||||
|
|
||||||
|
removedFiles.forEach {
|
||||||
|
dirtyFiles.remove(it)
|
||||||
|
File(caches[it.library]!!.rootDirectory).child(it.file).deleteRecursively()
|
||||||
|
}
|
||||||
|
|
||||||
|
val groupedDirtyFiles = dirtyFiles.groupBy { it.library }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " DIRTY FILES:")
|
||||||
|
groupedDirtyFiles.values.flatten().forEach {
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " $it")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (library in icedLibraries) {
|
||||||
|
val filesToCache = groupedDirtyFiles[library]?.let { libraryFiles ->
|
||||||
|
val filesWithFqNames = libraryFilesWithFqNames[library]!!.associateBy {
|
||||||
|
CacheSupport.cacheFileId(it.fqName, it.filePath)
|
||||||
|
}
|
||||||
|
libraryFiles.map { filesWithFqNames[it.file]!!.filePath }
|
||||||
|
}.orEmpty()
|
||||||
|
|
||||||
|
when {
|
||||||
|
library in needFullRebuild -> buildLibraryCache(library, false, emptyList())
|
||||||
|
caches[library] == null || filesToCache.isNotEmpty() -> buildLibraryCache(library, false, filesToCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildLibraryCache(library: KotlinLibrary, isExternal: Boolean, filesToCache: List<String>) {
|
||||||
|
val dependencies = library.getAllTransitiveDependencies(uniqueNameToLibrary)
|
||||||
|
val dependencyCaches = dependencies.map {
|
||||||
|
cacheRootDirectories[it] ?: run {
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING,
|
||||||
|
"SKIPPING ${library.libraryName} as some of the dependencies aren't cached")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, "CACHING ${library.libraryName}")
|
||||||
|
filesToCache.forEach { configuration.report(CompilerMessageSeverity.LOGGING, " $it") }
|
||||||
|
|
||||||
|
// Produce monolithic caches for external libraries for now.
|
||||||
|
val makePerFileCache = !isExternal && !library.isInteropLibrary()
|
||||||
|
|
||||||
|
val libraryCacheDirectory = when {
|
||||||
|
library.isDefault -> konanConfig.systemCacheDirectory
|
||||||
|
isExternal -> CachedLibraries.computeVersionedCacheDirectory(konanConfig.autoCacheDirectory, library, uniqueNameToLibrary)
|
||||||
|
else -> konanConfig.incrementalCacheDirectory!!
|
||||||
|
}
|
||||||
|
val libraryCache = libraryCacheDirectory.child(
|
||||||
|
if (makePerFileCache)
|
||||||
|
CachedLibraries.getPerFileCachedLibraryName(library)
|
||||||
|
else
|
||||||
|
CachedLibraries.getCachedLibraryName(library)
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
// TODO: Run monolithic cache builds in parallel.
|
||||||
|
libraryCacheDirectory.mkdirs()
|
||||||
|
spawnCompilation(konanConfig.additionalCacheFlags /* TODO: Some way to put them directly to CompilerConfiguration? */) {
|
||||||
|
val libraryPath = library.libraryFile.absolutePath
|
||||||
|
val libraries = dependencies.filter { !it.isDefault }.map { it.libraryFile.absolutePath }
|
||||||
|
val cachedLibraries = dependencies.zip(dependencyCaches).associate { it.first.libraryFile.absolutePath to it.second }
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " dependencies:\n " +
|
||||||
|
libraries.joinToString("\n "))
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " caches used:\n " +
|
||||||
|
cachedLibraries.entries.joinToString("\n ") { "${it.key}: ${it.value}" })
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, " cache dir: " +
|
||||||
|
libraryCacheDirectory.absolutePath)
|
||||||
|
|
||||||
|
setupCommonOptionsForCaches(konanConfig)
|
||||||
|
put(KonanConfigKeys.PRODUCE, CompilerOutputKind.STATIC_CACHE)
|
||||||
|
put(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE, libraryPath)
|
||||||
|
put(KonanConfigKeys.NODEFAULTLIBS, true)
|
||||||
|
put(KonanConfigKeys.NOENDORSEDLIBS, true)
|
||||||
|
put(KonanConfigKeys.NOSTDLIB, true)
|
||||||
|
put(KonanConfigKeys.LIBRARY_FILES, libraries)
|
||||||
|
if (generateTestRunner != TestRunnerKind.NONE && libraryPath in includedLibraries) {
|
||||||
|
put(KonanConfigKeys.GENERATE_TEST_RUNNER, generateTestRunner)
|
||||||
|
put(KonanConfigKeys.INCLUDED_LIBRARIES, listOf(libraryPath))
|
||||||
|
}
|
||||||
|
put(KonanConfigKeys.CACHED_LIBRARIES, cachedLibraries)
|
||||||
|
put(KonanConfigKeys.CACHE_DIRECTORIES, listOf(libraryCacheDirectory.absolutePath))
|
||||||
|
put(KonanConfigKeys.MAKE_PER_FILE_CACHE, makePerFileCache)
|
||||||
|
if (filesToCache.isNotEmpty())
|
||||||
|
put(KonanConfigKeys.FILES_TO_CACHE, filesToCache)
|
||||||
|
}
|
||||||
|
cacheRootDirectories[library] = libraryCache.absolutePath
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
configuration.report(CompilerMessageSeverity.LOGGING, "${t.message}\n${t.stackTraceToString()}")
|
||||||
|
configuration.report(CompilerMessageSeverity.WARNING,
|
||||||
|
"Failed to build cache: ${t.message}\n${t.stackTraceToString()}\n" +
|
||||||
|
"Falling back to not use cache for ${library.libraryName}")
|
||||||
|
|
||||||
|
libraryCache.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+5
-2
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan
|
|||||||
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.EagerInitializedPropertySerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.EagerInitializedPropertySerializer
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
|
||||||
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
|
|
||||||
internal class CacheStorage(private val generationState: NativeGenerationState) {
|
internal class CacheStorage(private val generationState: NativeGenerationState) {
|
||||||
private val outputFiles = generationState.outputFiles
|
private val outputFiles = generationState.outputFiles
|
||||||
@@ -16,8 +17,10 @@ internal class CacheStorage(private val generationState: NativeGenerationState)
|
|||||||
fun renameOutput(outputFiles: OutputFiles) {
|
fun renameOutput(outputFiles: OutputFiles) {
|
||||||
// For caches the output file is a directory. It might be created by someone else,
|
// For caches the output file is a directory. It might be created by someone else,
|
||||||
// we have to delete it in order for the next renaming operation to succeed.
|
// we have to delete it in order for the next renaming operation to succeed.
|
||||||
// TODO: what if the directory is not empty?
|
val tempDirectoryForRemoval = File(outputFiles.mainFileName + "-to-remove")
|
||||||
java.io.File(outputFiles.mainFileName).delete()
|
if (outputFiles.mainFile.exists && !outputFiles.mainFile.renameTo(tempDirectoryForRemoval))
|
||||||
|
return
|
||||||
|
tempDirectoryForRemoval.deleteRecursively()
|
||||||
if (!outputFiles.tempCacheDirectory!!.renameTo(outputFiles.mainFile))
|
if (!outputFiles.tempCacheDirectory!!.renameTo(outputFiles.mainFile))
|
||||||
outputFiles.tempCacheDirectory.deleteRecursively()
|
outputFiles.tempCacheDirectory.deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -80,10 +80,11 @@ class PartialCacheInfo(val klib: KotlinLibrary, val strategy: CacheDeserializati
|
|||||||
|
|
||||||
class CacheSupport(
|
class CacheSupport(
|
||||||
private val configuration: CompilerConfiguration,
|
private val configuration: CompilerConfiguration,
|
||||||
resolvedLibraries: KotlinLibraryResolveResult,
|
private val resolvedLibraries: KotlinLibraryResolveResult,
|
||||||
ignoreCacheReason: String?,
|
ignoreCacheReason: String?,
|
||||||
systemCacheDirectory: File,
|
systemCacheDirectory: File,
|
||||||
autoCacheDirectory: File,
|
autoCacheDirectory: File,
|
||||||
|
incrementalCacheDirectory: File?,
|
||||||
target: KonanTarget,
|
target: KonanTarget,
|
||||||
val produce: CompilerOutputKind
|
val produce: CompilerOutputKind
|
||||||
) {
|
) {
|
||||||
@@ -103,7 +104,9 @@ class CacheSupport(
|
|||||||
add(File(it).takeIf { it.isDirectory }
|
add(File(it).takeIf { it.isDirectory }
|
||||||
?: configuration.reportCompilationError("cache directory $it is not found or is not a directory"))
|
?: configuration.reportCompilationError("cache directory $it is not found or is not a directory"))
|
||||||
}
|
}
|
||||||
systemCacheDirectory.takeIf { autoCacheableFrom.isNotEmpty() }?.let { add(it) }
|
systemCacheDirectory.takeIf { autoCacheableFrom.isNotEmpty() || incrementalCacheDirectory != null }?.let { add(it) }
|
||||||
|
autoCacheDirectory.takeIf { autoCacheableFrom.isNotEmpty() }?.let { add(it) }
|
||||||
|
incrementalCacheDirectory?.let { add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun tryGetImplicitOutput(cacheDeserializationStrategy: CacheDeserializationStrategy?): String? {
|
internal fun tryGetImplicitOutput(cacheDeserializationStrategy: CacheDeserializationStrategy?): String? {
|
||||||
@@ -178,10 +181,11 @@ class CacheSupport(
|
|||||||
configuration.get(KonanConfigKeys.PRE_LINK_CACHES, false)
|
configuration.get(KonanConfigKeys.PRE_LINK_CACHES, false)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun cacheFileId(fqName: String, filePath: String) = "${if (fqName == "") "ROOT" else fqName}.${filePath.hashCode().toString(Character.MAX_RADIX)}"
|
fun cacheFileId(fqName: String, filePath: String) =
|
||||||
|
"${if (fqName == "") "ROOT" else fqName}.${filePath.hashCode().toString(Character.MAX_RADIX)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
fun checkConsistency() {
|
||||||
// Ensure dependencies of every cached library are cached too:
|
// Ensure dependencies of every cached library are cached too:
|
||||||
resolvedLibraries.getFullList { libraries ->
|
resolvedLibraries.getFullList { libraries ->
|
||||||
libraries.map { library ->
|
libraries.map { library ->
|
||||||
|
|||||||
+12
-10
@@ -84,11 +84,13 @@ class CachedLibraries(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PerFile(target: KonanTarget, kind: Kind, path: String, private val fileDirs: List<File>)
|
class PerFile(target: KonanTarget, kind: Kind, path: String, fileDirs: List<File>, val complete: Boolean)
|
||||||
: Cache(target, kind, path, File(path).absolutePath)
|
: Cache(target, kind, path, File(path).absolutePath)
|
||||||
{
|
{
|
||||||
|
private val existingFileDirs = if (complete) fileDirs else fileDirs.filter { it.exists }
|
||||||
|
|
||||||
private val perFileBitcodeDependencies by lazy {
|
private val perFileBitcodeDependencies by lazy {
|
||||||
fileDirs.associate {
|
existingFileDirs.associate {
|
||||||
val data = it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(BITCODE_DEPENDENCIES_FILE_NAME).readStrings()
|
val data = it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(BITCODE_DEPENDENCIES_FILE_NAME).readStrings()
|
||||||
it.name to DependenciesSerializer.deserialize(it.absolutePath, data)
|
it.name to DependenciesSerializer.deserialize(it.absolutePath, data)
|
||||||
}
|
}
|
||||||
@@ -108,26 +110,26 @@ class CachedLibraries(
|
|||||||
|
|
||||||
override fun computeBitcodeDependencies() = perFileBitcodeDependencies.values.flatten()
|
override fun computeBitcodeDependencies() = perFileBitcodeDependencies.values.flatten()
|
||||||
|
|
||||||
override fun computeBinariesPaths() = fileDirs.map {
|
override fun computeBinariesPaths() = existingFileDirs.map {
|
||||||
it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(getArtifactName(target, it.name, kind.toCompilerOutputKind())).absolutePath
|
it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(getArtifactName(target, it.name, kind.toCompilerOutputKind())).absolutePath
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun computeSerializedInlineFunctionBodies() = mutableListOf<SerializedInlineFunctionReference>().also {
|
override fun computeSerializedInlineFunctionBodies() = mutableListOf<SerializedInlineFunctionReference>().also {
|
||||||
fileDirs.forEach { fileDir ->
|
existingFileDirs.forEach { fileDir ->
|
||||||
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
|
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
|
||||||
InlineFunctionBodyReferenceSerializer.deserializeTo(data, it)
|
InlineFunctionBodyReferenceSerializer.deserializeTo(data, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun computeSerializedClassFields() = mutableListOf<SerializedClassFields>().also {
|
override fun computeSerializedClassFields() = mutableListOf<SerializedClassFields>().also {
|
||||||
fileDirs.forEach { fileDir ->
|
existingFileDirs.forEach { fileDir ->
|
||||||
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(CLASS_FIELDS_FILE_NAME).readBytes()
|
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(CLASS_FIELDS_FILE_NAME).readBytes()
|
||||||
ClassFieldsSerializer.deserializeTo(data, it)
|
ClassFieldsSerializer.deserializeTo(data, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun computeSerializedEagerInitializedFiles() = mutableListOf<SerializedEagerInitializedFile>().also {
|
override fun computeSerializedEagerInitializedFiles() = mutableListOf<SerializedEagerInitializedFile>().also {
|
||||||
fileDirs.forEach { fileDir ->
|
existingFileDirs.forEach { fileDir ->
|
||||||
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(EAGER_INITIALIZED_PROPERTIES_FILE_NAME).readBytes()
|
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(EAGER_INITIALIZED_PROPERTIES_FILE_NAME).readBytes()
|
||||||
EagerInitializedPropertySerializer.deserializeTo(data, it)
|
EagerInitializedPropertySerializer.deserializeTo(data, it)
|
||||||
}
|
}
|
||||||
@@ -162,8 +164,8 @@ class CachedLibraries(
|
|||||||
val libraryFileDirs = librariesFileDirs.getOrPut(library) {
|
val libraryFileDirs = librariesFileDirs.getOrPut(library) {
|
||||||
library.getFilesWithFqNames().map { cacheDir.child(CacheSupport.cacheFileId(it.fqName, it.filePath)) }
|
library.getFilesWithFqNames().map { cacheDir.child(CacheSupport.cacheFileId(it.fqName, it.filePath)) }
|
||||||
}
|
}
|
||||||
Cache.PerFile(target, Kind.STATIC, cacheDir.absolutePath, libraryFileDirs)
|
Cache.PerFile(target, Kind.STATIC, cacheDir.absolutePath, libraryFileDirs,
|
||||||
.takeIf { cacheDirContents.containsAll(libraryFileDirs.map { it.absolutePath }) }
|
complete = cacheDirContents.containsAll(libraryFileDirs.map { it.absolutePath }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,8 +198,8 @@ class CachedLibraries(
|
|||||||
fun isLibraryCached(library: KotlinLibrary): Boolean =
|
fun isLibraryCached(library: KotlinLibrary): Boolean =
|
||||||
getLibraryCache(library) != null
|
getLibraryCache(library) != null
|
||||||
|
|
||||||
fun getLibraryCache(library: KotlinLibrary): Cache? =
|
fun getLibraryCache(library: KotlinLibrary, allowIncomplete: Boolean = false): Cache? =
|
||||||
allCaches[library]
|
allCaches[library]?.takeIf { allowIncomplete || (it as? Cache.PerFile)?.complete != false }
|
||||||
|
|
||||||
val hasStaticCaches = allCaches.values.any {
|
val hasStaticCaches = allCaches.values.any {
|
||||||
when (it.kind) {
|
when (it.kind) {
|
||||||
|
|||||||
+16
-3
@@ -406,6 +406,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
|
|
||||||
internal val additionalCacheFlags by lazy { platformManager.loader(target).additionalCacheFlags }
|
internal val additionalCacheFlags by lazy { platformManager.loader(target).additionalCacheFlags }
|
||||||
|
|
||||||
|
internal val threadsCount = configuration.get(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS) ?: 1
|
||||||
|
|
||||||
private fun StringBuilder.appendCommonCacheFlavor() {
|
private fun StringBuilder.appendCommonCacheFlavor() {
|
||||||
append(target.toString())
|
append(target.toString())
|
||||||
if (debug) append("-g")
|
if (debug) append("-g")
|
||||||
@@ -440,9 +442,19 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val systemCacheRootDirectory = File(distribution.konanHome).child("klib").child("cache")
|
private val systemCacheRootDirectory = File(distribution.konanHome).child("klib").child("cache")
|
||||||
internal val systemCacheDirectory = systemCacheRootDirectory.child(systemCacheFlavorString)
|
internal val systemCacheDirectory = systemCacheRootDirectory.child(systemCacheFlavorString).also { it.mkdirs() }
|
||||||
private val autoCacheRootDirectory = configuration.get(KonanConfigKeys.AUTO_CACHE_DIR)?.let { File(it) } ?: systemCacheRootDirectory
|
private val autoCacheRootDirectory = configuration.get(KonanConfigKeys.AUTO_CACHE_DIR)?.let {
|
||||||
internal val autoCacheDirectory = autoCacheRootDirectory.child(userCacheFlavorString)
|
File(it).apply {
|
||||||
|
if (!isDirectory) configuration.reportCompilationError("auto cache directory $this is not found or is not a directory")
|
||||||
|
}
|
||||||
|
} ?: systemCacheRootDirectory
|
||||||
|
internal val autoCacheDirectory = autoCacheRootDirectory.child(userCacheFlavorString).also { it.mkdirs() }
|
||||||
|
private val incrementalCacheRootDirectory = configuration.get(KonanConfigKeys.INCREMENTAL_CACHE_DIR)?.let {
|
||||||
|
File(it).apply {
|
||||||
|
if (!isDirectory) configuration.reportCompilationError("incremental cache directory $this is not found or is not a directory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal val incrementalCacheDirectory = incrementalCacheRootDirectory?.child(userCacheFlavorString)?.also { it.mkdirs() }
|
||||||
|
|
||||||
internal val ignoreCacheReason = when {
|
internal val ignoreCacheReason = when {
|
||||||
optimizationsEnabled -> "for optimized compilation"
|
optimizationsEnabled -> "for optimized compilation"
|
||||||
@@ -457,6 +469,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
ignoreCacheReason = ignoreCacheReason,
|
ignoreCacheReason = ignoreCacheReason,
|
||||||
systemCacheDirectory = systemCacheDirectory,
|
systemCacheDirectory = systemCacheDirectory,
|
||||||
autoCacheDirectory = autoCacheDirectory,
|
autoCacheDirectory = autoCacheDirectory,
|
||||||
|
incrementalCacheDirectory = incrementalCacheDirectory,
|
||||||
target = target,
|
target = target,
|
||||||
produce = produce
|
produce = produce
|
||||||
)
|
)
|
||||||
|
|||||||
+2
@@ -39,6 +39,8 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create<List<String>>("paths to the root directories from which dependencies are to be cached automatically")
|
= CompilerConfigurationKey.create<List<String>>("paths to the root directories from which dependencies are to be cached automatically")
|
||||||
val AUTO_CACHE_DIR: CompilerConfigurationKey<String>
|
val AUTO_CACHE_DIR: CompilerConfigurationKey<String>
|
||||||
= CompilerConfigurationKey.create<String>("path to the directory where to put caches for auto-cacheable dependencies")
|
= CompilerConfigurationKey.create<String>("path to the directory where to put caches for auto-cacheable dependencies")
|
||||||
|
val INCREMENTAL_CACHE_DIR: CompilerConfigurationKey<String>
|
||||||
|
= CompilerConfigurationKey.create<String>("path to the directory where to put incremental build caches")
|
||||||
val CACHED_LIBRARIES: CompilerConfigurationKey<Map<String, String>>
|
val CACHED_LIBRARIES: CompilerConfigurationKey<Map<String, String>>
|
||||||
= CompilerConfigurationKey.create<Map<String, String>>("mapping from library paths to cache paths")
|
= CompilerConfigurationKey.create<Map<String, String>>("mapping from library paths to cache paths")
|
||||||
val FILES_TO_CACHE: CompilerConfigurationKey<List<String>>
|
val FILES_TO_CACHE: CompilerConfigurationKey<List<String>>
|
||||||
|
|||||||
+12
-7
@@ -40,14 +40,17 @@ class KonanDriver(
|
|||||||
) {
|
) {
|
||||||
fun run() {
|
fun run() {
|
||||||
val fileNames = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE)?.let { libPath ->
|
val fileNames = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE)?.let { libPath ->
|
||||||
if (configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) != true)
|
val filesToCache = configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
||||||
configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
when {
|
||||||
else {
|
!filesToCache.isNullOrEmpty() -> filesToCache
|
||||||
val lib = createKonanLibrary(File(libPath), "default", null, true)
|
configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) == true -> {
|
||||||
(0 until lib.fileCount()).map { fileIndex ->
|
val lib = createKonanLibrary(File(libPath), "default", null, true)
|
||||||
val proto = IrFile.parseFrom(lib.file(fileIndex).codedInputStream, ExtensionRegistryLite.newInstance())
|
(0 until lib.fileCount()).map { fileIndex ->
|
||||||
proto.fileEntry.name
|
val proto = IrFile.parseFrom(lib.file(fileIndex).codedInputStream, ExtensionRegistryLite.newInstance())
|
||||||
|
proto.fileEntry.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fileNames != null) {
|
if (fileNames != null) {
|
||||||
@@ -75,6 +78,8 @@ class KonanDriver(
|
|||||||
konanConfig = KonanConfig(project, configuration) // TODO: Just set freshly built caches.
|
konanConfig = KonanConfig(project, configuration) // TODO: Just set freshly built caches.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
konanConfig.cacheSupport.checkConsistency()
|
||||||
|
|
||||||
DynamicCompilerDriver().run(konanConfig, environment)
|
DynamicCompilerDriver().run(konanConfig, environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -177,6 +177,11 @@ fun CompilerConfiguration.setupFromArguments(arguments: K2NativeCompilerArgument
|
|||||||
put(CACHE_DIRECTORIES, arguments.cacheDirectories.toNonNullList())
|
put(CACHE_DIRECTORIES, arguments.cacheDirectories.toNonNullList())
|
||||||
put(AUTO_CACHEABLE_FROM, arguments.autoCacheableFrom.toNonNullList())
|
put(AUTO_CACHEABLE_FROM, arguments.autoCacheableFrom.toNonNullList())
|
||||||
arguments.autoCacheDir?.let { put(AUTO_CACHE_DIR, it) }
|
arguments.autoCacheDir?.let { put(AUTO_CACHE_DIR, it) }
|
||||||
|
val incrementalCacheDir = arguments.incrementalCacheDir
|
||||||
|
if ((incrementalCacheDir != null) xor (arguments.incrementalCompilation == true))
|
||||||
|
report(ERROR, "For incremental compilation both flags should be supplied: " +
|
||||||
|
"-Xenable-incremental-compilation and ${K2NativeCompilerArguments.INCREMENTAL_CACHE_DIR}")
|
||||||
|
incrementalCacheDir?.let { put(INCREMENTAL_CACHE_DIR, it) }
|
||||||
arguments.filesToCache?.let { put(FILES_TO_CACHE, it.toList()) }
|
arguments.filesToCache?.let { put(FILES_TO_CACHE, it.toList()) }
|
||||||
put(MAKE_PER_FILE_CACHE, arguments.makePerFileCache)
|
put(MAKE_PER_FILE_CACHE, arguments.makePerFileCache)
|
||||||
val nThreadsRaw = parseBackendThreads(arguments.backendThreads)
|
val nThreadsRaw = parseBackendThreads(arguments.backendThreads)
|
||||||
@@ -302,6 +307,7 @@ internal fun CompilerConfiguration.setupCommonOptionsForCaches(konanConfig: Kona
|
|||||||
put(BinaryOptions.freezing, konanConfig.freezing)
|
put(BinaryOptions.freezing, konanConfig.freezing)
|
||||||
put(BinaryOptions.runtimeAssertionsMode, konanConfig.runtimeAssertsMode)
|
put(BinaryOptions.runtimeAssertionsMode, konanConfig.runtimeAssertsMode)
|
||||||
put(LAZY_IR_FOR_CACHES, konanConfig.lazyIrForCaches)
|
put(LAZY_IR_FOR_CACHES, konanConfig.lazyIrForCaches)
|
||||||
|
put(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS, konanConfig.threadsCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Array<String>?.toNonNullList() = this?.asList().orEmpty()
|
private fun Array<String>?.toNonNullList() = this?.asList().orEmpty()
|
||||||
|
|||||||
+4
-5
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.konan.driver.utilities.CExportFiles
|
|||||||
import org.jetbrains.kotlin.backend.konan.driver.utilities.createTempFiles
|
import org.jetbrains.kotlin.backend.konan.driver.utilities.createTempFiles
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.konanLibrary
|
import org.jetbrains.kotlin.backend.konan.ir.konanLibrary
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
@@ -119,8 +118,8 @@ internal fun <C : PhaseContext> PhaseEngine<C>.runBackend(backendContext: Contex
|
|||||||
}
|
}
|
||||||
|
|
||||||
val fragments = backendEngine.splitIntoFragments(irModule)
|
val fragments = backendEngine.splitIntoFragments(irModule)
|
||||||
val nThreads = context.config.configuration.get(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS) ?: 1
|
val threadsCount = context.config.threadsCount
|
||||||
if (nThreads == 1) {
|
if (threadsCount == 1) {
|
||||||
fragments.forEach { fragment ->
|
fragments.forEach { fragment ->
|
||||||
runAfterLowerings(fragment, createGenerationStateAndRunLowerings(fragment))
|
runAfterLowerings(fragment, createGenerationStateAndRunLowerings(fragment))
|
||||||
}
|
}
|
||||||
@@ -133,9 +132,9 @@ internal fun <C : PhaseContext> PhaseEngine<C>.runBackend(backendContext: Contex
|
|||||||
// We'd love to run entire pipeline in parallel, but it's difficult (mainly because of the lowerings,
|
// We'd love to run entire pipeline in parallel, but it's difficult (mainly because of the lowerings,
|
||||||
// which need cross-file access all the time and it's not easy to overcome this). So, for now,
|
// which need cross-file access all the time and it's not easy to overcome this). So, for now,
|
||||||
// we split the pipeline into two parts - everything before lowerings (including them)
|
// we split the pipeline into two parts - everything before lowerings (including them)
|
||||||
// which is run sequentially, and everything else which in run in parallel.
|
// which is run sequentially, and everything else which is run in parallel.
|
||||||
val generationStates = fragmentsList.map { fragment -> createGenerationStateAndRunLowerings(fragment) }
|
val generationStates = fragmentsList.map { fragment -> createGenerationStateAndRunLowerings(fragment) }
|
||||||
val executor = Executors.newFixedThreadPool(nThreads)
|
val executor = Executors.newFixedThreadPool(threadsCount)
|
||||||
val thrownFromThread = AtomicReference<Throwable?>(null)
|
val thrownFromThread = AtomicReference<Throwable?>(null)
|
||||||
val tasks = fragmentsList.zip(generationStates).map { (fragment, generationState) ->
|
val tasks = fragmentsList.zip(generationStates).map { (fragment, generationState) ->
|
||||||
Callable {
|
Callable {
|
||||||
|
|||||||
Reference in New Issue
Block a user