Gradle plugin for swift benchmarks (#3361)
This commit is contained in:
@@ -63,12 +63,16 @@ gradlePlugin {
|
||||
plugins {
|
||||
create("benchmarkPlugin") {
|
||||
id = "benchmarking"
|
||||
implementationClass = "org.jetbrains.kotlin.benchmark.BenchmarkingPlugin"
|
||||
implementationClass = "org.jetbrains.kotlin.benchmark.KotlinNativeBenchmarkingPlugin"
|
||||
}
|
||||
create("compileBenchmarking") {
|
||||
id = "compile-benchmarking"
|
||||
implementationClass = "org.jetbrains.kotlin.benchmark.CompileBenchmarkingPlugin"
|
||||
}
|
||||
create("swiftBenchmarking") {
|
||||
id = "swift-benchmarking"
|
||||
implementationClass = "org.jetbrains.kotlin.benchmark.SwiftBenchmarkingPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,21 +159,11 @@ fun sendUploadRequest(url: String, fileName: String, username: String? = null, p
|
||||
fun createRunTask(
|
||||
subproject: Project,
|
||||
name: String,
|
||||
linkTask: KotlinNativeLink,
|
||||
linkTask: Task,
|
||||
executable: String,
|
||||
outputFileName: String
|
||||
): Task {
|
||||
return subproject.tasks.create(name, RunKotlinNativeTask::class.java, linkTask, outputFileName)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun createBenchmarksRunTask(
|
||||
subproject: Project,
|
||||
name: String,
|
||||
configureClosure: Closure<Any>? = null
|
||||
): Task {
|
||||
val task = subproject.tasks.create(name, RunBenchmarksExecutableTask::class.java)
|
||||
task.configure(configureClosure ?: task.emptyConfigureClosure())
|
||||
return task
|
||||
return subproject.tasks.create(name, RunKotlinNativeTask::class.java, linkTask, executable, outputFileName)
|
||||
}
|
||||
|
||||
fun getJvmCompileTime(programName: String): BenchmarkResult =
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.options.Option
|
||||
import org.gradle.api.tasks.Input
|
||||
import javax.inject.Inject
|
||||
import java.io.File
|
||||
|
||||
open class RunBenchmarksExecutableTask @Inject constructor() : DefaultTask() {
|
||||
var workingDir: Any = project.projectDir
|
||||
var outputFileName: String? = null
|
||||
var executable: String? = null
|
||||
@Input
|
||||
@Option(option = "filter", description = "Benchmarks to run (comma-separated)")
|
||||
var filter: String = ""
|
||||
@Input
|
||||
@Option(option = "filterRegex", description = "Benchmarks to run, described by regular expressions (comma-separated)")
|
||||
var filterRegex: String = ""
|
||||
@Input
|
||||
@Option(option = "verbose", description = "Verbose mode of running benchmarks")
|
||||
var verbose: Boolean = false
|
||||
|
||||
private var curArgs: List<String> = emptyList()
|
||||
private val curEnvironment: MutableMap<String, Any> = mutableMapOf()
|
||||
|
||||
fun args(vararg args: Any) {
|
||||
curArgs = args.map { it.toString() }
|
||||
}
|
||||
|
||||
fun environment(map: Map<String, Any>) {
|
||||
curEnvironment += map
|
||||
}
|
||||
|
||||
override fun configure(configureClosure: Closure<Any>): Task {
|
||||
val task = super.configure(configureClosure)
|
||||
return task
|
||||
}
|
||||
|
||||
fun depends(taskName: String) {
|
||||
this.dependsOn += taskName
|
||||
}
|
||||
|
||||
private fun executeTask(output: java.io.OutputStream? = null) {
|
||||
val filterArgs = filter.splitCommaSeparatedOption("-f")
|
||||
val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr")
|
||||
project.exec {
|
||||
it.executable = executable
|
||||
it.args = curArgs + filterArgs + filterRegexArgs
|
||||
it.environment = curEnvironment
|
||||
it.workingDir(workingDir)
|
||||
if (verbose) {
|
||||
it.args("-v")
|
||||
}
|
||||
if (output != null)
|
||||
it.standardOutput = output
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
if (outputFileName != null)
|
||||
File(outputFileName).outputStream().use { output -> executeTask(output) }
|
||||
else
|
||||
executeTask()
|
||||
}
|
||||
|
||||
internal fun emptyConfigureClosure() = object : Closure<Any>(this) {
|
||||
override fun call(): RunBenchmarksExecutableTask {
|
||||
return this@RunBenchmarksExecutableTask
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Task
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.options.Option
|
||||
@@ -14,7 +15,8 @@ import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
open class RunKotlinNativeTask @Inject constructor(private val linkTask: KotlinNativeLink,
|
||||
open class RunKotlinNativeTask @Inject constructor(private val linkTask: Task,
|
||||
private val executable: String,
|
||||
private val outputFileName: String
|
||||
) : DefaultTask() {
|
||||
@Input
|
||||
@@ -48,7 +50,7 @@ open class RunKotlinNativeTask @Inject constructor(private val linkTask: KotlinN
|
||||
fun run() {
|
||||
var output = ByteArrayOutputStream()
|
||||
project.exec {
|
||||
it.executable = linkTask.binary.outputFile.absolutePath
|
||||
it.executable = executable
|
||||
it.args("list")
|
||||
it.standardOutput = output
|
||||
}
|
||||
@@ -63,7 +65,7 @@ open class RunKotlinNativeTask @Inject constructor(private val linkTask: KotlinN
|
||||
val results = benchmarksToRun.map { benchmark ->
|
||||
output = ByteArrayOutputStream()
|
||||
project.exec {
|
||||
it.executable = linkTask.binary.outputFile.absolutePath
|
||||
it.executable = executable
|
||||
it.args(argumentsList)
|
||||
it.args("-f", benchmark)
|
||||
if (verbose) {
|
||||
|
||||
@@ -4,45 +4,33 @@ import groovy.lang.Closure
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.util.ConfigureUtil
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetPreset
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private val NamedDomainObjectContainer<KotlinSourceSet>.commonMain
|
||||
internal val NamedDomainObjectContainer<KotlinSourceSet>.commonMain
|
||||
get() = maybeCreate("commonMain")
|
||||
|
||||
private val NamedDomainObjectContainer<KotlinSourceSet>.nativeMain
|
||||
internal val NamedDomainObjectContainer<KotlinSourceSet>.nativeMain
|
||||
get() = maybeCreate("nativeMain")
|
||||
|
||||
private val NamedDomainObjectContainer<KotlinSourceSet>.jvmMain
|
||||
get() = maybeCreate("jvmMain")
|
||||
|
||||
private val Project.benchmark: BenchmarkExtension
|
||||
get() = extensions.getByName(BenchmarkingPlugin.BENCHMARK_EXTENSION_NAME) as BenchmarkExtension
|
||||
|
||||
private val Project.nativeWarmup: Int
|
||||
internal val Project.nativeWarmup: Int
|
||||
get() = (property("nativeWarmup") as String).toInt()
|
||||
|
||||
private val Project.jvmWarmup: Int
|
||||
get() = (property("jvmWarmup") as String).toInt()
|
||||
|
||||
private val Project.attempts: Int
|
||||
internal val Project.attempts: Int
|
||||
get() = (property("attempts") as String).toInt()
|
||||
|
||||
private val Project.nativeBenchResults: String
|
||||
internal val Project.nativeBenchResults: String
|
||||
get() = property("nativeBenchResults") as String
|
||||
|
||||
private val Project.jvmBenchResults: String
|
||||
get() = property("jvmBenchResults") as String
|
||||
|
||||
private val Project.compilerArgs: List<String>
|
||||
internal val Project.compilerArgs: List<String>
|
||||
get() = (findProperty("compilerArgs") as String?)?.split("\\s").orEmpty()
|
||||
|
||||
internal val Project.kotlinVersion: String
|
||||
@@ -75,10 +63,8 @@ internal val Project.commonBenchmarkProperties: Map<String, Any>
|
||||
open class BenchmarkExtension @Inject constructor(val project: Project) {
|
||||
var applicationName: String = project.name
|
||||
var commonSrcDirs: Collection<Any> = emptyList()
|
||||
var jvmSrcDirs: Collection<Any> = emptyList()
|
||||
var nativeSrcDirs: Collection<Any> = emptyList()
|
||||
var mingwSrcDirs: Collection<Any> = emptyList()
|
||||
var posixSrcDirs: Collection<Any> = emptyList()
|
||||
var compileTasks: List<String> = emptyList()
|
||||
var linkerOpts: Collection<String> = emptyList()
|
||||
|
||||
val dependencies: BenchmarkDependencies = BenchmarkDependencies()
|
||||
@@ -91,7 +77,7 @@ open class BenchmarkExtension @Inject constructor(val project: Project) {
|
||||
}
|
||||
|
||||
inner class BenchmarkDependencies {
|
||||
private val sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
|
||||
public val sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
|
||||
get() = project.kotlin.sourceSets
|
||||
|
||||
fun project(path: String): Dependency = project.dependencies.project(mapOf("path" to path))
|
||||
@@ -103,10 +89,6 @@ open class BenchmarkExtension @Inject constructor(val project: Project) {
|
||||
implementation(notation)
|
||||
}
|
||||
|
||||
fun jvm(notation: Any) = sourceSets.jvmMain.dependencies {
|
||||
implementation(notation)
|
||||
}
|
||||
|
||||
fun native(notation: Any) = sourceSets.nativeMain.dependencies {
|
||||
implementation(notation)
|
||||
}
|
||||
@@ -116,25 +98,30 @@ open class BenchmarkExtension @Inject constructor(val project: Project) {
|
||||
/**
|
||||
* A plugin configuring a benchmark Kotlin/Native project.
|
||||
*/
|
||||
open class BenchmarkingPlugin: Plugin<Project> {
|
||||
abstract class BenchmarkingPlugin: Plugin<Project> {
|
||||
protected abstract val Project.nativeExecutable: String
|
||||
protected abstract val Project.nativeLinkTask: Task
|
||||
protected abstract val Project.benchmark: BenchmarkExtension
|
||||
protected abstract val benchmarkExtensionName: String
|
||||
protected abstract val benchmarkExtensionClass: KClass<*>
|
||||
|
||||
private val mingwPath: String = System.getenv("MINGW64_DIR") ?: "c:/msys64/mingw64"
|
||||
protected val mingwPath: String = System.getenv("MINGW64_DIR") ?: "c:/msys64/mingw64"
|
||||
|
||||
private fun Project.determinePreset(): KotlinNativeTargetPreset =
|
||||
protected open fun Project.determinePreset(): KotlinNativeTargetPreset =
|
||||
defaultHostPreset(this).also { preset ->
|
||||
logger.quiet("$project has been configured for ${preset.name} platform.")
|
||||
} as KotlinNativeTargetPreset
|
||||
|
||||
private fun Project.configureSourceSets(kotlinVersion: String) {
|
||||
protected abstract fun NamedDomainObjectContainer<KotlinSourceSet>.configureSources(project: Project)
|
||||
|
||||
protected open fun NamedDomainObjectContainer<KotlinSourceSet>.additionalConfigurations(project: Project) {}
|
||||
|
||||
protected open fun Project.configureSourceSets(kotlinVersion: String) {
|
||||
with(kotlin.sourceSets) {
|
||||
commonMain.dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinStdlibVersion")
|
||||
}
|
||||
|
||||
jvmMain.dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinStdlibVersion")
|
||||
}
|
||||
|
||||
project.configurations.getByName(nativeMain.implementationConfigurationName).apply {
|
||||
// Exclude dependencies already included into K/N distribution (aka endorsed libraries).
|
||||
exclude(mapOf("module" to "kotlinx.cli"))
|
||||
@@ -144,69 +131,49 @@ open class BenchmarkingPlugin: Plugin<Project> {
|
||||
it.setUrl(kotlinStdlibRepo)
|
||||
}
|
||||
|
||||
additionalConfigurations(this@configureSourceSets)
|
||||
|
||||
// Add sources specified by a user in the benchmark DSL.
|
||||
afterEvaluate {
|
||||
benchmark.let {
|
||||
commonMain.kotlin.srcDirs(*it.commonSrcDirs.toTypedArray())
|
||||
if (HostManager.hostIsMingw) {
|
||||
nativeMain.kotlin.srcDirs(*(it.nativeSrcDirs + it.mingwSrcDirs).toTypedArray())
|
||||
} else {
|
||||
nativeMain.kotlin.srcDirs(*(it.nativeSrcDirs + it.posixSrcDirs).toTypedArray())
|
||||
}
|
||||
jvmMain.kotlin.srcDirs(*it.jvmSrcDirs.toTypedArray())
|
||||
}
|
||||
configureSources(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.configureJVMTarget() {
|
||||
kotlin.jvm {
|
||||
compilations.all {
|
||||
it.compileKotlinTask.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
suppressWarnings = true
|
||||
freeCompilerArgs = project.compilerArgs
|
||||
}
|
||||
protected open fun KotlinNativeTarget.configureNativeOutput(project: Project) {
|
||||
binaries.executable(NATIVE_EXECUTABLE_NAME, listOf(RELEASE)) {
|
||||
if (HostManager.hostIsMingw) {
|
||||
linkerOpts.add("-L${mingwPath}/lib")
|
||||
}
|
||||
|
||||
runTask!!.apply {
|
||||
group = ""
|
||||
enabled = false
|
||||
}
|
||||
|
||||
// Specify settings configured by a user in the benchmark extension.
|
||||
project.afterEvaluate {
|
||||
linkerOpts.addAll(project.benchmark.linkerOpts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.configureNativeTarget(hostPreset: KotlinNativeTargetPreset) {
|
||||
protected open fun Project.configureNativeTarget(hostPreset: KotlinNativeTargetPreset) {
|
||||
kotlin.targetFromPreset(hostPreset, NATIVE_TARGET_NAME) {
|
||||
compilations.getByName("main").kotlinOptions.freeCompilerArgs = project.compilerArgs
|
||||
compilations.getByName("main").enableEndorsedLibs = true
|
||||
binaries.executable(NATIVE_EXECUTABLE_NAME, listOf(RELEASE)) {
|
||||
if (HostManager.hostIsMingw) {
|
||||
linkerOpts.add("-L${mingwPath}/lib")
|
||||
}
|
||||
|
||||
runTask!!.apply {
|
||||
group = ""
|
||||
enabled = false
|
||||
}
|
||||
|
||||
// Specify settings configured by a user in the benchmark extension.
|
||||
afterEvaluate {
|
||||
linkerOpts.addAll(benchmark.linkerOpts)
|
||||
}
|
||||
}
|
||||
configureNativeOutput(this@configureNativeTarget)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun Project.configureMPPExtension() {
|
||||
configureSourceSets(kotlinVersion)
|
||||
configureJVMTarget()
|
||||
configureNativeTarget(determinePreset())
|
||||
protected open fun configureMPPExtension(project: Project) {
|
||||
project.configureSourceSets(project.kotlinVersion)
|
||||
project.configureNativeTarget(project.determinePreset())
|
||||
}
|
||||
|
||||
|
||||
private fun Project.configureTasks() {
|
||||
// Native run task.
|
||||
val nativeTarget = kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget
|
||||
val nativeExecutable = nativeTarget.binaries.getExecutable(NATIVE_EXECUTABLE_NAME, NativeBuildType.RELEASE)
|
||||
val konanRun = createRunTask(this, "konanRun", nativeExecutable.linkTask,
|
||||
buildDir.resolve(nativeBenchResults).absolutePath).apply {
|
||||
protected open fun Project.configureNativeTask(nativeTarget: KotlinNativeTarget): Task {
|
||||
val konanRun = createRunTask(this, "konanRun", nativeLinkTask,
|
||||
nativeExecutable, buildDir.resolve(nativeBenchResults).absolutePath).apply {
|
||||
group = BENCHMARKING_GROUP
|
||||
description = "Runs the benchmark for Kotlin/Native."
|
||||
}
|
||||
@@ -217,80 +184,61 @@ open class BenchmarkingPlugin: Plugin<Project> {
|
||||
"-p", "${benchmark.applicationName}::"
|
||||
)
|
||||
}
|
||||
return konanRun
|
||||
}
|
||||
|
||||
// JVM run task.
|
||||
val jvmRun = tasks.create("jvmRun", RunJvmTask::class.java) { task ->
|
||||
task.dependsOn("build")
|
||||
val mainCompilation = kotlin.jvm().compilations.getByName("main")
|
||||
val runtimeDependencies = configurations.getByName(mainCompilation.runtimeDependencyConfigurationName)
|
||||
task.classpath(files(mainCompilation.output.allOutputs, runtimeDependencies))
|
||||
task.main = "MainKt"
|
||||
protected abstract fun Project.configureJvmTask(): Task
|
||||
|
||||
task.group = BENCHMARKING_GROUP
|
||||
task.description = "Runs the benchmark for Kotlin/JVM."
|
||||
protected open fun Project.getCompilerFlags(nativeTarget: KotlinNativeTarget) =
|
||||
nativeTarget.compilations.main.kotlinOptions.freeCompilerArgs.map { "\"$it\"" }
|
||||
|
||||
// Specify settings configured by a user in the benchmark extension.
|
||||
afterEvaluate {
|
||||
task.args(
|
||||
"-w", jvmWarmup,
|
||||
"-r", attempts,
|
||||
"-o", buildDir.resolve(jvmBenchResults),
|
||||
"-p", "${benchmark.applicationName}::"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Native report task.
|
||||
val konanJsonReport = tasks.create("konanJsonReport") {
|
||||
protected open fun Project.collectCodeSize(applicationName: String) =
|
||||
getCodeSizeBenchmark(applicationName, nativeExecutable)
|
||||
|
||||
protected open fun Project.configureKonanJsonTask(nativeTarget: KotlinNativeTarget): Task {
|
||||
return tasks.create("konanJsonReport") {
|
||||
it.group = BENCHMARKING_GROUP
|
||||
it.description = "Builds the benchmarking report for Kotlin/Native."
|
||||
|
||||
it.doLast {
|
||||
val applicationName = benchmark.applicationName
|
||||
val nativeCompileTime = getNativeCompileTime(applicationName)
|
||||
val benchContents = buildDir.resolve(nativeBenchResults).readText()
|
||||
val nativeCompileTime = if (benchmark.compileTasks.isEmpty()) getNativeCompileTime(applicationName)
|
||||
else getNativeCompileTime(applicationName, benchmark.compileTasks)
|
||||
|
||||
val properties = commonBenchmarkProperties + mapOf(
|
||||
"type" to "native",
|
||||
"compilerVersion" to konanVersion,
|
||||
"flags" to nativeTarget.compilations.main.kotlinOptions.freeCompilerArgs.map { "\"$it\"" },
|
||||
"benchmarks" to benchContents,
|
||||
"compileTime" to listOf(nativeCompileTime),
|
||||
"codeSize" to getCodeSizeBenchmark(applicationName, nativeExecutable.outputFile.absolutePath)
|
||||
"type" to "native",
|
||||
"compilerVersion" to konanVersion,
|
||||
"flags" to getCompilerFlags(nativeTarget),
|
||||
"benchmarks" to benchContents,
|
||||
"compileTime" to listOf(nativeCompileTime),
|
||||
"codeSize" to collectCodeSize(applicationName)
|
||||
)
|
||||
|
||||
val output = createJsonReport(properties)
|
||||
buildDir.resolve(nativeJson).writeText(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun Project.configureJvmJsonTask(jvmRun: Task): Task
|
||||
|
||||
protected open fun Project.configureExtraTasks() {}
|
||||
|
||||
private fun Project.configureTasks() {
|
||||
val nativeTarget = kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget
|
||||
configureExtraTasks()
|
||||
// Native run task.
|
||||
configureNativeTask(nativeTarget)
|
||||
|
||||
// JVM run task.
|
||||
val jvmRun = configureJvmTask()
|
||||
|
||||
// Native report task.
|
||||
configureKonanJsonTask(nativeTarget)
|
||||
|
||||
// JVM report task.
|
||||
val jvmJsonReport = tasks.create("jvmJsonReport") {
|
||||
|
||||
it.group = BENCHMARKING_GROUP
|
||||
it.description = "Builds the benchmarking report for Kotlin/JVM."
|
||||
|
||||
it.doLast {
|
||||
val applicationName = benchmark.applicationName
|
||||
val jarPath = (tasks.getByName("jvmJar") as Jar).archiveFile.get().asFile
|
||||
val jvmCompileTime = getJvmCompileTime(applicationName)
|
||||
val benchContents = buildDir.resolve(jvmBenchResults).readText()
|
||||
|
||||
val properties: Map<String, Any> = commonBenchmarkProperties + mapOf(
|
||||
"type" to "jvm",
|
||||
"compilerVersion" to kotlinVersion,
|
||||
"benchmarks" to benchContents,
|
||||
"compileTime" to listOf(jvmCompileTime),
|
||||
"codeSize" to getCodeSizeBenchmark(applicationName, jarPath.absolutePath)
|
||||
)
|
||||
|
||||
val output = createJsonReport(properties)
|
||||
buildDir.resolve(jvmJson).writeText(output)
|
||||
}
|
||||
|
||||
jvmRun.finalizedBy(it)
|
||||
}
|
||||
configureJvmJsonTask(jvmRun)
|
||||
}
|
||||
|
||||
override fun apply(target: Project) = with(target) {
|
||||
@@ -298,18 +246,16 @@ open class BenchmarkingPlugin: Plugin<Project> {
|
||||
|
||||
// Use Kotlin compiler version specified by the project property.
|
||||
dependencies.add("kotlinCompilerClasspath", "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlinVersion")
|
||||
|
||||
extensions.create(BENCHMARK_EXTENSION_NAME, BenchmarkExtension::class.java, this)
|
||||
configureMPPExtension()
|
||||
addTimeListener(this)
|
||||
|
||||
extensions.create(benchmarkExtensionName, benchmarkExtensionClass.java, this)
|
||||
configureMPPExtension(this)
|
||||
configureTasks()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NATIVE_TARGET_NAME = "native"
|
||||
const val NATIVE_EXECUTABLE_NAME = "benchmark"
|
||||
const val BENCHMARK_EXTENSION_NAME = "benchmark"
|
||||
|
||||
const val BENCHMARKING_GROUP = "benchmarking"
|
||||
}
|
||||
}
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package org.jetbrains.kotlin.benchmark
|
||||
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Executable
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private val NamedDomainObjectContainer<KotlinSourceSet>.jvmMain
|
||||
get() = maybeCreate("jvmMain")
|
||||
|
||||
private val Project.jvmWarmup: Int
|
||||
get() = (property("jvmWarmup") as String).toInt()
|
||||
|
||||
private val Project.jvmBenchResults: String
|
||||
get() = property("jvmBenchResults") as String
|
||||
|
||||
open class KotlinNativeBenchmarkExtension @Inject constructor(project: Project) : BenchmarkExtension(project) {
|
||||
var jvmSrcDirs: Collection<Any> = emptyList()
|
||||
var mingwSrcDirs: Collection<Any> = emptyList()
|
||||
var posixSrcDirs: Collection<Any> = emptyList()
|
||||
|
||||
fun BenchmarkExtension.BenchmarkDependencies.jvm(notation: Any) = sourceSets.jvmMain.dependencies {
|
||||
implementation(notation)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A plugin configuring a benchmark Kotlin/Native project.
|
||||
*/
|
||||
open class KotlinNativeBenchmarkingPlugin: BenchmarkingPlugin() {
|
||||
override fun Project.configureJvmJsonTask(jvmRun: Task): Task {
|
||||
return tasks.create("jvmJsonReport") {
|
||||
it.group = BENCHMARKING_GROUP
|
||||
it.description = "Builds the benchmarking report for Kotlin/JVM."
|
||||
|
||||
it.doLast {
|
||||
val applicationName = benchmark.applicationName
|
||||
val jarPath = (tasks.getByName("jvmJar") as Jar).archiveFile.get().asFile
|
||||
val jvmCompileTime = getJvmCompileTime(applicationName)
|
||||
val benchContents = buildDir.resolve(jvmBenchResults).readText()
|
||||
|
||||
val properties: Map<String, Any> = commonBenchmarkProperties + mapOf(
|
||||
"type" to "jvm",
|
||||
"compilerVersion" to kotlinVersion,
|
||||
"benchmarks" to benchContents,
|
||||
"compileTime" to listOf(jvmCompileTime),
|
||||
"codeSize" to getCodeSizeBenchmark(applicationName, jarPath.absolutePath)
|
||||
)
|
||||
|
||||
val output = createJsonReport(properties)
|
||||
buildDir.resolve(jvmJson).writeText(output)
|
||||
}
|
||||
|
||||
jvmRun.finalizedBy(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun Project.configureJvmTask(): Task {
|
||||
return tasks.create("jvmRun", RunJvmTask::class.java) { task ->
|
||||
task.dependsOn("build")
|
||||
val mainCompilation = kotlin.jvm().compilations.getByName("main")
|
||||
val runtimeDependencies = configurations.getByName(mainCompilation.runtimeDependencyConfigurationName)
|
||||
task.classpath(files(mainCompilation.output.allOutputs, runtimeDependencies))
|
||||
task.main = "MainKt"
|
||||
|
||||
task.group = BENCHMARKING_GROUP
|
||||
task.description = "Runs the benchmark for Kotlin/JVM."
|
||||
|
||||
// Specify settings configured by a user in the benchmark extension.
|
||||
afterEvaluate {
|
||||
task.args(
|
||||
"-w", jvmWarmup,
|
||||
"-r", attempts,
|
||||
"-o", buildDir.resolve(jvmBenchResults),
|
||||
"-p", "${benchmark.applicationName}::"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val benchmarkExtensionClass: KClass<*>
|
||||
get() = KotlinNativeBenchmarkExtension::class
|
||||
|
||||
override val Project.benchmark: KotlinNativeBenchmarkExtension
|
||||
get() = extensions.getByName(benchmarkExtensionName) as KotlinNativeBenchmarkExtension
|
||||
|
||||
override val benchmarkExtensionName: String = "benchmark"
|
||||
|
||||
private val Project.nativeBinary: Executable
|
||||
get() = (kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget)
|
||||
.binaries.getExecutable(NATIVE_EXECUTABLE_NAME, NativeBuildType.RELEASE)
|
||||
|
||||
override val Project.nativeExecutable: String
|
||||
get() = nativeBinary.outputFile.absolutePath
|
||||
|
||||
override val Project.nativeLinkTask: Task
|
||||
get() = nativeBinary.linkTask
|
||||
|
||||
override fun configureMPPExtension(project: Project) {
|
||||
super.configureMPPExtension(project)
|
||||
project.configureJVMTarget()
|
||||
}
|
||||
|
||||
override fun NamedDomainObjectContainer<KotlinSourceSet>.configureSources(project: Project) {
|
||||
project.benchmark.let {
|
||||
commonMain.kotlin.srcDirs(*it.commonSrcDirs.toTypedArray())
|
||||
if (HostManager.hostIsMingw) {
|
||||
nativeMain.kotlin.srcDirs(*(it.nativeSrcDirs + it.mingwSrcDirs).toTypedArray())
|
||||
} else {
|
||||
nativeMain.kotlin.srcDirs(*(it.nativeSrcDirs + it.posixSrcDirs).toTypedArray())
|
||||
}
|
||||
jvmMain.kotlin.srcDirs(*it.jvmSrcDirs.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
override fun NamedDomainObjectContainer<KotlinSourceSet>.additionalConfigurations(project: Project) {
|
||||
jvmMain.dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${project.kotlinStdlibVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.configureJVMTarget() {
|
||||
kotlin.jvm {
|
||||
compilations.all {
|
||||
it.compileKotlinTask.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
suppressWarnings = true
|
||||
freeCompilerArgs = project.compilerArgs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BENCHMARK_EXTENSION_NAME = "benchmark"
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package org.jetbrains.kotlin.benchmark
|
||||
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetPreset
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import java.nio.file.Paths
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
enum class CodeSizeEntity { FRAMEWORK, EXECUTABLE }
|
||||
|
||||
open class SwiftBenchmarkExtension @Inject constructor(project: Project) : BenchmarkExtension(project) {
|
||||
var swiftSources: List<String> = emptyList()
|
||||
var useCodeSize: CodeSizeEntity = CodeSizeEntity.FRAMEWORK // use as code size metric framework size or executable
|
||||
}
|
||||
|
||||
/**
|
||||
* A plugin configuring a benchmark Kotlin/Native project.
|
||||
*/
|
||||
open class SwiftBenchmarkingPlugin : BenchmarkingPlugin() {
|
||||
override fun Project.configureJvmJsonTask(jvmRun: Task): Task {
|
||||
return tasks.create("jvmJsonReport") {
|
||||
logger.info("JVM run is unsupported")
|
||||
jvmRun.finalizedBy(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun Project.configureJvmTask(): Task {
|
||||
return tasks.create("jvmRun") { task ->
|
||||
task.doLast {
|
||||
logger.info("JVM run is unsupported")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val benchmarkExtensionClass: KClass<*>
|
||||
get() = SwiftBenchmarkExtension::class
|
||||
|
||||
override val Project.benchmark: SwiftBenchmarkExtension
|
||||
get() = extensions.getByName(benchmarkExtensionName) as SwiftBenchmarkExtension
|
||||
|
||||
override val benchmarkExtensionName: String = "swiftBenchmark"
|
||||
|
||||
override val Project.nativeExecutable: String
|
||||
get() = Paths.get(buildDir.absolutePath, benchmark.applicationName).toString()
|
||||
|
||||
override val Project.nativeLinkTask: Task
|
||||
get() = tasks.getByName("buildSwift")
|
||||
|
||||
private lateinit var framework: Framework
|
||||
val nativeFrameworkName = "benchmark"
|
||||
|
||||
override fun NamedDomainObjectContainer<KotlinSourceSet>.configureSources(project: Project) {
|
||||
project.benchmark.let {
|
||||
commonMain.kotlin.srcDirs(*it.commonSrcDirs.toTypedArray())
|
||||
nativeMain.kotlin.srcDirs(*(it.nativeSrcDirs).toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
override fun Project.determinePreset(): KotlinNativeTargetPreset = kotlin.presets.macosX64 as KotlinNativeTargetPreset
|
||||
|
||||
override fun KotlinNativeTarget.configureNativeOutput(project: Project) {
|
||||
binaries.framework(nativeFrameworkName, listOf(RELEASE)) {
|
||||
// Specify settings configured by a user in the benchmark extension.
|
||||
project.afterEvaluate {
|
||||
linkerOpts.addAll(project.benchmark.linkerOpts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun Project.configureExtraTasks() {
|
||||
val nativeTarget = kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget
|
||||
// Build executable from swift code.
|
||||
framework = nativeTarget.binaries.getFramework(nativeFrameworkName, NativeBuildType.RELEASE)
|
||||
val buildSwift = tasks.create("buildSwift") { task ->
|
||||
task.dependsOn(framework.linkTaskName)
|
||||
task.doLast {
|
||||
val frameworkParentDirPath = framework.outputDirectory.absolutePath
|
||||
val options = listOf("-Xlinker", "-rpath", "-Xlinker", frameworkParentDirPath, "-F", frameworkParentDirPath)
|
||||
compileSwift(project, nativeTarget.konanTarget, benchmark.swiftSources, options,
|
||||
Paths.get(buildDir.absolutePath, benchmark.applicationName), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun Project.collectCodeSize(applicationName: String) =
|
||||
getCodeSizeBenchmark(applicationName,
|
||||
if (benchmark.useCodeSize == CodeSizeEntity.FRAMEWORK)
|
||||
File("${framework.outputFile.absolutePath}/$nativeFrameworkName").canonicalPath
|
||||
else
|
||||
nativeExecutable
|
||||
)
|
||||
|
||||
override fun Project.getCompilerFlags(nativeTarget: KotlinNativeTarget) =
|
||||
listOf<String>()
|
||||
}
|
||||
@@ -56,7 +56,6 @@ abstract class Launcher {
|
||||
} else {
|
||||
printStderr("$message")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
import org.jetbrains.kotlin.MPPTools
|
||||
import org.jetbrains.kotlin.PlatformInfo
|
||||
import org.jetbrains.kotlin.RunJvmTask
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.UtilsKt
|
||||
import java.nio.file.Paths
|
||||
|
||||
buildscript {
|
||||
apply from: "$rootProject.projectDir/gradle/kotlinGradlePlugin.gradle"
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://cache-redirector.jetbrains.com/jcenter'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-multiplatform'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://cache-redirector.jetbrains.com/jcenter'
|
||||
}
|
||||
maven {
|
||||
url kotlinCompilerRepo
|
||||
}
|
||||
maven {
|
||||
url buildKotlinCompilerRepo
|
||||
}
|
||||
}
|
||||
|
||||
def toolsPath = '../../tools'
|
||||
def frameworkName = 'CityMap'
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
||||
implementation project(":endorsedLibraries:kotlinx.cli")
|
||||
}
|
||||
kotlin.srcDir "src"
|
||||
kotlin.srcDir "../shared/src/main/kotlin"
|
||||
kotlin.srcDir "$toolsPath/benchmarks/shared/src/main/kotlin"
|
||||
}
|
||||
macosMain {
|
||||
dependsOn commonMain
|
||||
kotlin.srcDir "../shared/src/main/kotlin-native/common"
|
||||
kotlin.srcDir "../shared/src/main/kotlin-native/posix"
|
||||
|
||||
// Exclude kotlinx.cli added in commonMain dependencies and inherited by macosMain.
|
||||
configurations.getByName(implementationConfigurationName) {
|
||||
exclude module: "kotlinx.cli"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macosX64("macos") {
|
||||
compilations.main.kotlinOptions.freeCompilerArgs = (project.hasProperty('compilerArgs') ? compilerArgs.split() : [])
|
||||
compilations.main.enableEndorsedLibs = true
|
||||
binaries {
|
||||
framework(frameworkName, [RELEASE])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MPPTools.addTimeListener(project)
|
||||
|
||||
build.finalizedBy 'buildSwift'
|
||||
|
||||
defaultTasks 'konanRun'
|
||||
|
||||
def applicationName = "swiftInterop"
|
||||
def swiftExecutable = Paths.get(buildDir.absolutePath, applicationName)
|
||||
|
||||
if (PlatformInfo.isAppleTarget(HostManager.host)) {
|
||||
MPPTools.createBenchmarksRunTask(project, 'konanRun') {
|
||||
workingDir = project.provider { buildDir }
|
||||
executable = swiftExecutable
|
||||
depends("build")
|
||||
args("-w", "$nativeWarmup", "-r", "$attempts", "-o", "${buildDir.absolutePath}/${nativeBenchResults}", "-p", "${applicationName}::")
|
||||
}
|
||||
}
|
||||
|
||||
def framework = null
|
||||
if (PlatformInfo.isMac()) {
|
||||
framework = kotlin.targets.macos.binaries.getFramework(frameworkName, 'RELEASE')
|
||||
} else {
|
||||
framework = kotlin.targets.ios.binaries.getFramework(frameworkName, 'RELEASE')
|
||||
}
|
||||
|
||||
task buildSwift {
|
||||
doLast {
|
||||
def frameworkParentDirPath = framework.outputDirectory
|
||||
def sources = ["$projectDir/swiftSrc/benchmarks.swift".toString(), "$projectDir/swiftSrc/main.swift".toString()]
|
||||
def options = ['-g', '-Xlinker', '-rpath', '-Xlinker', frameworkParentDirPath, '-F', frameworkParentDirPath]
|
||||
UtilsKt.compileSwift(project, HostManager.host, sources, options, swiftExecutable, false)
|
||||
}
|
||||
}
|
||||
|
||||
task jvmRun(type: RunJvmTask) {
|
||||
doLast {
|
||||
println("JVM run is unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
private def getCommonProperties() {
|
||||
return ['cpu': System.getProperty("os.arch"),
|
||||
'os': System.getProperty("os.name"), // OperatingSystem.current().getName()
|
||||
'jdkVersion': System.getProperty("java.version"), // org.gradle.internal.jvm.Jvm.current().javaVersion
|
||||
'jdkVendor': System.getProperty("java.vendor"),
|
||||
'kotlinVersion': "${kotlinVersion}".toString()]
|
||||
}
|
||||
|
||||
task konanJsonReport {
|
||||
doLast {
|
||||
if (PlatformInfo.isAppleTarget(HostManager.host)) {
|
||||
def targetExtension = ""
|
||||
if (PlatformInfo.isMac()) {
|
||||
targetExtension = "Macos"
|
||||
} else {
|
||||
targetExtension = "Ios"
|
||||
}
|
||||
|
||||
def frameworkPath = framework.outputFile.absolutePath
|
||||
def nativeFramework = new File("$frameworkPath/$frameworkName").canonicalPath
|
||||
def nativeCompileTime = MPPTools.getNativeCompileTime(applicationName, ["compileKotlin${targetExtension}".toString(),
|
||||
"link${frameworkName}ReleaseFramework${targetExtension}".toString()])
|
||||
|
||||
String benchContents = new File("${buildDir.absolutePath}/${nativeBenchResults}").text
|
||||
def properties = getCommonProperties() + ['type' : 'native',
|
||||
'compilerVersion': "${konanVersion}".toString(),
|
||||
'flags' : kotlin.targets.macos.compilations.main.extraOpts.collect{ "\"$it\"" },
|
||||
'benchmarks' : benchContents,
|
||||
'compileTime' : [nativeCompileTime],
|
||||
'codeSize' : MPPTools.getCodeSizeBenchmark(applicationName, nativeFramework)]
|
||||
def output = MPPTools.createJsonReport(properties)
|
||||
new File("${buildDir.absolutePath}/${nativeJson}").write(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task jvmJsonReport {
|
||||
doLast {
|
||||
println("JVM run is unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
konanRun.finalizedBy 'konanJsonReport'
|
||||
jvmRun.finalizedBy 'jvmJsonReport'
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("swift-benchmarking")
|
||||
}
|
||||
|
||||
val toolsPath = "../../tools"
|
||||
|
||||
swiftBenchmark {
|
||||
applicationName = "swiftInterop"
|
||||
commonSrcDirs = listOf("$toolsPath/benchmarks/shared/src/main/kotlin", "src", "../shared/src/main/kotlin")
|
||||
nativeSrcDirs = listOf("../shared/src/main/kotlin-native/common", "../shared/src/main/kotlin-native/posix")
|
||||
swiftSources = listOf("$projectDir/swiftSrc/benchmarks.swift", "$projectDir/swiftSrc/main.swift")
|
||||
compileTasks = listOf("compileKotlinNative", "linkBenchmarkReleaseFrameworkNative")
|
||||
|
||||
dependencies.common(project(":endorsedLibraries:kotlinx.cli"))
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import CityMap
|
||||
import benchmark
|
||||
|
||||
class SimpleCost: Cost {
|
||||
let value: Int
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import CityMap
|
||||
import benchmark
|
||||
|
||||
var runner = BenchmarksRunner()
|
||||
let args = KotlinArray(size: Int32(CommandLine.arguments.count - 1), init: {index in
|
||||
@@ -14,9 +14,7 @@ let args = KotlinArray(size: Int32(CommandLine.arguments.count - 1), init: {inde
|
||||
let companion = BenchmarkEntryWithInit.Companion()
|
||||
|
||||
var swiftLauncher = SwiftLauncher()
|
||||
|
||||
runner.runBenchmarks(args: args, run: { (arguments: BenchmarkArguments) -> [BenchmarkResult] in
|
||||
swiftLauncher.add(name: "createMultigraphOfInt", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
|
||||
swiftLauncher.add(name: "createMultigraphOfInt", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
|
||||
lambda: { ($0 as! SwiftInteropBenchmarks).createMultigraphOfInt() }))
|
||||
swiftLauncher.add(name: "fillCityMap", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
|
||||
lambda: { ($0 as! SwiftInteropBenchmarks).fillCityMap() }))
|
||||
@@ -38,6 +36,7 @@ runner.runBenchmarks(args: args, run: { (arguments: BenchmarkArguments) -> [Benc
|
||||
lambda: { ($0 as! SwiftInteropBenchmarks).stringInterop() }))
|
||||
swiftLauncher.add(name: "simpleFunction", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
|
||||
lambda: { ($0 as! SwiftInteropBenchmarks).simpleFunction() }))
|
||||
runner.runBenchmarks(args: args, run: { (arguments: BenchmarkArguments) -> [BenchmarkResult] in
|
||||
if arguments is BaseBenchmarkArguments {
|
||||
let argumentsList: BaseBenchmarkArguments = arguments as! BaseBenchmarkArguments
|
||||
return swiftLauncher.launch(numWarmIterations: argumentsList.warmup,
|
||||
|
||||
Reference in New Issue
Block a user