-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiplatform benchmarks baseline #4350
Changes from 6 commits
ac51ba2
a07767e
d4ea356
99c1a64
0a389fd
9ac96bb
1b9137e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,21 @@ | ||||||
## kotlinx-coroutines-core benchmarks | ||||||
|
||||||
Multiplatform benchmarks for kotlinx-coroutines-core. | ||||||
|
||||||
This source-set contains benchmarks that leverage `internal` API (e.g. `suspendCancellableCoroutineReusable`) or | ||||||
that are multiplatform (-> only supported with `kotlinx-benchmarks` which is less convenient than `jmh` plugin). | ||||||
For JVM-only non-internal benchmarks, consider using `benchmarks` top-level project. | ||||||
|
||||||
### Usage | ||||||
|
||||||
``` | ||||||
// JVM only | ||||||
./gradlew :kotlinx-coroutines-core:jvmBenchmarkBenchmarkJar | ||||||
java -jar kotlinx-coroutines-core/build/benchmarks/jvmBenchmark/jars/kotlinx-coroutines-core-jvmBenchmark-jmh-*-JMH.jar | ||||||
|
||||||
// Native, OS X | ||||||
./gradlew :kotlinx-coroutines-core:macosArm64BenchmarkBenchmark | ||||||
|
||||||
// Figure out what to use | ||||||
./gradlew :kotlinx-coroutines-core:tasks | grep -i bench | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Seems much more reliable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I explicitly opted into mine version -- shorter, more robust (also, will showcase non-launcing tasks, for example |
||||||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package kotlinx.coroutines | ||
|
||
import kotlinx.coroutines.* | ||
import kotlinx.coroutines.flow.* | ||
import kotlinx.benchmark.* | ||
|
||
// Stresses out 'syncrhonozed' codepath in MutableSharedFlow | ||
@State(Scope.Benchmark) | ||
@Measurement(iterations = 3, time = 1, timeUnit = BenchmarkTimeUnit.SECONDS) | ||
@OutputTimeUnit(BenchmarkTimeUnit.MICROSECONDS) | ||
@BenchmarkMode(Mode.AverageTime) | ||
open class SharedFlowBaseline { | ||
private var size: Int = 10_000 | ||
|
||
@Benchmark | ||
fun baseline() = runBlocking { | ||
val flow = MutableSharedFlow<Unit>() | ||
launch { | ||
repeat(size) { flow.emit(Unit) } | ||
} | ||
|
||
flow.take(size).collect { } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import org.gradle.api.tasks.testing.* | ||
import org.gradle.kotlin.dsl.* | ||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension | ||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet | ||
import org.jetbrains.kotlin.gradle.plugin.mpp.* | ||
import org.jetbrains.kotlin.gradle.targets.native.tasks.* | ||
import org.jetbrains.kotlin.gradle.tasks.* | ||
|
@@ -59,6 +61,8 @@ kotlin { | |
} | ||
} | ||
} | ||
setupBenchmarkSourceSets(sourceSets) | ||
|
||
/* | ||
* Configure two test runs for Native: | ||
* 1) Main thread | ||
|
@@ -84,13 +88,45 @@ kotlin { | |
jvm { | ||
// For animal sniffer | ||
withJava() | ||
compilations.create("benchmark") { associateWith([email protected]("main")) } | ||
} | ||
} | ||
|
||
benchmark { | ||
targets { | ||
register("jvmBenchmark") | ||
private fun KotlinMultiplatformExtension.setupBenchmarkSourceSets(ss: NamedDomainObjectContainer<KotlinSourceSet>) { | ||
// Forgive me, Father, for I have sinned. | ||
// Really, that is needed to have benchmark sourcesets be the part of the project, not a separate project | ||
val benchmarkMain by ss.creating { | ||
dependencies { | ||
implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:${version("benchmarks")}") | ||
} | ||
// For each source set we have to manually set path to the sources, otherwise lookup will fail | ||
kotlin.srcDir("benchmarks/main/kotlin") | ||
} | ||
|
||
@Suppress("UnusedVariable") | ||
val jvmBenchmark by ss.creating { | ||
// For each source set we have to manually set path to the sources, otherwise lookup will fail | ||
kotlin.srcDir("benchmarks/jvm/kotlin") | ||
} | ||
|
||
targets.matching { | ||
it.name != "metadata" | ||
// Doesn't work, don't want to figure it out for now | ||
qwwdfsad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
&& !it.name.contains("wasm") | ||
&& !it.name.contains("js") | ||
}.all { | ||
compilations.create("benchmark") { | ||
associateWith([email protected]("main")) | ||
defaultSourceSet { | ||
dependencies { | ||
implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:${version("benchmarks")}") | ||
} | ||
dependsOn(benchmarkMain) | ||
} | ||
} | ||
} | ||
|
||
targets.matching { it.name != "metadata" }.all { | ||
benchmark.targets.register("${name}Benchmark") | ||
} | ||
} | ||
|
||
|
@@ -131,10 +167,12 @@ val allMetadataJar by tasks.getting(Jar::class) { setupManifest(this) } | |
|
||
fun setupManifest(jar: Jar) { | ||
jar.manifest { | ||
attributes(mapOf( | ||
"Premain-Class" to "kotlinx.coroutines.debug.internal.AgentPremain", | ||
"Can-Retransform-Classes" to "true", | ||
)) | ||
attributes( | ||
mapOf( | ||
"Premain-Class" to "kotlinx.coroutines.debug.internal.AgentPremain", | ||
"Can-Retransform-Classes" to "true", | ||
) | ||
) | ||
} | ||
} | ||
|
||
|
@@ -187,9 +225,11 @@ fun Test.configureJvmForLincheck(segmentSize: Int = 1) { | |
minHeapSize = "1g" | ||
maxHeapSize = "4g" // we may need more space for building an interleaving tree in the model checking mode | ||
// https://github.com/JetBrains/lincheck#java-9 | ||
jvmArgs = listOf("--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED", // required for transformation | ||
jvmArgs = listOf( | ||
"--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED", // required for transformation | ||
"--add-exports", "java.base/sun.security.action=ALL-UNNAMED", | ||
"--add-exports", "java.base/jdk.internal.util=ALL-UNNAMED") // in the model checking mode | ||
"--add-exports", "java.base/jdk.internal.util=ALL-UNNAMED" | ||
) // in the model checking mode | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pro tip: use Difftastic when reviewing such changes! In a structural diff, the trivial formatting edits don't show up at all. |
||
// Adjust internal algorithmic parameters to increase the testing quality instead of performance. | ||
systemProperty("kotlinx.coroutines.semaphore.segmentSize", segmentSize) | ||
systemProperty("kotlinx.coroutines.semaphore.maxSpinCycles", 1) // better for the model checking mode | ||
|
@@ -215,6 +255,9 @@ kover { | |
// lincheck has NPE error on `ManagedStrategyStateHolder` class | ||
excludedClasses.addAll("org.jetbrains.kotlinx.lincheck.*") | ||
} | ||
sources { | ||
excludedSourceSets.addAll("benchmark") | ||
} | ||
} | ||
|
||
reports { | ||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth plugging
benchmarks_jmh_version=1.37
here, otherwise benchmarks will use pretty ancient version of JMH (1.21).