diff --git a/buildSrc/plugins/build.gradle b/buildSrc/plugins/build.gradle index 05122d2ec8f..7c77177becb 100644 --- a/buildSrc/plugins/build.gradle +++ b/buildSrc/plugins/build.gradle @@ -30,6 +30,7 @@ buildscript { apply plugin: 'kotlin' apply plugin: 'kotlinx-serialization' +apply plugin: 'java-gradle-plugin' /* don't use repositories: gradle will ignore it anyway, but may confuse gradle build engineer, see outer build.gradle */ @@ -57,4 +58,13 @@ rootProject.dependencies { compileGroovy { // Add Kotlin classes to a classpath for the Groovy compiler classpath += project.files(compileKotlin.destinationDir) -} \ No newline at end of file +} + +gradlePlugin { + plugins { + benchmarkPlugin { + id = 'benchmarking' + implementationClass = 'org.jetbrains.kotlin.benchmark.BenchmarkingPlugin' + } + } +} diff --git a/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/ExecClang.kt b/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/ExecClang.kt index 9950e710302..68b6df12ce0 100644 --- a/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/ExecClang.kt +++ b/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/ExecClang.kt @@ -26,7 +26,7 @@ import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.file.* -internal class ExecClang(private val project: Project) { +class ExecClang(private val project: Project) { private val platformManager = project.rootProject.findProperty("platformManager") as PlatformManager diff --git a/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt b/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt index 4f6fb5c033c..93f9a667607 100644 --- a/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt +++ b/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt @@ -69,9 +69,6 @@ fun getNativeProgramExtension(): String = when { else -> error("Unknown host") } -fun getKotlinNativeExecutable(target: KotlinNativeTarget, buildType: String) = - target.binaries.getExecutable("benchmark", buildType).outputFile.getAbsolutePath() - fun getFileSize(filePath: String): Long? { val file = File(filePath) return if (file.exists()) file.length() else null diff --git a/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/benchmark/BenchmarkingPlugin.kt b/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/benchmark/BenchmarkingPlugin.kt new file mode 100644 index 00000000000..177bb5d0b02 --- /dev/null +++ b/buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/benchmark/BenchmarkingPlugin.kt @@ -0,0 +1,231 @@ +package org.jetbrains.kotlin.benchmark + +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.jvm.tasks.Jar +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 + +private val NamedDomainObjectContainer.commonMain + get() = maybeCreate("commonMain") + +private val NamedDomainObjectContainer.nativeMain + get() = maybeCreate("nativeMain") + +private val NamedDomainObjectContainer.jvmMain + get() = maybeCreate("jvmMain") + +private val Project.benchmark: BenchmarkExtension + get() = extensions.getByName(BenchmarkingPlugin.BENCHMARK_EXTENSION_NAME) as BenchmarkExtension + +private 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 + get() = (property("attempts") as String).toInt() + +private val Project.nativeBenchResults: String + get() = property("nativeBenchResults") as String + +private val Project.jvmBenchResults: String + get() = property("jvmBenchResults") as String + +private val Project.compilerArgs: List + get() = (findProperty("compilerArgs") as String?)?.split("\\s").orEmpty() + +internal val Project.kotlinVersion: String + get() = property("kotlinVersion") as String + +internal val Project.konanVersion: String + get() = property("konanVersion") as String + +internal val Project.nativeJson: String + get() = project.property("nativeJson") as String + +internal val Project.commonBenchmarkProperties: Map + get() = mapOf( + "cpu" to System.getProperty("os.arch"), + "os" to System.getProperty("os.name"), + "jdkVersion" to System.getProperty("java.version"), + "jdkVendor" to System.getProperty("java.vendor"), + "kotlinVersion" to kotlinVersion + ) + +open class BenchmarkExtension @Inject constructor(val project: Project) { + var applicationName: String = project.name + var commonSrcDirs: Collection = emptyList() + var jvmSrcDirs: Collection = emptyList() + var nativeSrcDirs: Collection = emptyList() + var linkerOpts: Collection = emptyList() +} + +/** + * A plugin configuring a benchmark Kotlin/Native project. + */ +open class BenchmarkingPlugin: Plugin { + + private val mingwPath: String = System.getenv("MINGW64_DIR") ?: "c:/msys64/mingw64" + + private 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) { + with(kotlin.sourceSets) { + commonMain.dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion") + } + + jvmMain.dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") + } + + // Add sources specified by a user in the benchmark DSL. + afterEvaluate { + benchmark.let { + commonMain.kotlin.srcDirs(*it.commonSrcDirs.toTypedArray()) + nativeMain.kotlin.srcDirs(*it.nativeSrcDirs.toTypedArray()) + jvmMain.kotlin.srcDirs(*it.jvmSrcDirs.toTypedArray()) + } + } + } + } + + private fun Project.configureJVMTarget() { + kotlin.jvm { + compilations.all { + it.compileKotlinTask.kotlinOptions { + jvmTarget = "1.8" + suppressWarnings = true + freeCompilerArgs = project.compilerArgs + } + } + } + } + + private fun Project.configureNativeTarget(hostPreset: KotlinNativeTargetPreset) { + kotlin.targetFromPreset(hostPreset, NATIVE_TARGET_NAME) { + compilations.getByName("main").kotlinOptions.freeCompilerArgs = project.compilerArgs + "-opt" + binaries.executable(NATIVE_EXECUTABLE_NAME, listOf(RELEASE)) { + if (HostManager.hostIsMingw) { + linkerOpts.add("-L${mingwPath}/lib") + } + + // Specify settings configured by a user in the benchmark extension. + afterEvaluate { + linkerOpts.addAll(benchmark.linkerOpts) + runTask!!.args( + "-w", nativeWarmup, + "-r", attempts, + "-o", buildDir.resolve(nativeBenchResults).absolutePath, + "-p", "${benchmark.applicationName}::" + ) + } + + } + } + } + + + private fun Project.configureMPPExtension() { + configureSourceSets(kotlinVersion) + configureJVMTarget() + configureNativeTarget(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.runTask!!) + + // 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" + + // 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") { + it.doLast { + val applicationName = benchmark.applicationName + val nativeCompileTime = getNativeCompileTime(applicationName) + val benchContents = buildDir.resolve(nativeBenchResults).readText() + + 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) + ) + + val output = createJsonReport(properties) + buildDir.resolve(nativeJson).writeText(output) + } + } + + // JVM report task. + val jvmJsonReport = tasks.create("jvmJsonReport") { + 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 = commonBenchmarkProperties + mapOf( + "type" to "jvm", + // TODO: We had buildKotlinVersion here!!!! + "compilerVersion" to kotlinVersion, + "benchmarks" to benchContents, + "compileTime" to listOf(jvmCompileTime), + "codeSize" to getCodeSizeBenchmark(applicationName, jarPath.absolutePath) + ) + + val output = createJsonReport(properties) + buildDir.resolve(project.property("jvmJson") as String).writeText(output) + } + + jvmRun.finalizedBy(it) + } + } + + override fun apply(target: Project) = with(target) { + pluginManager.apply("kotlin-multiplatform") + extensions.create(BENCHMARK_EXTENSION_NAME, BenchmarkExtension::class.java, this) + configureMPPExtension() + addTimeListener(this) + configureTasks() + } + + companion object { + const val NATIVE_TARGET_NAME = "native" + const val NATIVE_EXECUTABLE_NAME = "benchmark" + const val BENCHMARK_EXTENSION_NAME = "benchmark" + } +} diff --git a/performance/cinterop/build.gradle b/performance/cinterop/build.gradle deleted file mode 100644 index 7224630f6bf..00000000000 --- a/performance/cinterop/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -project.ext { - applicationName = 'Cinterop' - commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt'] - jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm'] - nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native'] -} -apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/benchmark.gradle") -kotlin.targets.native.compilations.main.cinterops { - macros - struct - types -} \ No newline at end of file diff --git a/performance/cinterop/build.gradle.kts b/performance/cinterop/build.gradle.kts new file mode 100644 index 00000000000..79e6b4568d6 --- /dev/null +++ b/performance/cinterop/build.gradle.kts @@ -0,0 +1,24 @@ +/* + * 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.gradle.plugin.mpp.KotlinNativeTarget + +plugins { + id("benchmarking") +} + +benchmark { + applicationName = "Cinterop" + commonSrcDirs = listOf("../../tools/benchmarks/shared/src", "src/main/kotlin", "../shared/src/main/kotlin", "../../tools/kliopt") + jvmSrcDirs = listOf("src/main/kotlin-jvm", "../shared/src/main/kotlin-jvm") + nativeSrcDirs = listOf("src/main/kotlin-native", "../shared/src/main/kotlin-native") +} + +val native = kotlin.targets.getByName("native") as KotlinNativeTarget +native.compilations["main"].cinterops { + create("macros") + create("struct") + create("types") +} diff --git a/performance/gradle/benchmark.gradle b/performance/gradle/benchmark.gradle deleted file mode 100644 index 05b538631c2..00000000000 --- a/performance/gradle/benchmark.gradle +++ /dev/null @@ -1,141 +0,0 @@ -import org.jetbrains.kotlin.MPPTools -import org.jetbrains.kotlin.RunJvmTask - -apply plugin: 'kotlin-multiplatform' - -repositories { - maven { - url 'https://cache-redirector.jetbrains.com/jcenter' - } - maven { - url kotlinCompilerRepo - } - maven { - url buildKotlinCompilerRepo - } - -} - -private def determinePreset() { - def preset = MPPTools.defaultHostPreset(project) - println("$project has been configured for ${preset.name} platform.") - preset -} - -def getMingwPath() { - def directory = System.getenv("MINGW64_DIR") - if (directory == null) - directory = "c:/msys64/mingw64" - return directory -} - -def hostPreset = determinePreset() - -kotlin { - sourceSets { - commonMain { - dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion" - } - project.ext.commonSrcDirs.forEach { - kotlin.srcDir it - } - - } - nativeMain { - project.ext.nativeSrcDirs.forEach { - kotlin.srcDir it - } - } - jvmMain { - dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" - } - project.ext.jvmSrcDirs.forEach { - kotlin.srcDir it - } - } - } - - - jvm() { - compilations.all { - tasks[compileKotlinTaskName].kotlinOptions { - jvmTarget = '1.8' - suppressWarnings = true - freeCompilerArgs = (project.hasProperty('compilerArgs') ? compilerArgs.split() : []) - } - } - } - - targetFromPreset(hostPreset, 'native') { - compilations.main.extraOpts = (project.hasProperty('compilerArgs') ? compilerArgs.split() : []) + '-opt' - binaries { - executable('benchmark', [RELEASE]) { - if (project.hasProperty("linkerOpts")) { - linkerOpts = project.ext.linkerOpts - } - if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { - linkerOpts += ["-L${getMingwPath()}/lib".toString()] - } - runTask.args("-w", "$nativeWarmup", "-r", "$attempts", "-o", "${buildDir.absolutePath}/${nativeBenchResults}", "-p", "${project.ext.applicationName}::") - } - } - } -} - -MPPTools.addTimeListener(project) -MPPTools.createRunTask(project, 'konanRun', kotlin.targets.native.binaries.getExecutable("benchmark", "RELEASE").runTask) - -task jvmRun(type: RunJvmTask) { - dependsOn 'build' - def runtimeClasspath = files( - kotlin.targets.jvm.compilations.main.output.allOutputs, - project.configurations.getByName(kotlin.targets.jvm.compilations.main.runtimeDependencyConfigurationName) - ) - classpath runtimeClasspath - main = "MainKt" - args "-w", "$jvmWarmup", "-r", "$attempts", "-o", "${buildDir.absolutePath}/${jvmBenchResults}", "-p", "${project.ext.applicationName}::" -} - -task konanJsonReport { - doLast { - def nativeExecutable = MPPTools.getKotlinNativeExecutable(kotlin.targets.native, "RELEASE") - def nativeCompileTime = MPPTools.getNativeCompileTime(project.ext.applicationName) - String benchContents = new File("${buildDir.absolutePath}/${nativeBenchResults}").text - def properties = getCommonProperties() + ['type': 'native', - 'compilerVersion': "${konanVersion}".toString(), - 'flags': kotlin.targets.native.compilations.main.extraOpts.collect{ "\"$it\"" }, - 'benchmarks': benchContents, - 'compileTime': [nativeCompileTime], - 'codeSize': MPPTools.getCodeSizeBenchmark(project.ext.applicationName, nativeExecutable) ] - def output = MPPTools.createJsonReport(properties) - new File("${buildDir.absolutePath}/${nativeJson}").write(output) - } -} - -task jvmJsonReport { - doLast { - def jarPath = project.getTasks().getByName("jvmJar").archivePath - def jvmCompileTime = MPPTools.getJvmCompileTime(project.ext.applicationName) - String benchContents = new File("${buildDir.absolutePath}/${jvmBenchResults}").text - def properties = getCommonProperties() + ['type': 'jvm', - 'compilerVersion': "${buildKotlinVersion}".toString(), - 'benchmarks': benchContents, - 'compileTime': [jvmCompileTime], - 'codeSize': MPPTools.getCodeSizeBenchmark(project.ext.applicationName, "${jarPath}") ] - def output = MPPTools.createJsonReport(properties) - new File("${buildDir.absolutePath}/${jvmJson}").write(output) - } -} - -jvmRun.finalizedBy jvmJsonReport - -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()] -} - diff --git a/performance/objcinterop/build.gradle b/performance/objcinterop/build.gradle deleted file mode 100644 index 8a9b901ad1e..00000000000 --- a/performance/objcinterop/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -import org.jetbrains.kotlin.konan.target.HostManager - -project.ext { - applicationName = 'ObjCInterop' - commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt'] - jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm'] - nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native'] - linkerOpts = ["-L$buildDir".toString(), "-lcomplexnumbers".toString()] -} - -task compileLibrary { - doFirst { - mkdir buildDir.absolutePath - execKonanClang(HostManager.host) { - args "$projectDir/src/nativeInterop/cinterop/complexNumbers.m" - args "-lobjc", '-fobjc-arc' - args '-fPIC', '-shared', '-o', "$buildDir/libcomplexnumbers.dylib" - } - } -} - -apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/benchmark.gradle") -kotlin.targets.native.compilations.main.cinterops { - classes { - headers "$projectDir/src/nativeInterop/cinterop/complexNumbers.h" - } -} - -kotlin.targets.native.binaries.getExecutable("benchmark", "RELEASE").linkTask.dependsOn 'compileLibrary' diff --git a/performance/objcinterop/build.gradle.kts b/performance/objcinterop/build.gradle.kts new file mode 100644 index 00000000000..f85b68a5547 --- /dev/null +++ b/performance/objcinterop/build.gradle.kts @@ -0,0 +1,45 @@ +/* + * 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.benchmark.BenchmarkingPlugin +import org.jetbrains.kotlin.ExecClang +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.HostManager + +plugins { + id("benchmarking") +} + +benchmark { + applicationName = "ObjCInterop" + commonSrcDirs = listOf("../../tools/benchmarks/shared/src", "src/main/kotlin", "../shared/src/main/kotlin", "../../tools/kliopt") + jvmSrcDirs = listOf("src/main/kotlin-jvm", "../shared/src/main/kotlin-jvm") + nativeSrcDirs = listOf("src/main/kotlin-native", "../shared/src/main/kotlin-native") + linkerOpts = listOf("-L$buildDir", "-lcomplexnumbers") +} + +val compileLibary by tasks.creating { + doFirst { + mkdir(buildDir) + + project.withConvention(ExecClang::class) { + execKonanClang(HostManager.host) { + args("$projectDir/src/nativeInterop/cinterop/complexNumbers.m") + args("-lobjc", "-fobjc-arc") + args("-fPIC", "-shared", "-o", "$buildDir/libcomplexnumbers.dylib") + } + } + } +} + +val native = kotlin.targets.getByName("native") as KotlinNativeTarget +native.apply { + compilations["main"].cinterops { + create("classes") { + headers("$projectDir/src/nativeInterop/cinterop/complexNumbers.h") + } + } + binaries.getExecutable(BenchmarkingPlugin.NATIVE_EXECUTABLE_NAME, "RELEASE").linkTask.dependsOn(compileLibary) +} \ No newline at end of file diff --git a/performance/ring/build.gradle b/performance/ring/build.gradle deleted file mode 100644 index e07111d3128..00000000000 --- a/performance/ring/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -project.ext { - applicationName = 'Ring' - commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt'] - jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm'] - nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native'] - -} -apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/benchmark.gradle") \ No newline at end of file diff --git a/performance/ring/build.gradle.kts b/performance/ring/build.gradle.kts new file mode 100644 index 00000000000..cc89ab3b036 --- /dev/null +++ b/performance/ring/build.gradle.kts @@ -0,0 +1,15 @@ +/* + * 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("benchmarking") +} + +benchmark { + applicationName = "Ring" + commonSrcDirs = listOf("../../tools/benchmarks/shared/src", "src/main/kotlin", "../shared/src/main/kotlin", "../../tools/kliopt") + jvmSrcDirs = listOf("src/main/kotlin-jvm", "../shared/src/main/kotlin-jvm") + nativeSrcDirs = listOf("src/main/kotlin-native", "../shared/src/main/kotlin-native") +}