Hi, I’m benchmarking Collections fast api and Coll...
# kotlin-native
j
Hi, I’m benchmarking Collections fast api and Collections stdlib api. The fast api implements random-access of List. It is implemented like this: ListUtils.kt I expected the fast api to be always fast. The fast api calculates size only once, and the stdlib api calculates size in every
next()
operation. (stdlib api transforms to Iterator) (
next()
implementation code: ArrayList.java) But sometimes the stdlib api comes out faster. At higher numbers, the stdlib api is faster in most cases. Why is this result occurring? I’ll post the benchmarking code I used in a thread.
Copy code
suspend fun main() = coroutineScope {
    val times = List(/*100_000*/ 2_000_000_000) {} as ArrayList<Unit>
    val decimal = DecimalFormat("#,###")

    launch {
        var average = 0L
        launch {
            repeat(10) { fastCount ->
                launch(<http://Dispatchers.IO|Dispatchers.IO>) {
                    average += measureNanoTime {
                        var value = 0
                        times.fastForEach {
                            value++
                        }
                    }.also { result ->
                        println("[$fastCount] Collections Fast API: ${result}ns")
                    }
                }
            }
        }.join()
        println("[AVERAGE] Collections Fast API: ${decimal.format(average / 10)}ns")
    }

    launch {
        var average = 0L
        launch {
            repeat(10) { normalCount ->
                launch(<http://Dispatchers.IO|Dispatchers.IO>) {
                    average += measureNanoTime {
                        var value = 0
                        times.forEach {
                            value++
                        }
                    }.also { result ->
                        println("[$normalCount] Collections Normal API: ${result}ns")
                    }
                }
            }
        }.join()
        println("[AVERAGE] Collections Normal API: ${decimal.format(average / 10)}ns")
    }

    Unit
}

@Suppress("BanInlineOptIn")
@OptIn(ExperimentalContracts::class)
inline fun <T> List<T>.fastForEach(action: (T) -> Unit) {
    contract { callsInPlace(action) }
    for (index in indices) {
        val item = get(index)
        action(item)
    }
}
e
how is this related to #kotlin-native?
but by running them in parallel, your runs can impact each other, and by not discarding warmup runs, you are getting noise from JIT. use kotlinx.benchmark or jmh for benchmarking.
j
I thought this channel was suitable as it consists of pure Kotlin code. Is there a better channel? sorry.
My benchmarking method was wrong! Then understand that I chose the wrong channel. Thanks for letting me know. I'll try again.
e
this channel is for Kotlin/Native, see the channel description. your code mentions
DecimalFormat
which is JVM-only
j
Oh, sorry I didn't know that method was JVM specific. So which channel should kotlin-jvm go to? #kotlin-jvm doesn't seem to exist.
e
the channels outside of #multiplatform and #javascript and #kotlin-native are mostly JVM
but I'm not sure this is even a Kotlin question - the performance of
List.iterator()
vs
List.get()
is entirely down to the Java implementation
(if you were running the benchmark after compiling with Kotlin/Native, that would feel more fitting here since the native collections are implemented by Kotlin)
j
You’re right. I think I asked the wrong question. I should have thought more about whether this is really a Kotlin domain. Thanks for the explanation.