Mimalloc allocator integration

This commit is contained in:
Elena Lepilkina
2019-07-16 17:13:15 +03:00
committed by LepilkinaElena
parent 08e05bb10b
commit 5d6af6e806
19 changed files with 223 additions and 216 deletions
@@ -153,6 +153,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(LIGHT_DEBUG, arguments.lightDebug)
put(STATIC_FRAMEWORK, selectFrameworkType(configuration, arguments, outputKind))
put(OVERRIDE_CLANG_OPTIONS, arguments.clangOptions.toNonNullList())
put(ALLOCATION_MODE, arguments.allocator)
put(PRINT_IR, arguments.printIr)
put(PRINT_IR_WITH_DESCRIPTORS, arguments.printIrWithDescriptors)
@@ -242,6 +242,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-Xoverride-clang-options", valueDescription = "<arg1,arg2,...>", description = "Explicit list of Clang options")
var clangOptions: Array<String>? = null
@Argument(value="-Xallocator", valueDescription = "std | mimalloc", description = "Allocator used in runtime")
var allocator: String = "std"
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector).also {
val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
@@ -13,20 +13,13 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.CompilerVersion
import org.jetbrains.kotlin.konan.MetaVersion
import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.util.Logger
import kotlin.system.exitProcess
import org.jetbrains.kotlin.library.toUnresolvedLibraries
import org.jetbrains.kotlin.konan.CompilerVersion
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder
@@ -116,6 +109,18 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
add(if (debug) "debug.bc" else "release.bc")
add(if (memoryModel == MemoryModel.STRICT) "strict.bc" else "relaxed.bc")
if (shouldCoverLibraries || shouldCoverSources) add("profileRuntime.bc")
if (configuration.get(KonanConfigKeys.ALLOCATION_MODE) == "mimalloc") {
if (!target.supportsMimallocAllocator()) {
configuration.report(CompilerMessageSeverity.STRONG_WARNING,
"Mimalloc allocator isn't supported on target ${target.name}. Used standard mode.")
add("std_alloc.bc")
} else {
add("opt_alloc.bc")
add("mimalloc.bc")
}
} else {
add("std_alloc.bc")
}
}.map {
File(distribution.defaultNatives(target)).child(it).absolutePath
}
@@ -88,6 +88,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("program or library name")
val OVERRIDE_CLANG_OPTIONS: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("arguments for clang")
val ALLOCATION_MODE: CompilerConfigurationKey<String>
= CompilerConfigurationKey.create("allocation mode")
val PRINT_BITCODE: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("print bitcode")
val PRINT_DESCRIPTORS: CompilerConfigurationKey<Boolean>
@@ -1,146 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.*
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
class CompileCppToBitcode extends DefaultTask {
private String name = "main"
private String target = "host"
private File srcRoot;
protected List<String> compilerArgs = []
protected List<String> linkerArgs = []
@InputDirectory
File getSrcRoot() {
return srcRoot ?: project.file("src/$name")
}
@OutputFile
File getOutFile() {
return new File(getTargetDir(), "${name}.bc")
}
private File getSrcDir() {
return new File(this.getSrcRoot(), "cpp")
}
private File getHeadersDir() {
return new File(this.getSrcRoot(), "headers")
}
private File getTargetDir() {
return new File(project.buildDir, target)
}
private File getObjDir() {
return new File(getTargetDir(), name)
}
void name(String value) {
name = value
}
void target(String value) {
target = value
}
void srcRoot(File value) {
srcRoot = value
}
protected List<String> getCompilerArgs() {
return compilerArgs
}
protected List<String> getLinkerArgs() {
return linkerArgs
}
protected String getTarget() {
return target
}
void compilerArgs(String... args) {
compilerArgs.addAll(args)
}
void compilerArgs(List<String> args) {
compilerArgs.addAll(args)
}
void linkerArgs(String... args) {
linkerArgs.addAll(args)
}
void linkerArgs(List<String> args) {
linkerArgs.addAll(args)
}
private Boolean targetingMinGW() {
def hostManager = new HostManager()
return hostManager.targetByName(this.target).family == Family.MINGW
}
@TaskAction
void compile() {
// the strange code below seems to be required due to some Gradle (Groovy?) behaviour
File headersDir = this.getHeadersDir()
File srcDir = this.getSrcDir()
List<String> compilerArgs = this.getCompilerArgs()
List<String> linkerArgs = this.getLinkerArgs()
File objDir = this.getObjDir()
objDir.mkdirs()
Boolean targetingMinGW = this.targetingMinGW()
project.execKonanClang(this.target) {
workingDir objDir
executable "clang++"
args '-std=c++14'
args '-Werror'
args '-O2'
if (!targetingMinGW) {
args '-fPIC'
}
args compilerArgs
args "-I$headersDir"
args '-c', '-emit-llvm'
args project.fileTree(srcDir) {
include('**/*.cpp')
include('**/*.mm') // Objective-C++
}
}
project.exec {
executable "$project.llvmDir/bin/llvm-link"
args project.fileTree(objDir).include('**/*.bc').sort { a, b -> (a.name <=> b.name) }
args linkerArgs
args '-o', outFile
}
}
}
@@ -0,0 +1,97 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
import javax.inject.Inject
open class CompileToBitcode @Inject constructor(@InputDirectory val srcRoot: File,
val folderName: String,
val target: String) : DefaultTask() {
enum class Language {
C, CPP
}
val compilerArgs = mutableListOf<String>()
val linkerArgs = mutableListOf<String>()
val excludeFiles = mutableListOf<String>()
var srcDir = File(srcRoot, "cpp")
var headersDir = File(srcRoot, "headers")
var skipLinkagePhase = false
var excludedTargets = mutableListOf<String>()
var language = Language.CPP
private val targetDir by lazy { File(project.buildDir, target) }
private val objDir by lazy { File(targetDir, folderName) }
private val KonanTarget.isMINGW
get() = this.family == Family.MINGW
@OutputFile
val outFile = File(targetDir, "${folderName}.bc")
@TaskAction
fun compile() {
if (target in excludedTargets) return
objDir.mkdirs()
val plugin = project.convention.getPlugin(ExecClang::class.java)
val commonFlags = listOf("-c", "-emit-llvm", "-I$headersDir")
val (executable, defaultFlags, srcFilesPatterns) =
when (language) {
Language.C -> Triple("clang",
// Used flags provided by original build of allocator C code.
commonFlags + listOf("-std=gnu11", "-O3", "-Wall", "-Wextra", "-Wno-unknown-pragmas",
"-ftls-model=initial-exec"),
listOf("**/*.c"))
Language.CPP -> Triple("clang++",
commonFlags + listOfNotNull("-std=c++14", "-Werror", "-O2",
"-fPIC".takeIf { !HostManager().targetByName(target).isMINGW }),
listOf("**/*.cpp", "**/*.mm"))
}
plugin.execKonanClang(target, Action {
it.workingDir = objDir
it.executable = executable
it.args = defaultFlags + compilerArgs +
project.fileTree(srcDir) {
it.include(srcFilesPatterns)
it.exclude(excludeFiles)
}.files.map { it.absolutePath }
})
if (!skipLinkagePhase) {
project.exec {
val llvmDir = project.findProperty("llvmDir")
it.executable = "$llvmDir/bin/llvm-link"
it.args = listOf("-o", outFile.absolutePath) + linkerArgs +
project.fileTree(objDir) {
it.include("**/*.bc")
}.files.map { it.absolutePath }
}
}
}
}
@@ -240,4 +240,7 @@ fun compileSwift(project: Project, target: KonanTarget, sources: List<String>, o
""".trimMargin())
check(exitCode == 0, { "Compilation failed" })
check(output.toFile().exists(), { "Compiler swiftc hasn't produced an output file: $output" })
}
}
fun targetSupportsMimallocAllocator(targetName: String) =
HostManager().targetByName(targetName).supportsMimallocAllocator()
+3 -9
View File
@@ -2,22 +2,16 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
import org.jetbrains.kotlin.CompileCppToBitcode
import org.jetbrains.kotlin.CompileToBitcode
// TODO: consider using some Gradle plugins to build and test
targetList.each { targetName ->
task ("${targetName}Hash", type: CompileCppToBitcode) {
name 'hash'
target targetName
}
tasks.create("${targetName}Hash", CompileToBitcode, file("src/hash"), 'hash', targetName)
}
targetList.each { targetName ->
task ("${targetName}Files", type: CompileCppToBitcode) {
name 'files'
target targetName
}
tasks.create("${targetName}Files", CompileToBitcode, file("src/files"), 'files', targetName)
}
task build {
+35 -43
View File
@@ -1,21 +1,23 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
import org.jetbrains.kotlin.CompileCppToBitcode
import org.jetbrains.kotlin.CompileToBitcode
import org.jetbrains.kotlin.UtilsKt
// TODO: consider using some Gradle plugins to build and test
void includeRuntime(CompileCppToBitcode task) {
task.compilerArgs '-I' + project.file('../common/src/hash/headers')
task.compilerArgs '-I' + project.file('src/main/cpp')
void includeRuntime(CompileToBitcode task) {
task.compilerArgs.add('-I' + project.file('../common/src/hash/headers'))
task.compilerArgs.add('-I' + project.file('src/main/cpp'))
}
targetList.each { targetName ->
task("${targetName}Runtime", type: CompileCppToBitcode) {
name "runtime"
srcRoot file('src/main')
tasks.create("${targetName}Runtime", CompileToBitcode, file('src/main'), "runtime", targetName).configure {
dependsOn ":common:${targetName}Hash"
dependsOn "${targetName}StdAlloc"
dependsOn "${targetName}OptAlloc"
dependsOn "${targetName}Mimalloc"
dependsOn "${targetName}Launcher"
dependsOn "${targetName}Debug"
dependsOn "${targetName}Release"
@@ -24,63 +26,53 @@ targetList.each { targetName ->
dependsOn "${targetName}ProfileRuntime"
dependsOn "${targetName}ObjC"
dependsOn "${targetName}ExceptionsSupport"
target targetName
includeRuntime(delegate)
linkerArgs project.file("../common/build/$targetName/hash.bc").path
linkerArgs.add(project.file("../common/build/$targetName/hash.bc").path)
}
task("${targetName}Launcher", type: CompileCppToBitcode) {
name "launcher"
srcRoot file('src/launcher')
target targetName
tasks.create("${targetName}Mimalloc", CompileToBitcode, file('src/mimalloc'), "mimalloc", targetName).configure {
language = CompileToBitcode.Language.C
excludeFiles.addAll(["**/alloc-override*.c", "**/page-queue.c", "**/static.c"])
if (!UtilsKt.targetSupportsMimallocAllocator(targetName))
excludedTargets.add(targetName)
srcDir = new File(srcRoot, "c")
compilerArgs.add("-DKONAN_MI_MALLOC=1")
headersDir = new File(srcDir, "include")
}
tasks.create("${targetName}Launcher", CompileToBitcode, file('src/launcher'), "launcher", targetName).configure {
includeRuntime(delegate)
}
task ("${targetName}Debug", type: CompileCppToBitcode) {
name "debug"
srcRoot file('src/debug')
target targetName
tasks.create("${targetName}Debug", CompileToBitcode, file('src/debug'), "debug", targetName).configure {
includeRuntime(delegate)
}
task ("${targetName}ExceptionsSupport", type: CompileCppToBitcode) {
name "exceptionsSupport"
srcRoot file('src/exceptions_support')
target targetName
tasks.create("${targetName}StdAlloc", CompileToBitcode, file('src/std_alloc'), "std_alloc", targetName)
tasks.create("${targetName}OptAlloc", CompileToBitcode, file('src/opt_alloc'), "opt_alloc", targetName)
tasks.create("${targetName}ExceptionsSupport", CompileToBitcode, file('src/exceptions_support'),
"exceptionsSupport", targetName).configure {
includeRuntime(delegate)
}
task ("${targetName}Release", type: CompileCppToBitcode) {
name "release"
srcRoot file('src/release')
target targetName
tasks.create("${targetName}Release", CompileToBitcode, file('src/release'), "release", targetName).configure {
includeRuntime(delegate)
}
task ("${targetName}Strict", type: CompileCppToBitcode) {
name "strict"
srcRoot file('src/strict')
target targetName
tasks.create("${targetName}Strict", CompileToBitcode, file('src/strict'), "strict", targetName).configure {
includeRuntime(delegate)
}
task ("${targetName}Relaxed", type: CompileCppToBitcode) {
name "relaxed"
srcRoot file('src/relaxed')
target targetName
tasks.create("${targetName}Relaxed", CompileToBitcode, file('src/relaxed'), "relaxed", targetName).configure {
includeRuntime(delegate)
}
task ("${targetName}ProfileRuntime", type: CompileCppToBitcode) {
name "profileRuntime"
srcRoot file('src/profile_runtime')
target targetName
}
tasks.create("${targetName}ProfileRuntime", CompileToBitcode, file('src/profile_runtime'),
"profileRuntime", targetName)
task ("${targetName}ObjC", type: CompileCppToBitcode) {
name "objc"
srcRoot file('src/objc')
target targetName
tasks.create("${targetName}ObjC", CompileToBitcode, file('src/objc'), "objc", targetName).configure {
includeRuntime(delegate)
}
}
+4 -2
View File
@@ -216,8 +216,10 @@ extern "C" void dlfree(void*);
#define calloc_impl dlcalloc
#define free_impl dlfree
#else
#define calloc_impl ::calloc
#define free_impl ::free
extern "C" void* konan_calloc_impl(size_t, size_t);
extern "C" void konan_free_impl(void*);
#define calloc_impl konan_calloc_impl
#define free_impl konan_free_impl
#endif
void* calloc(size_t count, size_t size) {
@@ -5,6 +5,7 @@ terms of the MIT license. A copy of the license can be found in the file
"LICENSE" at the root of this distribution.
-----------------------------------------------------------------------------*/
#if !KONAN_MI_MALLOC
#include "mimalloc.h"
#include "mimalloc-internal.h"
@@ -228,3 +229,4 @@ static void __attribute__((constructor)) _mi_macos_override_malloc()
}
#endif // MI_MALLOC_OVERRIDE
#endif
+2 -2
View File
@@ -4,7 +4,7 @@ This is free software; you can redistribute it and/or modify it under the
terms of the MIT license. A copy of the license can be found in the file
"LICENSE" at the root of this distribution.
-----------------------------------------------------------------------------*/
#if !KONAN_MI_MALLOC
#if !defined(MI_IN_ALLOC_C)
#error "this file should be included from 'alloc.c' (so aliases can work)"
#endif
@@ -194,4 +194,4 @@ int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_me
#endif
#endif // MI_MALLOC_OVERRIDE && !_WIN32
#endif
@@ -214,7 +214,7 @@ static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x)
asm volatile ("pause" ::: "memory");
}
#elif defined(__arm__) || defined(__aarch64__)
#if defined(KONAN_MI_MALLOC)
#if KONAN_MI_MALLOC
#if defined(__arm__)
#include <sched.h>
static inline void mi_atomic_yield(void) {
@@ -457,7 +457,7 @@ static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept {
}
#elif (defined(__GNUC__) || defined(__clang__)) && \
(defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))
#if defined(KONAN_MI_MALLOC)
#if KONAN_MI_MALLOC
#include <pthread.h>
pthread_t pthread_self(void);
#endif
@@ -468,7 +468,7 @@ static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept {
#if defined(__i386__)
__asm__("movl %%gs:0, %0" : "=r" (tid) : : ); // 32-bit always uses GS
#elif defined(__MACH__)
#if defined(KONAN_MI_MALLOC)
#if KONAN_MI_MALLOC
#include <TargetConditionals.h>
#if TARGET_OS_EMBEDDED // iOS/tvOS/watchOS devices.
tid = pthread_self();
@@ -17,7 +17,7 @@ terms of the MIT license. A copy of the license can be found in the file
// ------------------------------------------------------
// Define NDEBUG in the release version to disable assertions.
#if !defined(KONAN_MI_MALLOC)
#if !KONAN_MI_MALLOC
#define NDEBUG
#endif
+2
View File
@@ -4,6 +4,7 @@ This is free software; you can redistribute it and/or modify it under the
terms of the MIT license. A copy of the license can be found in the file
"LICENSE" at the root of this distribution.
-----------------------------------------------------------------------------*/
#if !KONAN_MI_MALLOC
#define _DEFAULT_SOURCE
#include "mimalloc.h"
@@ -24,3 +25,4 @@ terms of the MIT license. A copy of the license can be found in the file
#include "alloc-posix.c"
#include "init.c"
#include "options.c"
#endif
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include <stdlib.h>
#include <stdio.h>
extern "C" {
void* mi_calloc(size_t, size_t);
void mi_free(void*);
void* konan_calloc_impl(size_t n_elements, size_t elem_size) {
return mi_calloc(n_elements, elem_size);
}
void konan_free_impl (void* mem) {
mi_free(mem);
}
} // extern "C"
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include <stdlib.h>
#include <stdio.h>
extern "C" {
// Memory operations.
void* konan_calloc_impl(size_t n_elements, size_t elem_size) {
return calloc(n_elements, elem_size);
}
void konan_free_impl (void* mem) {
free(mem);
}
}
@@ -4,4 +4,20 @@ fun KonanTarget.supportsCodeCoverage(): Boolean =
this == KonanTarget.MINGW_X64 ||
this == KonanTarget.LINUX_X64 ||
this == KonanTarget.MACOS_X64 ||
this == KonanTarget.IOS_X64
this == KonanTarget.IOS_X64
fun KonanTarget.supportsMimallocAllocator(): Boolean =
when(this) {
is KonanTarget.LINUX_X64 -> true
is KonanTarget.MINGW_X86 -> true
is KonanTarget.MINGW_X64 -> true
is KonanTarget.MACOS_X64 -> true
is KonanTarget.LINUX_ARM64 -> true
is KonanTarget.LINUX_ARM32_HFP -> true
is KonanTarget.ANDROID_X64 -> true
is KonanTarget.ANDROID_ARM64 -> true
is KonanTarget.IOS_ARM32 -> true
is KonanTarget.IOS_ARM64 -> true
is KonanTarget.IOS_X64 -> true
else -> false // watchOS/tvOS/android_x86/android_arm32 aren't tested; linux_mips32/linux_mipsel32 need linking with libatomic.
}