Objective c interop benchmarks migration (#3004)

This commit is contained in:
LepilkinaElena
2019-06-03 16:32:14 +03:00
committed by GitHub
parent 285bfc11f8
commit 69fd55656d
46 changed files with 1467 additions and 315 deletions
+7 -8
View File
@@ -103,33 +103,32 @@ To update the blackbox compiler tests set TeamCity build number in `gradle.prope
To measure performance of Kotlin/Native compiler on existing benchmarks: To measure performance of Kotlin/Native compiler on existing benchmarks:
cd performance ./gradlew :performance:konanRun
../gradlew konanRun
**konanRun** task can be run separately for one/several benchmark applications: **konanRun** task can be run separately for one/several benchmark applications:
../gradlew :cinterop:konanRun ./gradlew :performance:cinterop:konanRun
**konanRun** task has parameter `filter` which allows to run only some subset of benchmarks: **konanRun** task has parameter `filter` which allows to run only some subset of benchmarks:
../gradlew :cinterop:konanRun --filter=struct,macros ./gradlew :performance:cinterop:konanRun --filter=struct,macros
Or you can use `filterRegex` if you want to specify the filter as regexes: Or you can use `filterRegex` if you want to specify the filter as regexes:
../gradlew :ring:konanRun --filterRegex=String.*,Loop.* ./gradlew :performance:ring:konanRun --filterRegex=String.*,Loop.*
There are also tasks for running benchmarks on JVM (pay attention, some benchmarks e.g. cinterop benchmarks can't be run on JVM) There are also tasks for running benchmarks on JVM (pay attention, some benchmarks e.g. cinterop benchmarks can't be run on JVM)
../gradlew jvmRun ./gradlew :performance:jvmRun
Files with results of benchmarks run are saved in `performance/build/nativeReport.json` for konanRun and `jvmReport.json` for jvmRun. Files with results of benchmarks run are saved in `performance/build/nativeReport.json` for konanRun and `jvmReport.json` for jvmRun.
You can change the output filename by setting the `nativeJson` property for konanRun and `jvmJson` for jvmRun: You can change the output filename by setting the `nativeJson` property for konanRun and `jvmJson` for jvmRun:
../gradlew :ring:konanRun --filter=String.*,Loop.* -PnativeJson=stringsAndLoops.json ./gradlew :performance:ring:konanRun --filter=String.*,Loop.* -PnativeJson=stringsAndLoops.json
You can use the `compilerArgs` property to pass flags to the compiler used to compile the benchmarks: You can use the `compilerArgs` property to pass flags to the compiler used to compile the benchmarks:
../gradlew konanRun -PcompilerArgs="--time -g" ./gradlew :performance:konanRun -PcompilerArgs="--time -g"
To compare different results run benchmarksAnalyzer tool: To compare different results run benchmarksAnalyzer tool:
+4 -4
View File
@@ -3098,7 +3098,7 @@ kotlinNativeInterop {
defFile 'interop/basics/ccallbacksAndVarargs.def' defFile 'interop/basics/ccallbacksAndVarargs.def'
} }
if (isAppleTarget(project)) { if (PlatformInfo.isAppleTarget(project)) {
objcSmoke { objcSmoke {
defFile 'interop/objc/objcSmoke.def' defFile 'interop/objc/objcSmoke.def'
headers "$projectDir/interop/objc/smoke.h" headers "$projectDir/interop/objc/smoke.h"
@@ -3447,7 +3447,7 @@ task runKonanRegexTests(type: RunKonanTest) {
task coverage_basic_program(type: RunStandaloneKonanTest) { task coverage_basic_program(type: RunStandaloneKonanTest) {
disabled = getTarget(project).name != "ios_x64" && getTarget(project).name != "macos_x64" disabled = PlatformInfo.getTarget(project).name != "ios_x64" && PlatformInfo.getTarget(project).name != "macos_x64"
description = "Test that `-Xcoverage` generates correct __llvm_coverage information" description = "Test that `-Xcoverage` generates correct __llvm_coverage information"
@@ -3476,7 +3476,7 @@ task coverage_basic_program(type: RunStandaloneKonanTest) {
task coverage_basic_library(type: RunStandaloneKonanTest) { task coverage_basic_library(type: RunStandaloneKonanTest) {
disabled = getTarget(project).name != "ios_x64" && getTarget(project).name != "macos_x64" disabled = PlatformInfo.getTarget(project).name != "ios_x64" && PlatformInfo.getTarget(project).name != "macos_x64"
description = "Test that `-Xlibrary-to-cover` generates correct __llvm_coverage information" description = "Test that `-Xlibrary-to-cover` generates correct __llvm_coverage information"
@@ -3486,7 +3486,7 @@ task coverage_basic_library(type: RunStandaloneKonanTest) {
doFirst { doFirst {
def konancScript = isWindows() ? "konanc.bat" : "konanc" def konancScript = isWindows() ? "konanc.bat" : "konanc"
def konanc = "$dist/bin/$konancScript" def konanc = "$dist/bin/$konancScript"
"$konanc -target ${getTarget(project).name} $projectDir/coverage/basic/library/library.kt -p library -o $dir/lib_to_cover".execute().waitFor() "$konanc -target ${PlatformInfo.getTarget(project).name} $projectDir/coverage/basic/library/library.kt -p library -o $dir/lib_to_cover".execute().waitFor()
} }
flags = ["-Xcoverage-file=$dir/program.profraw", "-l", "$dir/lib_to_cover", "-Xlibrary-to-cover=$dir/lib_to_cover.klib", "-entry", "coverage.basic.library.main"] flags = ["-Xcoverage-file=$dir/program.profraw", "-l", "$dir/lib_to_cover", "-Xlibrary-to-cover=$dir/lib_to_cover.klib", "-entry", "coverage.basic.library.main"]
+9 -45
View File
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.* import org.jetbrains.kotlin.konan.util.*
import org.jetbrains.kotlin.CopySamples import org.jetbrains.kotlin.CopySamples
import org.jetbrains.kotlin.CopyCommonSources import org.jetbrains.kotlin.CopyCommonSources
import org.jetbrains.kotlin.PlatformInfo
import org.jetbrains.kotlin.konan.* import org.jetbrains.kotlin.konan.*
buildscript { buildscript {
@@ -41,7 +42,7 @@ wrapper.distributionType = Wrapper.DistributionType.ALL
defaultTasks 'clean', 'dist' defaultTasks 'clean', 'dist'
convention.plugins.platformInfo = new PlatformInfo() convention.plugins.platformInfo = PlatformInfo
ext { ext {
distDir = file('dist') distDir = file('dist')
@@ -161,43 +162,6 @@ void loadCommandLineProperties() {
ext.testTarget = project.hasProperty("test_target") ? ext.test_target : null ext.testTarget = project.hasProperty("test_target") ? ext.test_target : null
} }
class PlatformInfo {
boolean isMac() {
return HostManager.hostIsMac
}
boolean isWindows() {
return HostManager.hostIsMingw
}
boolean isLinux() {
return HostManager.hostIsLinux
}
boolean isAppleTarget(Project project) {
def target = getTarget(project)
return target.family == Family.IOS || target.family == Family.OSX
}
boolean isWindowsTarget(Project project) {
return getTarget(project).family == Family.MINGW
}
boolean isWasmTarget(Project project) {
return getTarget(project).family == Family.WASM
}
KonanTarget getTarget(Project project) {
def platformManager = project.rootProject.platformManager
def targetName = project.project.testTarget ?: 'host'
return platformManager.targetManager(targetName).target
}
Throwable unsupportedPlatformException() {
return new TargetSupportException()
}
}
configurations { configurations {
ftpAntTask ftpAntTask
kotlinCommonSources kotlinCommonSources
@@ -343,7 +307,7 @@ task distCompiler(type: Copy) {
from(file('cmd')) { from(file('cmd')) {
fileMode(0755) fileMode(0755)
into('bin') into('bin')
if (!isWindows()) { if (!PlatformInfo.isWindows()) {
exclude('**/*.bat') exclude('**/*.bat')
} }
} }
@@ -501,6 +465,12 @@ task samples {
dependsOn 'samplesZip', 'samplesTar' dependsOn 'samplesZip', 'samplesTar'
} }
task performance {
dependsOn 'dist'
dependsOn ':performance:clean'
dependsOn ':performance:konanRun'
}
task samplesZip(type: Zip) task samplesZip(type: Zip)
task samplesTar(type: Tar) { task samplesTar(type: Tar) {
extension = 'tar.gz' extension = 'tar.gz'
@@ -562,12 +532,6 @@ task uploadBundle {
} }
} }
// TODO return when problems with HostManagers will be solved
/*task performance {
dependsOn 'dist'
dependsOn ':performance:bench'
}*/
task teamcityKonanVersion { task teamcityKonanVersion {
doLast { doLast {
println("##teamcity[setParameter name='kotlin.native.version.base' value='$konanVersion']") println("##teamcity[setParameter name='kotlin.native.version.base' value='$konanVersion']")
+5 -2
View File
@@ -23,6 +23,7 @@ buildscript {
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle" apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
dependencies{ dependencies{
classpath "org.jetbrains.kotlin:kotlin-serialization:$buildKotlinVersion" classpath "org.jetbrains.kotlin:kotlin-serialization:$buildKotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
} }
} }
@@ -37,13 +38,15 @@ dependencies {
compile localGroovy() compile localGroovy()
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion" compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-reflect:$buildKotlinVersion" compile "org.jetbrains.kotlin:kotlin-reflect:$buildKotlinVersion"
compile group: 'com.ullink.slack', name: 'simpleslackapi', version: '0.6.0' compile group: 'com.ullink.slack', name: 'simpleslackapi', version: '1.2.0'
// An artifact from the included build 'shared' cannot be used here due to https://github.com/gradle/gradle/issues/3768 // An artifact from the included build 'shared' cannot be used here due to https://github.com/gradle/gradle/issues/3768
// TODO: Remove this hack when the bug is fixed implementation "org.jetbrains.kotlin:kotlin-gradle-plugin"
compile project(':shared') compile project(':shared')
compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.10.0" compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.10.0"
} }
sourceSets.main.kotlin.srcDirs = ["src", "$projectDir/../../tools/benchmarks/shared/src"]
rootProject.dependencies { rootProject.dependencies {
runtime project(path) runtime project(path)
} }
@@ -3,6 +3,8 @@
* that can be found in the license/LICENSE.txt file. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
@@ -78,7 +78,7 @@ open class FrameworkTest : DefaultTask() {
listOf(provider.toString(), swiftMain) listOf(provider.toString(), swiftMain)
val options = listOf("-g", "-Xlinker", "-rpath", "-Xlinker", frameworkParentDirPath, "-F", frameworkParentDirPath) val options = listOf("-g", "-Xlinker", "-rpath", "-Xlinker", frameworkParentDirPath, "-F", frameworkParentDirPath)
val testExecutable = Paths.get(testOutput, frameworkName, "swiftTestExecutable") val testExecutable = Paths.get(testOutput, frameworkName, "swiftTestExecutable")
swiftc(sources, options, testExecutable) compileSwift(project, project.testTarget(), sources, options, testExecutable, fullBitcode)
runTest(testExecutable) runTest(testExecutable)
} }
@@ -117,36 +117,6 @@ open class FrameworkTest : DefaultTask() {
check(exitCode == 0, { "Execution failed with exit code: $exitCode "}) check(exitCode == 0, { "Execution failed with exit code: $exitCode "})
} }
private fun swiftc(sources: List<String>, options: List<String>, output: Path) {
val target = project.testTarget()
val platform = project.platformManager().platform(target)
assert(platform.configurables is AppleConfigurables)
val configs = platform.configurables as AppleConfigurables
val compiler = configs.absoluteTargetToolchain + "/usr/bin/swiftc"
val swiftTarget = when (target) {
KonanTarget.IOS_X64 -> "x86_64-apple-ios" + configs.osVersionMin
KonanTarget.IOS_ARM64 -> "arm64_64-apple-ios" + configs.osVersionMin
KonanTarget.MACOS_X64 -> "x86_64-apple-macosx" + configs.osVersionMin
else -> throw IllegalStateException("Test target $target is not supported")
}
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
options + "-o" + output.toString() + sources +
if (fullBitcode) listOf("-embed-bitcode", "-Xlinker", "-bitcode_verify") else listOf("-embed-bitcode-marker")
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = compiler, args = args)
println("""
|$compiler finished with exit code: $exitCode
|options: ${args.joinToString(separator = " ")}
|stdout: $stdOut
|stderr: $stdErr
""".trimMargin())
check(exitCode == 0, { "Compilation failed" })
check(output.toFile().exists(), { "Compiler swiftc hasn't produced an output file: $output" })
}
private fun validateBitcodeEmbedding(frameworkBinary: String) { private fun validateBitcodeEmbedding(frameworkBinary: String) {
// Check only the full bitcode embedding for now. // Check only the full bitcode embedding for now.
if (!fullBitcode) { if (!fullBitcode) {
@@ -3,6 +3,8 @@
* that can be found in the license/LICENSE.txt file. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin
import org.gradle.api.NamedDomainObjectCollection import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project import org.gradle.api.Project
@@ -5,11 +5,14 @@
@file:JvmName("MPPTools") @file:JvmName("MPPTools")
package org.jetbrains.kotlin
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.tasks.TaskState import org.gradle.api.tasks.TaskState
import org.gradle.api.execution.TaskExecutionListener import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.tasks.AbstractExecTask
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.report.* import org.jetbrains.report.*
@@ -27,16 +30,6 @@ import java.util.Base64
* This file includes short-cuts that may potentially be implemented in Kotlin MPP Gradle plugin in the future. * This file includes short-cuts that may potentially be implemented in Kotlin MPP Gradle plugin in the future.
*/ */
// Short-cuts for detecting the host OS.
@get:JvmName("isMacos")
val isMacos by lazy { hostOs == "Mac OS X" }
@get:JvmName("isWindows")
val isWindows by lazy { hostOs.startsWith("Windows") }
@get:JvmName("isLinux")
val isLinux by lazy { hostOs == "Linux" }
// Short-cuts for mostly used paths. // Short-cuts for mostly used paths.
@get:JvmName("mingwPath") @get:JvmName("mingwPath")
val mingwPath by lazy { System.getenv("MINGW64_DIR") ?: "c:/msys64/mingw64" } val mingwPath by lazy { System.getenv("MINGW64_DIR") ?: "c:/msys64/mingw64" }
@@ -57,9 +50,9 @@ fun defaultHostPreset(
throw Exception("Preset whitelist must not be empty in Kotlin/Native ${subproject.displayName}.") throw Exception("Preset whitelist must not be empty in Kotlin/Native ${subproject.displayName}.")
val presetCandidate = when { val presetCandidate = when {
isMacos -> subproject.kotlin.presets.macosX64 PlatformInfo.isMac() -> subproject.kotlin.presets.macosX64
isLinux -> subproject.kotlin.presets.linuxX64 PlatformInfo.isLinux() -> subproject.kotlin.presets.linuxX64
isWindows -> subproject.kotlin.presets.mingwX64 PlatformInfo.isWindows() -> subproject.kotlin.presets.mingwX64
else -> null else -> null
} }
@@ -70,9 +63,9 @@ fun defaultHostPreset(
} }
fun getNativeProgramExtension(): String = when { fun getNativeProgramExtension(): String = when {
isMacos -> ".kexe" PlatformInfo.isMac() -> ".kexe"
isLinux -> ".kexe" PlatformInfo.isLinux() -> ".kexe"
isWindows -> ".exe" PlatformInfo.isWindows() -> ".exe"
else -> error("Unknown host") else -> error("Unknown host")
} }
@@ -161,10 +154,21 @@ fun sendUploadRequest(url: String, fileName: String, username: String? = null, p
fun createRunTask( fun createRunTask(
subproject: Project, subproject: Project,
name: String, name: String,
target: KotlinNativeTarget, runTask: AbstractExecTask<*>,
configureClosure: Closure<Any>? = null configureClosure: Closure<Any>? = null
): Task { ): Task {
val task = subproject.tasks.create(name, RunKotlinNativeTask::class.java, target) val task = subproject.tasks.create(name, RunKotlinNativeTask::class.java, runTask)
task.configure(configureClosure ?: task.emptyConfigureClosure())
return task
}
@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()) task.configure(configureClosure ?: task.emptyConfigureClosure())
return task return task
} }
@@ -174,7 +178,7 @@ fun getJvmCompileTime(programName: String): BenchmarkResult =
@JvmOverloads @JvmOverloads
fun getNativeCompileTime(programName: String, fun getNativeCompileTime(programName: String,
tasks: List<String> = listOf("compileKotlinNative", "linkBenchmarkReleaseExecutableNative")): BenchmarkResult = tasks: List<String> = listOf("linkBenchmarkReleaseExecutableNative")): BenchmarkResult =
TaskTimerListener.getBenchmarkResult(programName, tasks) TaskTimerListener.getBenchmarkResult(programName, tasks)
fun getCompileBenchmarkTime(programName: String, tasksNames: Iterable<String>, repeats: Int, exitCodes: Map<String, Int>) = fun getCompileBenchmarkTime(programName: String, tasksNames: Iterable<String>, repeats: Int, exitCodes: Map<String, Int>) =
@@ -207,7 +211,7 @@ class TaskTimerListener: TaskExecutionListener {
fun getTime(taskName: String) = tasksTimes[taskName] ?: 0.0 fun getTime(taskName: String) = tasksTimes[taskName] ?: 0.0
} }
private var startTime = System.currentTimeMillis() private var startTime = System.nanoTime()
override fun beforeExecute(task: Task) { override fun beforeExecute(task: Task) {
startTime = System.nanoTime() startTime = System.nanoTime()
@@ -0,0 +1,41 @@
package org.jetbrains.kotlin
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.*
import org.gradle.api.Project
object PlatformInfo {
@JvmStatic
fun isMac() = HostManager.hostIsMac
@JvmStatic
fun isWindows() = HostManager.hostIsMingw
@JvmStatic
fun isLinux() = HostManager.hostIsLinux
@JvmStatic
fun isAppleTarget(project: Project): Boolean {
val target = getTarget(project)
return target.family == Family.IOS || target.family == Family.OSX
}
@JvmStatic
fun isAppleTarget(target: KonanTarget): Boolean {
return target.family == Family.IOS || target.family == Family.OSX
}
@JvmStatic
fun isWindowsTarget(project: Project) = getTarget(project).family == Family.MINGW
@JvmStatic
fun isWasmTarget(project: Project) =
getTarget(project).family == Family.WASM
@JvmStatic
fun getTarget(project: Project): KonanTarget {
val platformManager = project.rootProject.platformManager()
val targetName = project.project.testTarget().name
return platformManager.targetManager(targetName).target
}
fun unsupportedPlatformException() = TargetSupportException()
}
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * 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. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
@@ -37,7 +38,6 @@ import java.util.Properties
*/ */
open class RegressionsReporter : DefaultTask() { open class RegressionsReporter : DefaultTask() {
val slackUsers = mapOf( val slackUsers = mapOf(
"olonho" to "nikolay.igotti", "olonho" to "nikolay.igotti",
"nikolay.igotti" to "nikolay.igotti", "nikolay.igotti" to "nikolay.igotti",
@@ -3,6 +3,8 @@
* that can be found in the license/LICENSE.txt file. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
@@ -3,23 +3,21 @@
* that can be found in the license/LICENSE.txt file. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option import org.gradle.api.tasks.options.Option
import org.gradle.api.tasks.Input import org.gradle.api.tasks.Input
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import javax.inject.Inject import javax.inject.Inject
import java.io.File import java.io.File
open class RunKotlinNativeTask @Inject constructor( open class RunBenchmarksExecutableTask @Inject constructor() : DefaultTask() {
private val curTarget: KotlinNativeTarget
) : DefaultTask() {
var buildType = "RELEASE"
var workingDir: Any = project.projectDir var workingDir: Any = project.projectDir
var outputFileName: String? = null var outputFileName: String? = null
var executable: String? = null
@Input @Input
@Option(option = "filter", description = "Benchmarks to run (comma-separated)") @Option(option = "filter", description = "Benchmarks to run (comma-separated)")
var filter: String = "" var filter: String = ""
@@ -40,7 +38,6 @@ open class RunKotlinNativeTask @Inject constructor(
override fun configure(configureClosure: Closure<Any>): Task { override fun configure(configureClosure: Closure<Any>): Task {
val task = super.configure(configureClosure) val task = super.configure(configureClosure)
this.dependsOn += curTarget.binaries.getExecutable("benchmark", buildType).linkTaskName
return task return task
} }
@@ -52,7 +49,7 @@ open class RunKotlinNativeTask @Inject constructor(
val filterArgs = filter.splitCommaSeparatedOption("-f") val filterArgs = filter.splitCommaSeparatedOption("-f")
val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr") val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr")
project.exec { project.exec {
it.executable = curTarget.binaries.getExecutable("benchmark", buildType).outputFile.getAbsolutePath() it.executable = executable
it.args = curArgs + filterArgs + filterRegexArgs it.args = curArgs + filterArgs + filterRegexArgs
it.environment = curEnvironment it.environment = curEnvironment
it.workingDir(workingDir) it.workingDir(workingDir)
@@ -70,8 +67,8 @@ open class RunKotlinNativeTask @Inject constructor(
} }
internal fun emptyConfigureClosure() = object : Closure<Any>(this) { internal fun emptyConfigureClosure() = object : Closure<Any>(this) {
override fun call(): RunKotlinNativeTask { override fun call(): RunBenchmarksExecutableTask {
return this@RunKotlinNativeTask return this@RunBenchmarksExecutableTask
} }
} }
} }
@@ -3,6 +3,8 @@
* that can be found in the license/LICENSE.txt file. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.JavaExec
import org.gradle.api.Task import org.gradle.api.Task
@@ -0,0 +1,55 @@
/*
* 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.AbstractExecTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
import org.gradle.api.tasks.Input
import javax.inject.Inject
open class RunKotlinNativeTask @Inject constructor(
private val runTask: AbstractExecTask<*>
) : DefaultTask() {
@Input
var buildType = "RELEASE"
@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 = ""
override fun configure(configureClosure: Closure<Any>): Task {
val task = super.configure(configureClosure)
this.finalizedBy(runTask.name)
runTask.finalizedBy("konanJsonReport")
return task
}
fun depends(taskName: String) {
this.dependsOn += taskName
}
@TaskAction
fun run() {
runTask.run {
val filterArgs = filter.splitCommaSeparatedOption("-f")
val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr")
runTask.args(filterArgs)
runTask.args(filterRegexArgs)
}
}
internal fun emptyConfigureClosure() = object : Closure<Any>(this) {
override fun call(): RunKotlinNativeTask {
return this@RunKotlinNativeTask
}
}
}
@@ -1,10 +1,21 @@
package org.jetbrains.kotlin package org.jetbrains.kotlin
import org.gradle.api.Project import org.gradle.api.Project
import org.jetbrains.kotlin.konan.target.AppleConfigurables
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.PlatformManager import org.jetbrains.kotlin.konan.target.PlatformManager
import java.io.FileInputStream
import java.io.IOException
import java.io.File
import java.util.concurrent.TimeUnit
import java.net.HttpURLConnection
import java.net.URL
import java.util.Base64
import org.jetbrains.report.json.*
import java.nio.file.Path
fun Project.platformManager() = findProperty("platformManager") as PlatformManager fun Project.platformManager() = findProperty("platformManager") as PlatformManager
fun Project.testTarget() = findProperty("target") as KonanTarget fun Project.testTarget() = findProperty("target") as KonanTarget
@@ -12,13 +23,126 @@ fun Project.testTarget() = findProperty("target") as KonanTarget
* Ad-hoc signing of the specified path * Ad-hoc signing of the specified path
*/ */
fun codesign(project: Project, path: String) { fun codesign(project: Project, path: String) {
check(HostManager.hostIsMac, { "Apple specific code signing" } ) check(HostManager.hostIsMac, { "Apple specific code signing" })
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = "/usr/bin/codesign", val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = "/usr/bin/codesign",
args = listOf("--verbose", "-s", "-", path)) args = listOf("--verbose", "-s", "-", path))
check(exitCode == 0, { """ check(exitCode == 0, {
"""
|Codesign failed with exitCode: $exitCode |Codesign failed with exitCode: $exitCode
|stdout: $stdOut |stdout: $stdOut
|stderr: $stdErr |stderr: $stdErr
""".trimMargin() """.trimMargin()
}) })
} }
// Run command line from string.
fun Array<String>.runCommand(workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS): String {
return try {
ProcessBuilder(*this)
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().apply {
waitFor(timeoutAmount, timeoutUnit)
}.inputStream.bufferedReader().readText()
} catch (e: IOException) {
error("Couldn't run command $this")
}
}
fun String.splitCommaSeparatedOption(optionName: String) =
split("\\s*,\\s*".toRegex()).map {
if (it.isNotEmpty()) listOf(optionName, it) else listOf(null)
}.flatten().filterNotNull()
data class Commit(val revision: String, val developer: String, val webUrlWithDescription: String)
val teamCityUrl = "http://buildserver.labs.intellij.net"
// List of commits.
class CommitsList(data: JsonElement): ConvertedFromJson {
val commits: List<Commit>
init {
if (data !is JsonObject) {
error("Commits description is expected to be a json object!")
}
val changesElement = data.getOptionalField("change")
commits = changesElement?.let {
if (changesElement !is JsonArray) {
error("Change field is expected to be an array. Please, check source.")
}
changesElement.jsonArray.map {
with(it as JsonObject) {
Commit(elementToString(getRequiredField("version"), "version"),
elementToString(getRequiredField("username"), "username"),
elementToString(getRequiredField("webUrl"), "webUrl")
)
}
}
} ?: listOf<Commit>()
}
}
fun buildsUrl(buildLocator: String) =
"$teamCityUrl/app/rest/builds/?locator=$buildLocator"
fun getBuild(buildLocator: String, user: String, password: String) =
try {
sendGetRequest(buildsUrl(buildLocator), user, password)
} catch (t: Throwable) {
error("Try to get build! TeamCity is unreachable!")
}
fun sendGetRequest(url: String, username: String? = null, password: String? = null) : String {
val connection = URL(url).openConnection() as HttpURLConnection
if (username != null && password != null) {
val auth = Base64.getEncoder().encode((username + ":" + password).toByteArray()).toString(Charsets.UTF_8)
connection.addRequestProperty("Authorization", "Basic $auth")
}
connection.setRequestProperty("Accept", "application/json");
connection.connect()
return connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
}
fun getBuildProperty(buildJsonDescription: String, property: String) =
with(JsonTreeParser.parse(buildJsonDescription) as JsonObject) {
if (getPrimitive("count").int == 0) {
error("No build information on TeamCity for $buildJsonDescription!")
}
(getArray("build").getObject(0).getPrimitive(property) as JsonLiteral).unquoted()
}
@JvmOverloads
fun compileSwift(project: Project, target: KonanTarget, sources: List<String>, options: List<String>,
output: Path, fullBitcode: Boolean = false) {
val platform = project.platformManager().platform(target)
assert(platform.configurables is AppleConfigurables)
val configs = platform.configurables as AppleConfigurables
val compiler = configs.absoluteTargetToolchain + "/usr/bin/swiftc"
val swiftTarget = when (target) {
KonanTarget.IOS_X64 -> "x86_64-apple-ios" + configs.osVersionMin
KonanTarget.IOS_ARM64 -> "arm64_64-apple-ios" + configs.osVersionMin
KonanTarget.MACOS_X64 -> "x86_64-apple-macosx" + configs.osVersionMin
else -> throw IllegalStateException("Test target $target is not supported")
}
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
options + "-o" + output.toString() + sources +
if (fullBitcode) listOf("-embed-bitcode", "-Xlinker", "-bitcode_verify") else listOf("-embed-bitcode-marker")
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = compiler, args = args)
println("""
|$compiler finished with exit code: $exitCode
|options: ${args.joinToString(separator = " ")}
|stdout: $stdOut
|stderr: $stdErr
""".trimMargin())
check(exitCode == 0, { "Compilation failed" })
check(output.toFile().exists(), { "Compiler swiftc hasn't produced an output file: $output" })
}
+2 -1
View File
@@ -27,7 +27,8 @@ buildscript {
} }
} }
import org.jetbrains.kotlin.konan.target.ClangArgs import org.jetbrains.kotlin.konan.target.ClangArgs
ext.isEnabled = isMac() import org.jetbrains.kotlin.PlatformInfo
ext.isEnabled = PlatformInfo.isMac()
model { model {
components { components {
+44 -3
View File
@@ -1,3 +1,8 @@
import org.jetbrains.kotlin.RegressionsReporter
import org.jetbrains.kotlin.RegressionsSummaryReporter
import org.jetbrains.kotlin.BuildRegister
import org.jetbrains.kotlin.MPPTools
buildscript { buildscript {
ext.rootBuildDirectory = file('..') ext.rootBuildDirectory = file('..')
@@ -42,16 +47,17 @@ defaultTasks 'konanRun'
// Produce and send slack report. // Produce and send slack report.
task slackReport(type: RegressionsReporter) { task slackReport(type: RegressionsReporter) {
def analyzerBinary = MPPTools.findFile("${analyzerTool}${MPPTools.getNativeProgramExtension()}",
"${rootBuildDirectory}/${analyzerToolDirectory}")
def teamcityConfig = System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE") def teamcityConfig = System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE")
if (teamcityConfig) { if (teamcityConfig && analyzerBinary != null) {
// Create folder for report (root Kotlin project settings make create report in separate folder). // Create folder for report (root Kotlin project settings make create report in separate folder).
def reportDirectory = new File(outputReport).parentFile def reportDirectory = new File(outputReport).parentFile
mkdir reportDirectory mkdir reportDirectory
def targetsResults = new File(new File("${rootBuildDirectory}"), "targetsResults").toString() def targetsResults = new File(new File("${rootBuildDirectory}"), "targetsResults").toString()
mkdir targetsResults mkdir targetsResults
currentBenchmarksReportFile = "${buildDir.absolutePath}/${nativeJson}" currentBenchmarksReportFile = "${buildDir.absolutePath}/${nativeJson}"
analyzer = MPPTools.findFile("${analyzerTool}${MPPTools.getNativeProgramExtension()}", analyzer = analyzerBinary
"${rootBuildDirectory}/${analyzerToolDirectory}")
htmlReport = outputReport htmlReport = outputReport
defaultBranch = project.findProperty('kotlin.native.default.branch') ?: "master" defaultBranch = project.findProperty('kotlin.native.default.branch') ?: "master"
def target = System.getProperty("os.name") def target = System.getProperty("os.name")
@@ -139,3 +145,38 @@ task teamCityStat(type:Exec) {
println("No analyzer $analyzerTool found in subdirectories of ${rootBuildDirectory}/${analyzerToolDirectory}") println("No analyzer $analyzerTool found in subdirectories of ${rootBuildDirectory}/${analyzerToolDirectory}")
} }
} }
task сinterop {
dependsOn 'clean'
dependsOn 'сinterop:konanRun'
}
task framework {
dependsOn 'clean'
dependsOn 'framework:konanRun'
}
task helloworld {
dependsOn 'clean'
dependsOn 'helloworld:konanRun'
}
task objcinterop {
dependsOn 'clean'
dependsOn 'objcinterop:konanRun'
}
task ring {
dependsOn 'clean'
dependsOn 'ring:konanRun'
}
task swiftinterop {
dependsOn 'clean'
dependsOn 'swiftinterop:konanRun'
}
task videoplayer {
dependsOn 'clean'
dependsOn 'swiftinterop:konanRun'
}
-36
View File
@@ -1,36 +0,0 @@
buildscript {
repositories {
maven {
url 'https://cache-redirector.jetbrains.com/maven-central'
}
maven {
url kotlinCompilerRepo
}
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
apply plugin: 'kotlin'
repositories {
maven {
url kotlinCompilerRepo
}
maven {
url buildKotlinCompilerRepo
}
jcenter()
}
dependencies {
compileOnly gradleApi()
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin"
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
compile group: 'com.ullink.slack', name: 'simpleslackapi', version: '1.2.0'
}
sourceSets.main.kotlin.srcDirs = ["src", "$projectDir/../../tools/benchmarks/shared/src"]
-21
View File
@@ -1,21 +0,0 @@
// Reuse Kotlin version from the root project.
File rootProjectGradlePropertiesFile = file("${rootProject.projectDir}/../../gradle.properties")
if (!rootProjectGradlePropertiesFile.isFile()) {
throw new Exception("File $rootProjectGradlePropertiesFile does not exist or is not a file")
}
Properties rootProjectProperties = new Properties()
rootProjectGradlePropertiesFile.withInputStream { inputStream ->
rootProjectProperties.load(inputStream)
if (!rootProjectProperties.containsKey('kotlinVersion')) {
throw new Exception("No 'kotlinVersion' property in $rootProjectGradlePropertiesFile file")
}
}
gradle.beforeProject { project ->
rootProjectProperties.forEach { String key, value ->
if (!project.hasProperty(key))
project.ext[key] = value
}
}
@@ -1,94 +0,0 @@
/*
* 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/LICENSE.txt file.
*/
import java.io.FileInputStream
import java.io.IOException
import java.io.File
import java.util.concurrent.TimeUnit
import java.net.HttpURLConnection
import java.net.URL
import java.util.Base64
import org.jetbrains.report.json.*
// Run command line from string.
fun Array<String>.runCommand(workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS): String {
return try {
ProcessBuilder(*this)
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().apply {
waitFor(timeoutAmount, timeoutUnit)
}.inputStream.bufferedReader().readText()
} catch (e: IOException) {
error("Couldn't run command $this")
}
}
fun String.splitCommaSeparatedOption(optionName: String) =
split("\\s*,\\s*".toRegex()).map {
if (it.isNotEmpty()) listOf(optionName, it) else listOf(null)
}.flatten().filterNotNull()
data class Commit(val revision: String, val developer: String, val webUrlWithDescription: String)
val teamCityUrl = "http://buildserver.labs.intellij.net"
// List of commits.
class CommitsList(data: JsonElement): ConvertedFromJson {
val commits: List<Commit>
init {
if (data !is JsonObject) {
error("Commits description is expected to be a json object!")
}
val changesElement = data.getOptionalField("change")
commits = changesElement?.let {
if (changesElement !is JsonArray) {
error("Change field is expected to be an array. Please, check source.")
}
changesElement.jsonArray.map {
with(it as JsonObject) {
Commit(elementToString(getRequiredField("version"), "version"),
elementToString(getRequiredField("username"), "username"),
elementToString(getRequiredField("webUrl"), "webUrl")
)
}
}
} ?: listOf<Commit>()
}
}
fun buildsUrl(buildLocator: String) =
"$teamCityUrl/app/rest/builds/?locator=$buildLocator"
fun getBuild(buildLocator: String, user: String, password: String) =
try {
sendGetRequest(buildsUrl(buildLocator), user, password)
} catch (t: Throwable) {
error("Try to get build! TeamCity is unreachable!")
}
fun sendGetRequest(url: String, username: String? = null, password: String? = null) : String {
val connection = URL(url).openConnection() as HttpURLConnection
if (username != null && password != null) {
val auth = Base64.getEncoder().encode((username + ":" + password).toByteArray()).toString(Charsets.UTF_8)
connection.addRequestProperty("Authorization", "Basic $auth")
}
connection.setRequestProperty("Accept", "application/json");
connection.connect()
return connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
}
fun getBuildProperty(buildJsonDescription: String, property: String) =
with(JsonTreeParser.parse(buildJsonDescription) as JsonObject) {
if (getPrimitive("count").int == 0) {
error("No build information on TeamCity for $buildJsonDescription!")
}
(getArray("build").getObject(0).getPrimitive(property) as JsonLiteral).unquoted()
}
+1 -2
View File
@@ -3,9 +3,8 @@ project.ext {
commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt'] commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt']
jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm'] jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm']
nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native'] nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native']
} }
apply from: rootProject.file("${rootProject.rootDir}/gradle/benchmark.gradle") apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/benchmark.gradle")
kotlin.targets.native.compilations.main.cinterops { kotlin.targets.native.compilations.main.cinterops {
macros macros
struct struct
+6 -2
View File
@@ -1,3 +1,7 @@
import org.jetbrains.kotlin.MPPTools
import org.jetbrains.kotlin.PlatformInfo
import org.jetbrains.kotlin.RunJvmTask
buildscript { buildscript {
ext.rootBuildDirectory = file('../..') ext.rootBuildDirectory = file('../..')
@@ -64,7 +68,7 @@ kotlin {
MPPTools.addTimeListener(project) MPPTools.addTimeListener(project)
task konanRun { task konanRun {
if (MPPTools.isMacos()) { if (PlatformInfo.isMac()) {
dependsOn 'build' dependsOn 'build'
} }
} }
@@ -77,7 +81,7 @@ task jvmRun(type: RunJvmTask) {
task konanJsonReport { task konanJsonReport {
doLast { doLast {
if (MPPTools.isMacos()) { if (PlatformInfo.isMac()) {
def applicationName = "FrameworkBenchmarksAnalyzer" def applicationName = "FrameworkBenchmarksAnalyzer"
def frameworkPath = kotlin.macosX64("macos").binaries. def frameworkPath = kotlin.macosX64("macos").binaries.
getFramework(frameworkName, kotlin.macosX64("macos").binaries.RELEASE).outputFile.absolutePath getFramework(frameworkName, kotlin.macosX64("macos").binaries.RELEASE).outputFile.absolutePath
+11 -11
View File
@@ -1,3 +1,6 @@
import org.jetbrains.kotlin.MPPTools
import org.jetbrains.kotlin.RunJvmTask
apply plugin: 'kotlin-multiplatform' apply plugin: 'kotlin-multiplatform'
repositories { repositories {
@@ -54,6 +57,7 @@ kotlin {
} }
} }
jvm() { jvm() {
compilations.all { compilations.all {
tasks[compileKotlinTaskName].kotlinOptions { tasks[compileKotlinTaskName].kotlinOptions {
@@ -68,23 +72,20 @@ kotlin {
compilations.main.extraOpts = (project.hasProperty('compilerArgs') ? compilerArgs.split() : []) + '-opt' compilations.main.extraOpts = (project.hasProperty('compilerArgs') ? compilerArgs.split() : []) + '-opt'
binaries { binaries {
executable('benchmark', [RELEASE]) { executable('benchmark', [RELEASE]) {
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { if (project.hasProperty("linkerOpts")) {
linkerOpts = ["-L${getMingwPath()}/lib".toString()] 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.addTimeListener(project)
MPPTools.createRunTask(project, 'konanRun', kotlin.targets.native.binaries.getExecutable("benchmark", "RELEASE").runTask)
MPPTools.createRunTask(project, 'konanRun', kotlin.targets.native) {
workingDir = project.provider {
kotlin.targets.native.binaries.getExecutable("benchmark", buildType).outputDirectory
}
depends("build")
args("-w", "$nativeWarmup", "-r", "$attempts", "-o", "${buildDir.absolutePath}/${nativeBenchResults}", "-p", "${project.ext.applicationName}::")
}
task jvmRun(type: RunJvmTask) { task jvmRun(type: RunJvmTask) {
dependsOn 'build' dependsOn 'build'
@@ -129,7 +130,6 @@ task jvmJsonReport {
} }
jvmRun.finalizedBy jvmJsonReport jvmRun.finalizedBy jvmJsonReport
konanRun.finalizedBy konanJsonReport
private def getCommonProperties() { private def getCommonProperties() {
return ['cpu': System.getProperty("os.arch"), return ['cpu': System.getProperty("os.arch"),
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.MPPTools
def exitCodes = [:] def exitCodes = [:]
MPPTools.addTimeListener(project) MPPTools.addTimeListener(project)
+3 -1
View File
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.MPPTools
def dist = findProperty('org.jetbrains.kotlin.native.home') ?: 'dist' def dist = findProperty('org.jetbrains.kotlin.native.home') ?: 'dist'
dist = (new File(dist)).isAbsolute() ? dist : "${project.getProjectDir()}/$dist" dist = (new File(dist)).isAbsolute() ? dist : "${project.getProjectDir()}/$dist"
def toolExtension = System.getProperty("os.name").startsWith('Windows') ? ".bat" : "" def toolExtension = System.getProperty("os.name").startsWith('Windows') ? ".bat" : ""
@@ -7,4 +9,4 @@ project.ext {
buildSteps = ["runKonanc": ["$dist/bin/konanc$toolExtension", "${project.getProjectDir()}/src/main/kotlin/main.kt", "-o", buildSteps = ["runKonanc": ["$dist/bin/konanc$toolExtension", "${project.getProjectDir()}/src/main/kotlin/main.kt", "-o",
"${buildDir.absolutePath}/program${MPPTools.getNativeProgramExtension()}"]] "${buildDir.absolutePath}/program${MPPTools.getNativeProgramExtension()}"]]
} }
apply from: rootProject.file("${rootProject.rootDir}/gradle/compileBenchmark.gradle") apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/compileBenchmark.gradle")
+29
View File
@@ -0,0 +1,29 @@
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'
@@ -0,0 +1 @@
org.jetbrains.kotlin.native.home=../../dist
@@ -0,0 +1,39 @@
/*
* 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.
*/
package org.jetbrains.complexNumbers
actual class ComplexNumber() {}
actual class ComplexNumbersBenchmark actual constructor() {
actual fun generateNumbersSequence(): List<ComplexNumber> {
error("Benchmark generateNumbersSequence is unsupported on JVM!")
}
actual fun sumComplex() {
error("Benchmark sumComplex is unsupported on JVM!")
}
actual fun subComplex() {
error("Benchmark subComplex is unsupported on JVM!")
}
actual fun classInheritance() {
error("Benchmark classInheritance is unsupported on JVM!")
}
actual fun categoryMethods() {
error("Benchmark categoryMethods is unsupported on JVM!")
}
actual fun stringToObjC() {
error("Benchmark stringToObjC is unsupported on JVM!")
}
actual fun stringFromObjC() {
error("Benchmark stringToObjC is unsupported on JVM!")
}
actual fun fft() {
error("Benchmark fft is unsupported on JVM!")
}
actual fun invertFft() {
error("Benchmark invertFft is unsupported on JVM!")
}
}
@@ -0,0 +1,134 @@
/*
* 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.
*/
package org.jetbrains.complexNumbers
import kotlinx.cinterop.*
import platform.posix.*
import kotlin.math.sqrt
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
import platform.Foundation.*
import platform.darwin.*
actual typealias ComplexNumber = Complex
actual class ComplexNumbersBenchmark actual constructor() {
val complexNumbersSequence = generateNumbersSequence()
fun randomNumber() = Random.nextDouble(0.0, benchmarkSize.toDouble())
actual fun generateNumbersSequence(): List<Complex> {
val result = mutableListOf<Complex>()
for (i in 1..benchmarkSize) {
result.add(Complex(randomNumber(), randomNumber()))
}
return result
}
actual fun sumComplex() {
complexNumbersSequence.map { it.add(it) }.reduce { acc, it -> acc.add(it) }
}
actual fun subComplex() {
complexNumbersSequence.map { it.sub(it) }.reduce { acc, it -> acc.sub(it) }
}
actual fun classInheritance() {
class InvertedNumber(val value: Double) : CustomNumberProtocol, NSObject() {
override fun add(other: CustomNumberProtocol) : CustomNumberProtocol =
if (other is InvertedNumber)
InvertedNumber(-value + sqrt(other.value))
else
error("Expected object of InvertedNumber class")
override fun sub(other: CustomNumberProtocol) : CustomNumberProtocol =
if (other is InvertedNumber)
InvertedNumber(-value - sqrt(other.value))
else
error("Expected object of InvertedNumber class")
}
val result = InvertedNumber(0.0)
for (i in 1..benchmarkSize) {
result.add(InvertedNumber(randomNumber()))
result.sub(InvertedNumber(randomNumber()))
}
}
actual fun categoryMethods() {
complexNumbersSequence.map { it.mul(it) }.reduce { acc, it -> acc.mul(it) }
complexNumbersSequence.map { it.div(it) }.reduce { acc, it -> acc.mul(it) }
}
actual fun stringToObjC() {
complexNumbersSequence.forEach {
it.setFormat("%.1lf|%.1lf")
}
}
actual fun stringFromObjC() {
complexNumbersSequence.forEach {
it.description()?.split(" ")
}
}
private fun revert(number: Int, lg: Int): Int {
var result = 0
for (i in 0 until lg) {
if (number and (1 shl i) != 0) {
result = result or 1 shl (lg - i - 1)
}
}
return result
}
inline private fun fftRoutine(invert:Boolean = false): Array<Complex> {
var lg = 0
while ((1 shl lg) < complexNumbersSequence.size) {
lg++
}
val sequence = complexNumbersSequence.toTypedArray()
sequence.forEachIndexed { index, number ->
if (index < revert(index, lg) && revert(index, lg) < complexNumbersSequence.size) {
sequence[index] = sequence[revert(index, lg)].also { sequence[revert(index, lg)] = sequence[index] }
}
}
var length = 2
while (length < complexNumbersSequence.size) {
val angle = 2 * PI / length * if (invert) -1 else 1
val base = Complex(cos(angle), sin(angle))
for (i in 0 until complexNumbersSequence.size / 2 step length) {
var value = Complex(1.0, 1.0)
for (j in 0 until length/2) {
val first = sequence[i + j]
val second = sequence[i + j + length/2].mul(value)
sequence[i + j] = (first.add(second) as Complex)!!
sequence[i + j + length/2] = (first.sub(second) as Complex)!!
value = value.mul(base)!!
}
}
length = length shl 1
}
return sequence
}
actual fun fft() {
fftRoutine()
}
actual fun invertFft() {
val sequence = fftRoutine(true)
sequence.forEachIndexed { index, number ->
sequence[index] = number.div(Complex(sequence.size.toDouble(), 0.0)) ?: Complex(0.0, 0.0)
}
}
}
@@ -0,0 +1,32 @@
/*
* 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.benchmarksLauncher.*
import org.jetbrains.complexNumbers.*
import org.jetbrains.kliopt.*
class ObjCInteropLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) {
val complexNumbersBecnhmark = ComplexNumbersBenchmark()
override val benchmarks = BenchmarksCollection(
mutableMapOf(
"generateNumbersSequence" to complexNumbersBecnhmark::generateNumbersSequence,
"sumComplex" to complexNumbersBecnhmark::sumComplex,
"subComplex" to complexNumbersBecnhmark::subComplex,
"classInheritance" to complexNumbersBecnhmark::classInheritance,
"categoryMethods" to complexNumbersBecnhmark::categoryMethods,
"stringToObjC" to complexNumbersBecnhmark::stringToObjC,
"stringFromObjC" to complexNumbersBecnhmark::stringFromObjC,
"fft" to complexNumbersBecnhmark::fft,
"invertFft" to complexNumbersBecnhmark::invertFft
)
)
}
fun main(args: Array<String>) {
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
ObjCInteropLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!).launch(parser.getAll<String>("filter"))
})
}
@@ -0,0 +1,22 @@
/*
* 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.
*/
package org.jetbrains.complexNumbers
const val benchmarkSize = 10000
expect class ComplexNumber
expect class ComplexNumbersBenchmark() {
fun generateNumbersSequence(): List<ComplexNumber>
fun sumComplex()
fun subComplex()
fun classInheritance()
fun categoryMethods()
fun stringToObjC()
fun stringFromObjC()
fun fft()
fun invertFft()
}
@@ -0,0 +1,2 @@
package = org.jetbrains.complexNumbers
language = Objective-C
@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>
@protocol CustomNumber
@required
- (id<CustomNumber> _Nonnull)add: (id<CustomNumber> _Nonnull)other;
- (id<CustomNumber> _Nonnull)sub: (id<CustomNumber> _Nonnull)other;
@end
@interface Complex : NSObject<CustomNumber>
@property (nonatomic, readonly) double re;
@property (nonatomic, readonly) double im;
@property (nonatomic, readwrite) NSString *format;
- (id)initWithRe: (double)re andIm: (double)im;
+ (Complex *)complexWithRe: (double)re im: (double)im;
@end
@interface Complex (CategorizedComplex)
- (Complex * _Nonnull)mul: (Complex * _Nonnull)other;
- (Complex * _Nonnull)div: (Complex * _Nonnull)other;
@end
@@ -0,0 +1,62 @@
#import <stdio.h>
#import "complexNumbers.h"
@implementation Complex
{
double re;
double im;
NSString *format;
}
- (id)init {
return [self initWithRe: 0.0 andIm: 0.0];
}
- (id)initWithRe: (double)_re andIm: (double)_im {
if (self = [super init]) {
re = _re;
im = _im;
format = @"re: %.1lf im: %.1lf";
}
return self;
}
+ (Complex *)complexWithRe: (double)re im: (double)im {
return [[Complex alloc] initWithRe: re andIm: im];
}
- (id<CustomNumber> _Nonnull)add: (id<CustomNumber> _Nonnull)other {
if ([self isKindOfClass:[Complex class]]) {
Complex * otherComplex = (Complex *)other;
return [[Complex alloc] initWithRe: re + otherComplex->re andIm: im + otherComplex->im];
}
return NULL;
}
- (id<CustomNumber> _Nonnull)sub: (id<CustomNumber> _Nonnull)other {
if ([self isKindOfClass:[Complex class]]) {
Complex * otherComplex = (Complex *)other;
return [[Complex alloc] initWithRe: re - otherComplex->re andIm: im - otherComplex->im];
}
return NULL;
}
- (NSString *)description {
return [NSString stringWithFormat: format, re, im];
}
@end
@implementation Complex (CategorizedComplex)
- (Complex * _Nonnull)mul: (Complex * _Nonnull)other {
return [Complex complexWithRe: re * other.re - im * other.im im: re * other.im + im * other.re];
}
- (Complex * _Nonnull)div: (Complex * _Nonnull)other {
double retRe;
double retIm;
double denominator;
denominator = other.re * other.re + other.im * other.im;
if (!denominator)
return nil;
retRe = (re * other.re + im * other.im) / denominator;
retIm = (im * other.re - re * other.im) / denominator;
return [Complex complexWithRe: retRe im: retIm];
}
@end
+1 -1
View File
@@ -5,4 +5,4 @@ project.ext {
nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native'] nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native']
} }
apply from: rootProject.file("${rootProject.rootDir}/gradle/benchmark.gradle") apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/benchmark.gradle")
-5
View File
@@ -1,5 +0,0 @@
include ':ring'
include ':cinterop'
include ':helloworld'
include ':videoplayer'
include ':framework'
@@ -19,12 +19,20 @@ package org.jetbrains.benchmarksLauncher
import kotlin.math.sqrt import kotlin.math.sqrt
import org.jetbrains.report.BenchmarkResult import org.jetbrains.report.BenchmarkResult
import org.jetbrains.kliopt.* import org.jetbrains.kliopt.*
import kotlin.reflect.KFunction0
abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, val prefix: String = "") { abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, val prefix: String = "") {
class Results(val mean: Double, val variance: Double) class Results(val mean: Double, val variance: Double)
abstract val benchmarks: BenchmarksCollection abstract val benchmarks: BenchmarksCollection
fun add(name: String, benchmark:() -> Any?) {
fun benchmarkWrapper() {
benchmark()
}
benchmarks[name] = ::benchmarkWrapper
}
fun launch(filters: Collection<String>? = null, fun launch(filters: Collection<String>? = null,
filterRegexes: Collection<String>? = null): List<BenchmarkResult> { filterRegexes: Collection<String>? = null): List<BenchmarkResult> {
val regexes = filterRegexes?.map { it.toRegex() } ?: listOf() val regexes = filterRegexes?.map { it.toRegex() } ?: listOf()
+153
View File
@@ -0,0 +1,153 @@
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 {
ext.rootBuildDirectory = file('../..')
apply from: "$rootBuildDirectory/gradle/loadRootProperties.gradle"
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
repositories {
maven {
url 'https://cache-redirector.jetbrains.com/jcenter'
}
maven {
url kotlinCompilerRepo
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
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"
}
kotlin.srcDir "src"
kotlin.srcDir "../shared/src/main/kotlin"
kotlin.srcDir "$toolsPath/kliopt"
kotlin.srcDir "$toolsPath/benchmarks/shared/src"
}
macosMain {
dependsOn commonMain
kotlin.srcDir "../shared/src/main/kotlin-native"
}
}
macosX64("macos") {
compilations.main.extraOpts = (project.hasProperty('compilerArgs') ? compilerArgs.split() : []) + '-opt'
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 @@
org.jetbrains.kotlin.native.home=../../dist
@@ -0,0 +1,14 @@
/*
* 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.benchmarksLauncher.*
import org.jetbrains.kliopt.*
class SwiftLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) {
override val benchmarks = BenchmarksCollection(
mutableMapOf(
)
)
}
@@ -0,0 +1,122 @@
/*
* 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.
*/
package org.jetbrains.model
import org.jetbrains.multigraph.*
import kotlin.comparisons.compareBy
enum class Transport { CAR, UNDERGROUND, BUS, TROLLEYBUS, TRAM, TAXI, FOOT }
enum class Interest { SIGHT, CULTURE, PARK, ENTERTAINMENT }
class PlaceAbsenceException(message: String): Exception(message) {}
data class RouteCost(val moneyCost: Double, val timeCost: Double, val interests: Set<Interest>, val transport: Set<Transport>): Cost {
private val comparator = compareBy<RouteCost>({ it.moneyCost }, { it.timeCost }, { it.interests.size }, { it.transport.size })
override operator fun plus(other: Cost) =
if (other is RouteCost) {
RouteCost(moneyCost + other.moneyCost, timeCost + other.timeCost,
interests.union(other.interests), transport.union(other.transport))
} else {
error("Expected type is RouteCost")
}
override operator fun minus(other: Cost) =
if (other is RouteCost) {
RouteCost(if (moneyCost > other.moneyCost) moneyCost - other.moneyCost else 0.0,
if (timeCost > other.timeCost) timeCost - other.timeCost else 0.0,
interests.subtract(other.interests), transport.subtract(other.transport))
} else {
error("Expected type is RouteCost")
}
override operator fun compareTo(other: Cost) =
if (other is RouteCost) {
comparator.compare(this, other)
} else {
error("Expected type is RouteCost")
}
}
internal var placeCounter = 0u
data class Place(val geoCoordinateX: Double, val geoCoordinateY: Double, val name: String, val interestCategory: Interest) {
private val comparator = compareBy<Place>({ it.geoCoordinateX }, { it.geoCoordinateY })
val id: UInt
init {
id = placeCounter
placeCounter++
}
val fullDescription: String
get() = "Place $name($geoCoordinateX;$geoCoordinateY)"
fun compareTo(other: Place) =
comparator.compare(this, other)
}
data class Path(val from: Place, val to: Place, val cost: RouteCost)
class CityMap {
data class RouteId(val id: UInt, val from: UInt, val to: UInt)
private val graph = Multigraph<Place>()
val allPlaces: Set<Place>
get() = graph.allVertexes
val allRoutes: List<RouteId>
get() {
val edges = graph.allEdges
val result = mutableListOf<RouteId>()
edges.forEach {
result.add(RouteId(it, graph.getFrom(it).id, graph.getTo(it).id))
}
return result
}
fun addRoute(from: Place, to: Place, cost: RouteCost): UInt {
return graph.addEdge(from, to, cost)
}
fun getPlaceById(id: UInt): Place {
graph.allVertexes.forEach {
if (it.id == id) {
return it
}
}
throw PlaceAbsenceException("Place with id $id wasn't found.")
}
fun removePlaceById(id: UInt) {
graph.allVertexes.forEach {
if (it.id == id) {
graph.removeVertex(it)
return
}
}
}
fun removeRouteById(id: UInt) {
graph.removeEdge(id)
}
fun getRoutes(start: Place, finish: Place, limits: RouteCost): List<List<Path>> {
val result = graph.searchRoutesWithLimits(start, finish, limits)
return result.map {
it.map {
Path(graph.getFrom(it), graph.getTo(it), graph.getCost(it) as RouteCost)
}
}
}
fun getRouteById(id: UInt) =
graph.getEdgeById(id)
fun getAllStraightRoutesFrom(place: Place) =
graph.getEdgesFrom(place).map { Path(graph.getFrom(it.id), graph.getTo(it.id), graph.getCost(it.id) as RouteCost) }
fun isEmpty() = graph.isEmpty()
}
@@ -0,0 +1,184 @@
/*
* 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.
*/
package org.jetbrains.multigraph
import kotlin.math.pow
interface Cost {
operator fun plus(other: Cost): Cost
operator fun minus(other: Cost): Cost
override operator fun equals(other: Any?): Boolean
operator fun compareTo(other: Cost): Int
}
data class Edge<T>(val id: UInt, val from: T, val to: T, val cost: Cost) {
override operator fun equals(other: Any?): Boolean {
return if (other is Edge<*>) (from == other.from && to == other.to && cost == other.cost) else false
}
override fun hashCode(): Int =
from.hashCode() * 31.0.pow(2.0).toInt() + to.hashCode() * 31 + cost.hashCode()
}
class EdgeAbsenceMultigraphException(message: String): Exception(message) {}
class VertexAbsenceMultigraphException(message: String): Exception(message) {}
class Multigraph<T>() {
private var edges = mutableMapOf<T, MutableList<Edge<T>>>()
private var idCounter = 0u
val allVertexes: Set<T>
get() {
val outerVertexes = edges.keys
val innerVertexes = edges.map { (_, values) ->
values.map { it.to }.filter { it !in outerVertexes }
}.flatten()
return outerVertexes.union(innerVertexes)
}
val allEdges: List<UInt>
get() = edges.values.flatten().map { it.id }
fun getEdgeById(id: UInt): Edge<T> {
edges.forEach { (_, value) ->
value.forEach {
if (it.id == id)
return it
}
}
throw EdgeAbsenceMultigraphException("Edge with id $id wasn't found.")
}
fun copyMultigraph(): Multigraph<T> {
val newInstance = Multigraph<T>()
edges.forEach { (vertex, edges) ->
edges.forEach { edge ->
newInstance.addEdge(vertex, edge.to, edge.cost)
}
}
return newInstance
}
fun addEdge(from: T, to: T, cost: Cost): UInt {
val edge = Edge(idCounter, from, to, cost)
edges.getOrPut(from) { mutableListOf() }.add(edge)
idCounter++
return edge.id
}
fun removeEdge(id: UInt) {
try {
val edge = getEdgeById(id)
edges[edge.from]?.remove(edge)
} catch (exception: EdgeAbsenceMultigraphException) {
println("WARNING: no edge with id $id was found.")
}
}
fun removeVertex(vertex: T) {
edges.remove(vertex)
val edgesToRemove = edges.map { (_, values) ->
values.filter {
it.to == vertex
}
}.flatten()
edgesToRemove.forEach {
removeEdge(it.id)
}
}
fun checkVertexExistance(vertex: T): Boolean {
return vertex in allVertexes
}
fun getTo(edgeId: UInt) =
getEdgeById(edgeId).to
fun getFrom(edgeId: UInt) =
getEdgeById(edgeId).from
fun getCost(edgeId: UInt) =
getEdgeById(edgeId).cost
fun getEdgesFrom(vertex: T) =
edges[vertex] ?: listOf<Edge<T>>()
fun isEmpty() = edges.isEmpty()
fun searchRoutesWithLimits(start: T, finish: T, limits: Cost): List<List<UInt>> {
data class WaveStep(val costs: MutableList<Cost> = mutableListOf(),
val routes: MutableList<MutableList<UInt>> = mutableListOf(),
val vertexes: MutableList<MutableList<T>> = mutableListOf())
val currentStepsState = mutableMapOf<T, WaveStep>()
var oldFront = mutableSetOf<T>(start)
val newFront = mutableSetOf<T>()
if (!checkVertexExistance(start)) {
throw(VertexAbsenceMultigraphException("Start vertex wasn't found in graph."))
}
if (!checkVertexExistance(finish)) {
throw(VertexAbsenceMultigraphException("Finish vertex wasn't found in graph."))
}
allVertexes.forEach {
currentStepsState[it] = WaveStep()
}
while (!oldFront.isEmpty()) {
oldFront.forEach {
val currentStepState = currentStepsState[it] ?: WaveStep()
// Lookup all edges from vertex.
val values = edges.get(it) ?: mutableListOf<Edge<T>>()
values.forEach { edge ->
val newRoutes = mutableListOf<UInt>()
val toStep = currentStepsState[edge.to] ?: WaveStep()
// Create new pathes and count their costs.
if (currentStepState.routes.isEmpty()) {
val newVertexes = mutableListOf(edge.from, edge.to)
val newCost = edge.cost
if (newCost <= limits && edge.from != edge.to) {
newRoutes.add(edge.id)
toStep.routes.add(newRoutes)
toStep.costs.add(edge.cost)
toStep.vertexes.add(newVertexes)
currentStepsState[edge.to] = toStep
// Add new wave front.
if (edge.to != finish && edge.to !in oldFront) {
newFront.add(edge.to)
}
}
} else {
currentStepState.routes.forEachIndexed { index, it ->
val newRoutes = it.toMutableList()
val oldCost = currentStepState.costs.get(index)
val newCost = edge.cost + oldCost
val newVertexes = currentStepState.vertexes.get(index).toMutableList()
if (newCost <= limits && edge.to !in currentStepState.vertexes.get(index)) {
newRoutes.add(edge.id)
newVertexes.add(edge.to)
var addNewSequence = true
if (newRoutes !in toStep.routes) {
toStep.routes.add(newRoutes)
toStep.costs.add(newCost)
toStep.vertexes.add(newVertexes)
currentStepsState[edge.to] = toStep
if (edge.to != finish && edge.to !in oldFront) {
newFront.add(edge.to)
}
}
}
}
}
}
}
oldFront = newFront.toMutableSet()
newFront.clear()
}
return currentStepsState[finish]?.routes ?: listOf<List<UInt>>()
}
}
@@ -0,0 +1,225 @@
/*
* 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 Foundation
import CityMap
class SimpleCost: Cost {
let value: Int
init(cost: Int) {
value = cost
}
func plus(other: Cost) -> Cost {
let otherInstance = other as! SimpleCost
return SimpleCost(cost: value + otherInstance.value)
}
func minus(other: Cost) -> Cost {
let otherInstance = other as! SimpleCost
return SimpleCost(cost: value - otherInstance.value)
}
func compareTo(other: Cost) -> Int32 {
let otherInstance = other as! SimpleCost
if (value < otherInstance.value) {
return -1
}
if (value == otherInstance.value) {
return 0
}
return 1
}
}
class SwiftInteropBenchmarks {
let BENCHMARK_SIZE = 10000
let SMALL_BENCHMARK_SIZE = 50
let MEDIUM_BENCHMARK_SIZE = 100
var multigraph = Multigraph()
var cityMap = CityMap()
func randomInt(border: Int) -> Int {
return Int.random(in: 1 ..< border)
}
func randomDouble(border: Double) -> Double {
return Double.random(in: 0 ..< border)
}
func randomString(length: Int) -> String {
let letters = "abcdefghijklmnopqrst"
return String((0..<length).map{ _ in letters.randomElement()! })
}
func randomTransport() -> Transport {
let allValues = [Transport.car, Transport.underground, Transport.bus, Transport.trolleybus, Transport.tram, Transport.taxi, Transport.foot]
return allValues.randomElement()!
}
func randomInterest() -> Interest {
let allValues = [Interest.sight, Interest.culture, Interest.park, Interest.entertainment]
return allValues.randomElement()!
}
func randomPlace() -> Place {
return Place(geoCoordinateX: randomDouble(border: 180), geoCoordinateY: randomDouble(border: 90), name: randomString(length: 5), interestCategory: randomInterest())
}
func randomRouteCost() -> RouteCost {
let transportCount = randomInt(border: 7)
let interestCount = randomInt(border: 4)
var transports = Set<Transport>()
var interests = Set<Interest>()
for _ in 0...transportCount {
transports.insert(randomTransport())
}
for _ in 0...interestCount {
interests.insert(randomInterest())
}
return RouteCost(moneyCost: randomDouble(border: 10000), timeCost: randomDouble(border: 24), interests: interests, transport: transports)
}
func initMultigraph(size: Int) {
multigraph = Multigraph()
for i in 1...size {
multigraph.addEdge(from: i, to: i + 1, cost: SimpleCost(cost: (i + 1) % i ))
multigraph.addEdge(from: i, to: i * 2, cost: SimpleCost(cost: (i * 2) % i))
multigraph.addEdge(from: i + 5, to: i, cost: SimpleCost(cost: (i + 5) % i))
}
}
func createMultigraphOfInt() {
initMultigraph(size: BENCHMARK_SIZE)
}
func fillCityMap() {
cityMap = CityMap()
for _ in 0...BENCHMARK_SIZE {
cityMap.addRoute(from: randomPlace(), to: randomPlace(), cost: randomRouteCost())
}
}
func initCityMap(size: Int) {
cityMap = CityMap()
let allValuesInterests = [Interest.sight, Interest.culture, Interest.park, Interest.entertainment]
let allValuesTransport = [Transport.car, Transport.underground, Transport.bus, Transport.trolleybus, Transport.tram, Transport.taxi, Transport.foot]
for i in 1...size {
let from = Place(geoCoordinateX: Double(i % 180), geoCoordinateY: Double(i % 90 + 90 % i),
name: randomString(length: 5), interestCategory: allValuesInterests[i % allValuesInterests.count])
let to = Place(geoCoordinateX: Double(i % 180 + 180 % i), geoCoordinateY: Double(i % 90),
name: randomString(length: 5), interestCategory: allValuesInterests[(i + 5) % allValuesInterests.count])
var transports = Set<Transport>()
var interests = Set<Interest>()
for j in 0...i % 2 + 1 {
interests.insert(allValuesInterests[(i + j) % allValuesInterests.count])
}
for j in 0...i % 2 + 1 {
transports.insert(allValuesTransport[i % allValuesTransport.count])
}
let cost = RouteCost(moneyCost: Double((i * 2) % 10000), timeCost: Double((i + 3) % 24), interests: interests, transport: transports)
cityMap.addRoute(from: from, to: to, cost: cost)
}
}
func searchRoutesInSwiftMultigraph() {
initMultigraph(size: SMALL_BENCHMARK_SIZE)
for _ in 0...SMALL_BENCHMARK_SIZE {
var vertexes = Array(multigraph.allVertexes)
var result = multigraph.searchRoutesWithLimits(start: 1,
finish: SMALL_BENCHMARK_SIZE / 2 + SMALL_BENCHMARK_SIZE / 4,
limits: SimpleCost(cost: SMALL_BENCHMARK_SIZE / 5))
var count = result.map{ $0.count }.reduce(0, +)
}
}
func searchTravelRoutes() {
cityMap = CityMap()
initCityMap(size: BENCHMARK_SIZE)
let transports: Set = [Transport.car, Transport.underground]
let interests: Set = [Interest.sight, Interest.culture]
let cost = RouteCost(moneyCost: 500, timeCost: 6, interests: interests, transport: transports)
for _ in 0...SMALL_BENCHMARK_SIZE {
var result = cityMap.getRoutes(start: Array(cityMap.allPlaces).first!, finish: Array(cityMap.allPlaces).last!, limits: cost)
var totalCost = result.flatMap{ $0 }.map { $0.cost.moneyCost }.reduce(0, +)
}
}
func availableTransportOnMap() {
cityMap = CityMap()
initCityMap(size: MEDIUM_BENCHMARK_SIZE)
Set(cityMap.allRoutes.map { (cityMap.getRouteById(id: $0.id).cost as! RouteCost).transport })
}
func allPlacesMapedByInterests() {
cityMap = CityMap()
initCityMap(size: MEDIUM_BENCHMARK_SIZE)
let placesByInterests = cityMap.allPlaces.reduce([Interest: Array<Place>]()) { (dict, place) -> [Interest: Array<Place>] in
var dict = dict
if (dict[place.interestCategory] != nil) {
dict[place.interestCategory]?.append(place)
} else {
dict[place.interestCategory] = [place]
}
return dict
}
}
func getAllPlacesWithStraightRoutesTo() {
cityMap = CityMap()
initCityMap(size: MEDIUM_BENCHMARK_SIZE)
for _ in 0...SMALL_BENCHMARK_SIZE {
let start = cityMap.allPlaces.randomElement()!
let availableRoutes = cityMap.getAllStraightRoutesFrom(place: start)
var _ = availableRoutes.map { $0.to }
}
}
func goToAllAvailablePlaces() {
cityMap = CityMap()
initCityMap(size: MEDIUM_BENCHMARK_SIZE)
for _ in 0...SMALL_BENCHMARK_SIZE {
let start = cityMap.allPlaces.randomElement()!
let availableRoutes = cityMap.getAllStraightRoutesFrom(place: start)
availableRoutes.map { 2 * $0.cost.moneyCost }
}
}
func removeVertexAndEdgesSwiftMultigraph() {
initMultigraph(size: SMALL_BENCHMARK_SIZE)
let multigraphCopy = multigraph.doCopyMultigraph()
var edges = multigraphCopy.allEdges
while (!edges.isEmpty) {
multigraphCopy.removeEdge(id: UInt32(edges.randomElement()!))
let vertexes = multigraphCopy.allVertexes
multigraphCopy.removeVertex(vertex: vertexes.randomElement()!)
edges = multigraphCopy.allEdges
}
}
func stringInterop() {
cityMap = CityMap()
fillCityMap()
let place = cityMap.allPlaces.first!
for _ in 0...BENCHMARK_SIZE {
let _ = place.fullDescription
}
}
func simpleFunction() {
cityMap = CityMap()
fillCityMap()
let place = cityMap.allPlaces.first!
for _ in 0...BENCHMARK_SIZE {
let _ = place.compareTo(other:place)
}
}
}
@@ -0,0 +1,31 @@
/*
* 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 Foundation
import CityMap
var runner = BenchmarksRunner()
let args = KotlinArray(size: Int32(CommandLine.arguments.count - 1), init: {index in
CommandLine.arguments[Int(truncating: index) + 1]
})
runner.runBenchmarks(args: args, run: { (parser: ArgParser) -> [BenchmarkResult] in
var swiftBenchmarks = SwiftInteropBenchmarks()
var swiftLauncher = SwiftLauncher(numWarmIterations: parser.get(name: "warmup") as! Int32,
numberOfAttempts: parser.get(name: "repeat") as! Int32, prefix: parser.get(name: "prefix") as! String)
swiftLauncher.add(name: "createMultigraphOfInt", benchmark: swiftBenchmarks.createMultigraphOfInt)
swiftLauncher.add(name: "fillCityMap", benchmark: swiftBenchmarks.fillCityMap)
swiftLauncher.add(name: "searchRoutesInSwiftMultigraph", benchmark: swiftBenchmarks.searchRoutesInSwiftMultigraph)
swiftLauncher.add(name: "searchTravelRoutes", benchmark: swiftBenchmarks.searchTravelRoutes)
swiftLauncher.add(name: "availableTransportOnMap", benchmark: swiftBenchmarks.availableTransportOnMap)
swiftLauncher.add(name: "allPlacesMapedByInterests", benchmark: swiftBenchmarks.allPlacesMapedByInterests)
swiftLauncher.add(name: "getAllPlacesWithStraightRoutesTo", benchmark: swiftBenchmarks.getAllPlacesWithStraightRoutesTo)
swiftLauncher.add(name: "goToAllAvailablePlaces", benchmark: swiftBenchmarks.goToAllAvailablePlaces)
swiftLauncher.add(name: "removeVertexAndEdgesSwiftMultigraph", benchmark: swiftBenchmarks.removeVertexAndEdgesSwiftMultigraph)
swiftLauncher.add(name: "stringInterop", benchmark: swiftBenchmarks.stringInterop)
swiftLauncher.add(name: "simpleFunction", benchmark: swiftBenchmarks.simpleFunction)
return swiftLauncher.launch(filters: parser.getAll(name: "filter"), filterRegexes: parser.getAll(name: "filterRegex"))
}, parseArgs: runner.parse, collect: { (benchmarks: [BenchmarkResult], parser: ArgParser) -> Void in
runner.collect(results: benchmarks, parser: parser)
})
+13 -10
View File
@@ -1,36 +1,39 @@
import org.jetbrains.kotlin.PlatformInfo
import org.jetbrains.kotlin.MPPTools
def dist = findProperty('org.jetbrains.kotlin.native.home') ?: 'dist' def dist = findProperty('org.jetbrains.kotlin.native.home') ?: 'dist'
dist = (new File(dist)).isAbsolute() ? dist : "${project.getProjectDir()}/$dist" dist = (new File(dist)).isAbsolute() ? dist : "${project.getProjectDir()}/$dist"
def toolExtension = System.getProperty("os.name").startsWith('Windows') ? ".bat" : "" def toolExtension = System.getProperty("os.name").startsWith('Windows') ? ".bat" : ""
def linkerOpts = [] def linkerOpts = []
if (MPPTools.isMacos()) { if (PlatformInfo.isMac()) {
linkerOpts += ['-linker-options','-L/opt/local/lib', '-linker-options', '-L/usr/local/lib'] linkerOpts += ['-linker-options','-L/opt/local/lib', '-linker-options', '-L/usr/local/lib']
} else if (MPPTools.isLinux()) { } else if (PlatformInfo.isLinux()) {
linkerOpts += ['-linker-options', '-L/usr/lib/x86_64-linux-gnu', '-linker-options', '-L/usr/lib64'] linkerOpts += ['-linker-options', '-L/usr/lib/x86_64-linux-gnu', '-linker-options', '-L/usr/lib64']
} else if (MPPTools.isWindows()) { } else if (PlatformInfo.isWindows()) {
linkerOpts += ['-linker-options', "-L${MPPTools.mingwPath()}/lib"] linkerOpts += ['-linker-options', "-L${MPPTools.mingwPath()}/lib"]
} }
def includeDirsFfmpeg = [] def includeDirsFfmpeg = []
def filterDirsFfmpeg = [] def filterDirsFfmpeg = []
if (MPPTools.isMacos()) { if (PlatformInfo.isMac()) {
filterDirsFfmpeg += ['-headerFilterAdditionalSearchPrefix', '/opt/local/include', filterDirsFfmpeg += ['-headerFilterAdditionalSearchPrefix', '/opt/local/include',
'-headerFilterAdditionalSearchPrefix', '/usr/local/include'] '-headerFilterAdditionalSearchPrefix', '/usr/local/include']
} else if (MPPTools.isLinux()) { } else if (PlatformInfo.isLinux()) {
filterDirsFfmpeg += ['-headerFilterAdditionalSearchPrefix', '/usr/include', filterDirsFfmpeg += ['-headerFilterAdditionalSearchPrefix', '/usr/include',
'-headerFilterAdditionalSearchPrefix', '/usr/include/x86_64-linux-gnu', '-headerFilterAdditionalSearchPrefix', '/usr/include/x86_64-linux-gnu',
'-headerFilterAdditionalSearchPrefix', '/usr/include/ffmpeg'] '-headerFilterAdditionalSearchPrefix', '/usr/include/ffmpeg']
} else if (MPPTools.isWindows()) { } else if (PlatformInfo.isWindows()) {
includeDirsFfmpeg += ['-compiler-option', "-I${MPPTools.mingwPath()}/include"] includeDirsFfmpeg += ['-compiler-option', "-I${MPPTools.mingwPath()}/include"]
} }
def includeDirsSdl = [] def includeDirsSdl = []
if (MPPTools.isMacos()) { if (PlatformInfo.isMac()) {
includeDirsSdl += ['-compiler-option', '-I/opt/local/include/SDL2', includeDirsSdl += ['-compiler-option', '-I/opt/local/include/SDL2',
'-compiler-option', '-I/usr/local/include/SDL2'] '-compiler-option', '-I/usr/local/include/SDL2']
} else if (MPPTools.isLinux()) { } else if (PlatformInfo.isLinux()) {
includeDirsSdl += ['-compiler-option', '-I/usr/include/SDL2'] includeDirsSdl += ['-compiler-option', '-I/usr/include/SDL2']
} else if (MPPTools.isWindows()) { } else if (PlatformInfo.isWindows()) {
includeDirsSdl += ['-compiler-option', "-I${MPPTools.mingwPath()}/include/SDL2"] includeDirsSdl += ['-compiler-option', "-I${MPPTools.mingwPath()}/include/SDL2"]
} }
@@ -47,4 +50,4 @@ project.ext {
"-Xmulti-platform", "$dist/../samples/videoplayer/src/videoPlayerMain/kotlin", "-Xmulti-platform", "$dist/../samples/videoplayer/src/videoPlayerMain/kotlin",
"-entry", "sample.videoplayer.main"] + linkerOpts] "-entry", "sample.videoplayer.main"] + linkerOpts]
} }
apply from: rootProject.file("${rootProject.rootDir}/gradle/compileBenchmark.gradle") apply from: rootProject.file("${rootProject.rootDir}/performance/gradle/compileBenchmark.gradle")
+13 -3
View File
@@ -1,3 +1,6 @@
import org.jetbrains.kotlin.PlatformInfo
import org.jetbrains.kotlin.konan.target.HostManager
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
@@ -29,8 +32,16 @@ include ':common'
include ':backend.native:tests' include ':backend.native:tests'
include ':backend.native:debugger-tests' include ':backend.native:debugger-tests'
include ':utilities' include ':utilities'
//include ':performance' TODO: return when there is one HostManager class version include ':performance'
//include ':tools:benchmarksAnalyzer' include ':performance:ring'
include ':performance:cinterop'
include ':performance:helloworld'
include ':performance:videoplayer'
include ':performance:framework'
if (PlatformInfo.isAppleTarget(HostManager.host)) {
include ':performance:objcinterop'
include ':performance:swiftinterop'
}
include ':platformLibs' include ':platformLibs'
includeBuild 'shared' includeBuild 'shared'
@@ -38,7 +49,6 @@ includeBuild 'extracted/konan.metadata'
includeBuild 'extracted/konan.serializer' includeBuild 'extracted/konan.serializer'
includeBuild 'tools/kotlin-native-gradle-plugin' includeBuild 'tools/kotlin-native-gradle-plugin'
if (hasProperty("kotlinProjectPath")) { if (hasProperty("kotlinProjectPath")) {
include ':runtime:generator' include ':runtime:generator'
includeBuild(kotlinProjectPath) { includeBuild(kotlinProjectPath) {