Skip to content

Commit 061d79a

Browse files
authored
Support registering multiplatform source sets as benchmark targets (#112)
1 parent f4740f2 commit 061d79a

File tree

9 files changed

+136
-6
lines changed

9 files changed

+136
-6
lines changed

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ kotlin {
9999
# Configuration
100100

101101
In a `build.gradle` file create `benchmark` section, and inside it add a `targets` section.
102-
In this section register all targets you want to run benchmarks from.
102+
In this section register all compilations you want to run benchmarks for.
103+
`register` should either be called on the name of a target (e.g. `"jvm"`) which will register its `main` compilation
104+
(meaning that `register("jvm")` and `register("jvmMain")` register the same compilation)
105+
Or on the name of a source set (e.g. `"jvmTest"`, `"jsBenchmark"`) which will register the apt compilation
106+
(e.g. `register("jsFoo")` uses the `foo` compilation defined for the `js` target)
103107
Example for multiplatform project:
104108

105109
```groovy
@@ -211,6 +215,7 @@ benchmark {
211215
# Separate source sets for benchmarks
212216

213217
Often you want to have benchmarks in the same project, but separated from main code, much like tests. Here is how:
218+
For a Kotlin/JVM project:
214219

215220
Define source set:
216221
```groovy
@@ -241,6 +246,27 @@ benchmark {
241246
}
242247
```
243248

249+
For a Kotlin Multiplatform project:
250+
251+
Define a new compilation in whichever target you'd like (e.g. `jvm`, `js`, etc):
252+
```groovy
253+
kotlin {
254+
jvm {
255+
compilations.create('benchmark') { associateWith(compilations.main) }
256+
}
257+
}
258+
```
259+
260+
Register it by its source set name (`jvmBenchmark` is the name for the `benchmark` compilation for `jvm` target):
261+
262+
```groovy
263+
benchmark {
264+
targets {
265+
register("jvmBenchmark")
266+
}
267+
}
268+
```
269+
244270
# Examples
245271

246272
The project contains [examples](https://github.com/Kotlin/kotlinx-benchmark/tree/master/examples) subproject that demonstrates using the library.

examples/kotlin-multiplatform/build.gradle

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ allOpen {
1414
}
1515

1616
kotlin {
17-
jvm()
17+
jvm {
18+
compilations.create('benchmark') { associateWith(compilations.main) }
19+
}
1820
js('jsIr', IR) { nodejs() }
1921
js('jsIrBuiltIn', IR) { nodejs() }
2022
wasm { d8() }
@@ -101,10 +103,16 @@ benchmark {
101103

102104
// Setup configurations
103105
targets {
104-
// This one matches compilation base name, e.g. 'jvm', 'jvmTest', etc
106+
// This one matches target name, e.g. 'jvm', 'js',
107+
// and registers its 'main' compilation, so 'jvm' registers 'jvmMain'
105108
register("jvm") {
106109
jmhVersion = "1.21"
107110
}
111+
// This one matches source set name, e.g. 'jvmMain', 'jvmTest', etc
112+
// and register the corresponding compilation (here the 'benchmark' compilation declared in the 'jvm' target)
113+
register("jvmBenchmark") {
114+
jmhVersion = "1.21"
115+
}
108116
register("jsIr")
109117
register("jsIrBuiltIn") {
110118
jsBenchmarksExecutor = JsBenchmarksExecutor.BuiltIn
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package test
2+
3+
import org.openjdk.jmh.annotations.*
4+
import java.util.concurrent.*
5+
6+
@State(Scope.Benchmark)
7+
@Fork(1)
8+
@BenchmarkMode(Mode.AverageTime)
9+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
10+
// jvmBenchmark can access declarations from jvmMain!
11+
@Warmup(iterations = WARMUP_ITERATIONS, time = 1, timeUnit = TimeUnit.SECONDS)
12+
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
13+
class JvmBenchmark {
14+
private var data = 0.0
15+
16+
@Setup
17+
fun setUp() {
18+
data = 3.0
19+
}
20+
21+
@Benchmark
22+
fun sqrtBenchmark(): Double {
23+
return Math.sqrt(data)
24+
}
25+
26+
@Benchmark
27+
fun cosBenchmark(): Double {
28+
return Math.cos(data)
29+
}
30+
}
31+

examples/kotlin-multiplatform/src/jvmMain/kotlin/JvmTestBenchmark.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ package test
33
import org.openjdk.jmh.annotations.*
44
import java.util.concurrent.*
55

6+
const val WARMUP_ITERATIONS = 20
67
@State(Scope.Benchmark)
78
@Fork(1)
89
@BenchmarkMode(Mode.AverageTime)
910
@OutputTimeUnit(TimeUnit.NANOSECONDS)
10-
@Warmup(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS)
11+
@Warmup(iterations = WARMUP_ITERATIONS, time = 1, timeUnit = TimeUnit.SECONDS)
1112
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
1213
class JvmTestBenchmark {
1314
private var data = 0.0
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package kotlinx.benchmark.integration
2+
3+
enum class JsBenchmarksExecutor {
4+
BenchmarkJs,
5+
BuiltIn
6+
}
7+
8+
class BenchmarkTarget {
9+
var jmhVersion: String? = null
10+
var jsBenchmarksExecutor: JsBenchmarksExecutor? = null
11+
12+
fun lines(name: String): List<String> = """
13+
register("$name") {
14+
${jmhVersion?.let { "jmhVersion = \"$it\"" } ?: ""}
15+
${jsBenchmarksExecutor?.let { "jsBenchmarksExecutor = JsBenchmarksExecutor.${it.name}" } ?: ""}
16+
}
17+
""".trimIndent().split("\n")
18+
}

integration/src/main/kotlin/kotlinx/benchmark/integration/ProjectBuilder.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import java.io.*
44

55
class ProjectBuilder {
66
private val configurations = mutableMapOf<String, BenchmarkConfiguration>()
7+
private val targets = mutableMapOf<String, BenchmarkTarget>()
78

89
fun configuration(name: String, configuration: BenchmarkConfiguration.() -> Unit = {}) {
910
configurations[name] = BenchmarkConfiguration().apply(configuration)
1011
}
12+
fun register(name: String, configuration: BenchmarkTarget.() -> Unit = {}) {
13+
targets[name] = BenchmarkTarget().apply(configuration)
14+
}
1115

1216
fun build(original: String): String {
1317

@@ -17,6 +21,9 @@ benchmark {
1721
configurations {
1822
${configurations.flatMap { it.value.lines(it.key) }.joinToString("\n ")}
1923
}
24+
targets {
25+
${targets.flatMap { it.value.lines(it.key) }.joinToString("\n ")}
26+
}
2027
}
2128
""".trimIndent()
2229

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package kotlinx.benchmark.integration
2+
3+
import java.io.*
4+
import kotlin.test.*
5+
6+
class SourceSetAsBenchmarkTargetTest : GradleTest() {
7+
8+
@Test
9+
fun testSupportForSourceSetsAsBenchmarkTargets() {
10+
val jvmBenchmark = "jvmBenchmark"
11+
val configuration = "jsonDefault"
12+
val targets = listOf("jsIr", "wasm", "jvm", "native", jvmBenchmark)
13+
14+
val runner =
15+
project("kotlin-multiplatform", true) {
16+
configuration(configuration) {
17+
iterations = 1
18+
iterationTime = 100
19+
iterationTimeUnit = "ms"
20+
}
21+
register(jvmBenchmark) { jmhVersion = "1.21" }
22+
}
23+
24+
runner.run("${configuration}Benchmark")
25+
val reports = reports(configuration)
26+
assertEquals(targets.size, reports.size)
27+
assertEquals(targets.map { "$it.json" }.toSet(), reports.map(File::getName).toSet())
28+
}
29+
}

integration/src/test/resources/templates/kotlin-multiplatform/build.gradle

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
22
import org.jetbrains.kotlin.konan.target.HostManager
33

44
kotlin {
5-
jvm()
5+
jvm {
6+
compilations.create('benchmark') { associateWith(compilations.main) }
7+
}
68
js('jsIr', IR) { nodejs() }
79
wasm { d8() }
810

@@ -22,6 +24,12 @@ kotlin {
2224
implementation(benchmarkRuntimeJvm)
2325
}
2426
}
27+
jvmBenchmark {
28+
dependsOn(jvmMain)
29+
dependencies {
30+
implementation(benchmarkRuntimeJvm)
31+
}
32+
}
2533
jsIrMain {
2634
dependencies {
2735
implementation(benchmarkRuntimeJsIr)

plugin/main/src/kotlinx/benchmark/gradle/BenchmarksExtension.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ open class BenchmarksExtension(val project: Project) {
5151
when {
5252
multiplatform != null -> {
5353
val target = multiplatform.targets.findByName(name)
54-
when (val compilation = target?.compilations?.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)) {
54+
// We allow the name to be either a target or a source set
55+
when (val compilation = target?.compilations?.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)
56+
?: multiplatform.targets.flatMap { it.compilations }.find { it.defaultSourceSetName == name }) {
5557
null -> {
5658
project.logger.warn("Warning: Cannot find a benchmark compilation '$name', ignoring.")
5759
BenchmarkTarget(this, name) // ignore

0 commit comments

Comments
 (0)