Skip to content

Commit f43fb80

Browse files
committed
chore: kotlinx benchmarking support
1 parent bfcdabe commit f43fb80

File tree

11 files changed

+239
-9
lines changed

11 files changed

+239
-9
lines changed

backend/build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,9 @@ application {
1919

2020
mppTargetName = "jvm"
2121

22-
dependencies { implementation(projects.common) }
22+
dependencies {
23+
implementation(projects.common)
24+
25+
// Specify the classifier using variantOf
26+
// implementation(variantOf(libs.lwjgl.opengl) { classifier("natives-linux") })
27+
}

benchmarks/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Run Benchmarks
2+
3+
```bash
4+
$ ./gradlew :benchmarks:benchmark
5+
```
6+
7+
### Resources
8+
9+
- [Kotlin Multiplatform Benchmarking](https://github.com/Kotlin/kotlinx-benchmark/tree/master/examples)

benchmarks/build.gradle.kts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import common.mppTargetName
2+
3+
plugins {
4+
plugins.kotlin.mpp
5+
alias(libs.plugins.kotlinx.benchmark)
6+
alias(libs.plugins.kotlin.allopen)
7+
}
8+
9+
allOpen { annotation("org.openjdk.jmh.annotations.State") }
10+
11+
benchmark {
12+
targets {
13+
register("jvm")
14+
register("desktop")
15+
// register("js")
16+
}
17+
18+
configurations {
19+
named("main") {
20+
warmups = 5 // number of warmup iterations
21+
iterations = 5 // number of iterations
22+
iterationTime = 3 // time in seconds per iteration
23+
iterationTimeUnit = "ms"
24+
advanced("jvmForks", 3)
25+
advanced("jsUseBridge", true)
26+
}
27+
}
28+
}
29+
30+
mppTargetName = "jvm"
31+
32+
dependencies {
33+
commonMainImplementation(projects.common)
34+
commonMainImplementation(libs.kotlinx.bench.runtime)
35+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package bench
2+
3+
import kotlin.math.*
4+
import kotlinx.benchmark.*
5+
6+
@State(Scope.Benchmark)
7+
@Measurement(iterations = 3, time = 1, timeUnit = BenchmarkTimeUnit.SECONDS)
8+
@OutputTimeUnit(BenchmarkTimeUnit.MILLISECONDS)
9+
@BenchmarkMode(Mode.AverageTime)
10+
class CommonBenchmark {
11+
private var data = 0.0
12+
private lateinit var text: String
13+
14+
@Setup
15+
fun setUp() {
16+
data = 3.0
17+
text = "Hello!"
18+
}
19+
20+
@TearDown fun teardown() {}
21+
22+
@Benchmark
23+
fun exception() {
24+
try {
25+
fail()
26+
} catch (e: Throwable) {
27+
throw Exception("I failed!", e)
28+
}
29+
}
30+
31+
private fun fail() {
32+
TODO("not implemented")
33+
}
34+
35+
@Benchmark
36+
fun mathBenchmark(): Double {
37+
return log(sqrt(data) * cos(data), 2.0)
38+
}
39+
40+
@Benchmark
41+
fun longBenchmark(): Double {
42+
var value = 1.0
43+
repeat(1000) { value *= text.length }
44+
return value
45+
}
46+
47+
@Benchmark
48+
fun longBlackholeBenchmark(bh: Blackhole) {
49+
repeat(1000) { bh.consume(text.length) }
50+
}
51+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package bench
2+
3+
import java.util.concurrent.*
4+
import org.openjdk.jmh.annotations.*
5+
6+
const val WARMUP_ITERATIONS = 20
7+
8+
@State(Scope.Benchmark)
9+
@Fork(1)
10+
@BenchmarkMode(Mode.AverageTime)
11+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
12+
@Warmup(iterations = WARMUP_ITERATIONS, time = 1, timeUnit = TimeUnit.SECONDS)
13+
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
14+
class JvmTestBenchmark {
15+
private var data = 0.0
16+
17+
@Setup
18+
fun setUp() {
19+
data = 3.0
20+
}
21+
22+
@Benchmark
23+
fun sqrtBenchmark(): Double {
24+
return Math.sqrt(data)
25+
}
26+
27+
@Benchmark
28+
fun cosBenchmark(): Double {
29+
return Math.cos(data)
30+
}
31+
}

common/src/jvmMain/kotlin/dev/suresh/Application.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ fun main() {
1414
it.join().throwIfFailed()
1515
println(subTask.get())
1616
}
17+
18+
langFeatures()
19+
stdlibFeatures()
1720
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package dev.suresh
2+
3+
import kotlin.time.Duration.Companion.microseconds
4+
import kotlin.time.TimeSource
5+
6+
enum class Planet(val moon: Int) {
7+
MERCURY(0),
8+
VENUS(0),
9+
EARTH(1),
10+
MARS(2),
11+
JUPITER(5),
12+
SATURN(66),
13+
URANUS(62),
14+
NEPTUNE(13)
15+
}
16+
17+
data object MyService
18+
19+
@JvmInline
20+
value class Person(private val name: String) {
21+
init {
22+
check(name.isNotBlank()) { "Name should not be empty" }
23+
}
24+
25+
constructor(firstName: String, lastName: String) : this("$firstName $lastName") {
26+
check(firstName.isNotBlank()) { "First name should not be empty" }
27+
check(lastName.isNotBlank()) { "Last name should not be empty" }
28+
}
29+
}
30+
31+
fun langFeatures() {
32+
println(Planet.entries.filter { it.moon == 1 })
33+
// MyService::class.createInstance() - Throws error
34+
println(MyService)
35+
36+
println(Person("Foo"))
37+
println(Person("Foo", "Bar"))
38+
}
39+
40+
fun stdlibFeatures() {
41+
42+
val timeSource = TimeSource.Monotonic
43+
val m1 = timeSource.markNow()
44+
Thread.sleep(100)
45+
val m2 = timeSource.markNow()
46+
println(m2.elapsedNow() + 2.microseconds)
47+
println(m1 + 2.microseconds)
48+
println(m2 - m1)
49+
50+
val regex = """\b(?<city>[A-Za-z\s]+),\s(?<state>[A-Z]{2}),\s(?<areacode>[0-9]{5})\b""".toRegex()
51+
val match = regex.find("San Jose, CA, 95124")!!
52+
println(match.groups)
53+
println(match.groups["city"]?.value)
54+
println(match.groups["state"]?.value)
55+
println(match.groups["areacode"]?.value)
56+
57+
val hexFormat = HexFormat {
58+
this.upperCase = true
59+
this.bytes {
60+
this.bytePrefix = "0x"
61+
this.byteSeparator = ":"
62+
this.bytesPerLine = 4
63+
this.bytesPerGroup = 2
64+
this.groupSeparator = " "
65+
}
66+
67+
this.number {
68+
this.prefix = "0x"
69+
this.removeLeadingZeros = true
70+
}
71+
}
72+
73+
println(123232.toHexString(hexFormat))
74+
val hex = "Kotlin 1.9.0".encodeToByteArray().toHexString(hexFormat)
75+
println(hex)
76+
println(hex.hexToByteArray(hexFormat).decodeToString())
77+
}

gradle/build-logic/common-plugins/src/main/kotlin/plugins/kotlin.mpp.gradle.kts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,12 @@ kotlinMultiplatform.apply {
134134
val jvmMain by getting {
135135
dependencies {
136136
implementation(libs.kotlin.stdlib.jdk8)
137-
// https://kotlinlang.org/docs/ksp-multiplatform.html
138-
project.dependencies.add("kspJvm", libs.ksp.auto.service)
137+
implementation(libs.kotlin.reflect)
139138
implementation(libs.google.auto.annotations)
140139
implementation(libs.slf4j.api)
140+
141+
// https://kotlinlang.org/docs/ksp-multiplatform.html
142+
project.dependencies.add("kspJvm", libs.ksp.auto.service)
141143
}
142144
}
143145

@@ -250,6 +252,9 @@ if (!isNodeJSConfigured.toBoolean()) {
250252
download = true
251253
lockFileDirectory = project.rootDir.resolve("gradle/kotlin-js-store")
252254
isNodeJSConfigured = "true"
255+
256+
yarnLockMismatchReport = YarnLockMismatchReport.WARNING
257+
yarnLockAutoReplace = false
253258
}
254259
}
255260
}

gradle/libs.versions.toml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ kotlin-jvmtarget = "20"
66
kotlin-dsl-jvmtarget = "17"
77
kotlin-api-version = "1.9"
88
kotlin-lang-version = "2.0"
9-
gradle = "8.2"
9+
gradle = "8.2.1"
1010
java-vendor = "Oracle"
1111
java-jvmArguments = "--enable-preview"
1212
java-addModules = "jdk.incubator.vector"
@@ -39,10 +39,11 @@ ajalt-clikt = "4.0.0"
3939
ajalt-colormath = "3.3.1"
4040
compose-routing = "0.2.12"
4141
classgraph = "4.8.160"
42+
cache4k = "0.11.0"
4243
dokka = "1.8.20"
4344
intellij-markdown = "0.4.1"
4445
jgit = "6.5.0.202303070854-r"
45-
jte = "3.0.0"
46+
jte = "3.0.1"
4647
junit = "5.10.0-RC1"
4748
ktor = "2.3.2"
4849
koin = "3.4.1"
@@ -71,12 +72,14 @@ kotlin-retry = "1.0.9"
7172
kmp-store5 = "5.0.0-beta01"
7273
kmp-settings = "1.0.0"
7374
parsus = "0.4.0"
75+
java-keyring = "1.0.3"
76+
java-keychain = "1.1.0"
7477

7578

7679
# Plugin versions
7780
benmanes = "0.47.0"
7881
compose-mpp = "0.0.0"
79-
foojay-resolver = "0.5.0"
82+
foojay-resolver = "0.6.0"
8083
gradle-enterprise = "3.13.4"
8184
nexus-publish = "2.0.0-rc-1"
8285
shadow = "8.1.1"
@@ -97,6 +100,7 @@ build-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle
97100
build-kotlin-noarg = { module = "org.jetbrains.kotlin:kotlin-noarg" , version.ref = "kotlin"}
98101
build-kotlinx-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization" , version.ref = "kotlin"}
99102
build-kotlinx-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu-gradle-plugin" , version.ref = "kotlinx-atomicfu"}
103+
build-kotlinx-benchmark = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-plugin" , version.ref = "kotlinx-benchmark"}
100104
build-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin" , version.ref = "dokka"}
101105
build-kotlin-ksp = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin" , version.ref = "kotlin-ksp"}
102106
build-ksp-redacted = { module = "dev.zacsweers.redacted:redacted-compiler-plugin-gradle" , version.ref = "ksp-redacted"}
@@ -119,6 +123,7 @@ build-wire-plugin = { module = "com.squareup.wire:wire-gradle-plug
119123
build-poko-plugin = { module = "dev.drewhamilton.poko:poko-gradle-plugin" , version.ref = "poko-plugin"}
120124
build-kotlinx-bincompat = { module = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin" , version.ref = "kotlinx-bincompat"}
121125

126+
122127
# Gradle Dependencies
123128
kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom" , version.ref = "kotlin"}
124129
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib" , version.ref = "kotlin"}
@@ -139,6 +144,7 @@ kotlinx-lincheck = { module = "org.jetbrains.kotlinx:lincheck"
139144
kotlinx-reflect-lite = { module = "org.jetbrains.kotlinx:kotlinx.reflect.lite" , version.ref = "kotlinx-reflect-lite"}
140145
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable" , version.ref = "kotlinx-collections-immutable"}
141146
kotlinx-html = { module = "org.jetbrains.kotlinx:kotlinx-html" , version.ref = "kotlinx-html"}
147+
kotlinx-bench-runtime = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime" , version.ref = "kotlinx-benchmark"}
142148

143149
ktor-bom = { module = "io.ktor:ktor-bom" , version.ref = "ktor"}
144150
ktor-server = { module = "io.ktor:ktor-server-core" , version.ref = "ktor"}
@@ -174,6 +180,7 @@ benasher44-uuid = { module = "com.benasher44:uuid"
174180
store5 = { module = "org.mobilenativefoundation.store:store5" , version.ref = "kmp-store5" }
175181
multiplatform-settings = { module = "com.russhwolf:multiplatform-settings" , version.ref = "kmp-settings" }
176182
parsus = { module = "me.alllex.parsus:parsus" , version.ref = "parsus" }
183+
cache4k = { module = "io.github.reactivecircus.cache4k:cache4k" , version.ref = "cache4k" }
177184

178185
ajalt-mordant = { module = "com.github.ajalt.mordant:mordant" , version.ref = "ajalt-mordant"}
179186
ajalt-colormath = { module = "com.github.ajalt.colormath:colormath" , version.ref = "ajalt-colormath"}
@@ -210,6 +217,9 @@ log4j-bom = { module = "org.apache.logging.log4j:log4j-bom"
210217
log4j-core = { module = "org.apache.logging.log4j:log4j-core" , version.ref = "log4j"}
211218
log4j-jpl = { module = "org.apache.logging.log4j:log4j-jpl" , version.ref = "log4j"}
212219

220+
java-keyring = { module = "com.github.javakeyring:java-keyring" , version.ref = "java-keyring"}
221+
java-keychain = { module = "pt.davidafsilva.apple:jkeychain" , version.ref = "java-keychain"}
222+
213223
compose-routing = { module = "app.softwork:routing-compose" , version.ref = "compose-routing" }
214224

215225
compose-icons-cssgg = { module = "br.com.devsrsouza.compose.icons:css-gg" , version.ref = "compose-icons" }
@@ -224,7 +234,9 @@ compose-icons-simpleIcons = { module = "br.com.devsrsouza.compose.icons:simpl
224234
compose-icons-tablerIcons = { module = "br.com.devsrsouza.compose.icons:tabler-icons" , version.ref = "compose-icons" }
225235

226236
[plugins]
227-
benmanes = { id = "com.github.ben-manes.versions" , version.ref = "benmanes" }
228237
jte = { id = "gg.jte.gradle" , version.ref = "jte" }
238+
kotlin-allopen = { id = "org.jetbrains.kotlin.plugin.allopen" , version.ref = "kotlin"}
239+
kotlinx-benchmark = { id = "org.jetbrains.kotlinx.benchmark" , version.ref = "kotlinx-benchmark" }
240+
benmanes = { id = "com.github.ben-manes.versions" , version.ref = "benmanes" }
229241
bestpractices = { id = "com.autonomousapps.plugin-best-practices-plugin" , version.ref = "best-practices-plugin" }
230242
graalvm-nativeimage = { id = "org.graalvm.buildtools.native" , version.ref = "graalvm-nativeimage"}

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

settings.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ include(":web")
2020

2121
include(":compose-web")
2222

23-
include("desktop")
23+
include(":desktop")
24+
25+
include(":benchmarks")

0 commit comments

Comments
 (0)