Skip to content

Commit

Permalink
Benchmark awaiting heavier computations in the benchmarks
Browse files Browse the repository at this point in the history
Some conclusions:
1. Calling `runBlocking` without a `CoroutineContext` should be equivalent to calling it with `Dispatchers.Unconfined`, both of which run on the original single thread of the caller.
1. Awaiting empty `async`s is dependent on single-core performance.
1. Both `Dispatchers.Default` and `Dispatchers.IO` utilize all the cores for computation.
1. `await` is much heavier on `Dispatchers.IO`.
1. `await` is lightest when calling `runBlocking` without a `CoroutineContext` or on `Dispatchers.Unconfined`.
  • Loading branch information
ShreckYe committed Nov 27, 2024
1 parent 0ef8aa2 commit c1ab4a8
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import kotlinx.benchmark.State
import kotlinx.benchmark.Warmup

@State(Scope.Benchmark)
@Warmup(time = 1, iterations = 8)
@Warmup(time = 1, iterations = 8) // 4 seems not enough
@Measurement(time = 1, iterations = 8)
abstract class AbstractBenchmark
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.huanshankeji.kotlinx.coroutines.benchmark

abstract class AbstractRunBlockingAwaitAsyncsBenchmark : AbstractBenchmark() {
abstract fun runBlockingAwait1mAsyncs()

abstract fun runBlockingAwait1KAsync1mSums()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll

@Suppress("SuspendFunctionOnCoroutineScope")
internal suspend inline fun CoroutineScope.await1MAasyncs() {
internal suspend inline fun CoroutineScope.await1mAsyncs() {
List(1 shl 20) { async {} }.awaitAll()
}

internal val `1mSizeList` = List(1 shl 20) { it }

// It seems the loop get optimized and removed in this function.
@Suppress("SuspendFunctionOnCoroutineScope")
internal suspend inline fun CoroutineScope.await1kAsync1mLoops() {
List(1 shl 10) { async { repeat(1 shl 20) {} } }.awaitAll()
}

@Suppress("SuspendFunctionOnCoroutineScope")
internal suspend inline fun CoroutineScope.await1kAsync1mSums() {
List(1 shl 10) { async { `1mSizeList`.sum() } }.awaitAll()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Param
import kotlinx.coroutines.*

class ParameterizedRunBlockingAwaitAsyncsBenchmark : AbstractBenchmark() {
class ParameterizedRunBlockingAwaitAsyncsBenchmark : AbstractRunBlockingAwaitAsyncsBenchmark() {
enum class DispatcherArgumentEnum {
Default, /*Main,*/ Unconfined, IO, SingleThread
}
Expand All @@ -14,18 +14,21 @@ class ParameterizedRunBlockingAwaitAsyncsBenchmark : AbstractBenchmark() {

@OptIn(ExperimentalCoroutinesApi::class, DelicateCoroutinesApi::class)
val singleThreadContext = newSingleThreadContext("single thread")
val dispatcher
get() = when (dispatcherArgumentEnum) {
DispatcherArgumentEnum.Default -> Dispatchers.Default
//DispatcherArgumentEnum.Main -> Dispatchers.Main
DispatcherArgumentEnum.Unconfined -> Dispatchers.Unconfined
DispatcherArgumentEnum.IO -> Dispatchers.IO
DispatcherArgumentEnum.SingleThread -> singleThreadContext
}


@Benchmark
fun runBlockingAwait1MAsyncsWithDispatcherArgument() =
runBlocking(
when (dispatcherArgumentEnum) {
DispatcherArgumentEnum.Default -> Dispatchers.Default
//DispatcherArgumentEnum.Main -> Dispatchers.Main
DispatcherArgumentEnum.Unconfined -> Dispatchers.Unconfined
DispatcherArgumentEnum.IO -> Dispatchers.IO
DispatcherArgumentEnum.SingleThread -> singleThreadContext
}
) {
await1MAasyncs()
}
override fun runBlockingAwait1mAsyncs() =
runBlocking(dispatcher) { await1mAsyncs() }

@Benchmark
override fun runBlockingAwait1KAsync1mSums() =
runBlocking(dispatcher) { await1kAsync1mSums() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package com.huanshankeji.kotlinx.coroutines.benchmark
import kotlinx.benchmark.Benchmark
import kotlinx.coroutines.runBlocking

class RunBlockingAwaitAsyncsBenchmark : AbstractBenchmark() {
class RunBlockingAwaitAsyncsBenchmark : AbstractRunBlockingAwaitAsyncsBenchmark() {
@Benchmark
fun runBlockingAwait1MAsyncs() =
runBlocking { await1MAasyncs() }
override fun runBlockingAwait1mAsyncs() =
runBlocking { await1mAsyncs() }

@Benchmark
override fun runBlockingAwait1KAsync1mSums() =
runBlocking { await1kAsync1mSums() }
}

0 comments on commit c1ab4a8

Please sign in to comment.