Skip to content
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

Introduce TreapList #12

Merged
merged 3 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions benchmarks/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ benchmark {

register("compare") {
param("size", "10", "1000", "10000")
param("implementation", "hash_map", "hamt", "treap")
param("implementation", "java", "treap")
}

register("named") {
param("size", "10", "1000", "10000")
param("implementation", "hash_map", "hamt", "treap")
param("implementation", "java", "treap")
include("${project.findProperty("benchmark")}")
}

Expand All @@ -62,7 +62,15 @@ benchmark {
include("immutableMap.ParallelUpdateValues")
}

register("list") {
param("size", "1", "10", "1000", "10000")
param("implementation", "treap", "java")

include("benchmarks.immutableList")
}

configureEach {
reportFormat = "csv"
warmups = 5
iterations = 10
iterationTime = 100
Expand Down
33 changes: 33 additions & 0 deletions benchmarks/src/main/kotlin/benchmarks/FakePersistentList.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package benchmarks

import kotlinx.collections.immutable.*

class FakePersistentList<T>(val value: List<T>) : PersistentList<T>, List<T> by value {
class Builder<T>(val value: MutableList<T>) : PersistentList.Builder<T>, MutableList<T> by value {
override fun equals(other: Any?) = value == other
override fun hashCode() = value.hashCode()
override fun build() = FakePersistentList(value)
}

override fun equals(other: Any?) = value == other
override fun hashCode() = value.hashCode()

override fun builder() = Builder(value.toMutableList())
override fun clear() = FakePersistentList(emptyList<T>())

override fun add(element: T): PersistentList<T> = FakePersistentList(value + element)
override fun add(index: Int, element: T): PersistentList<T> = FakePersistentList(value.toMutableList().apply { add(index, element) })
override fun addAll(elements: Collection<T>): PersistentList<T> = FakePersistentList(value + elements)
override fun addAll(index: Int, c: Collection<T>): PersistentList<T> = FakePersistentList(value.toMutableList().apply { addAll(index, c) })
override fun remove(element: T): PersistentList<T> = FakePersistentList(value - element)
override fun removeAll(predicate: (T) -> Boolean): PersistentList<T> = FakePersistentList(value.filterNot(predicate))
override fun removeAll(elements: Collection<T>): PersistentList<T> = FakePersistentList(value - elements)
override fun removeAt(index: Int): PersistentList<T> = FakePersistentList(value.toMutableList().apply { removeAt(index) })
override fun retainAll(elements: Collection<T>): PersistentList<T> = FakePersistentList(value.filter { it !in elements})
override fun set(index: Int, element: T): PersistentList<T> = FakePersistentList(value.toMutableList().apply { set(index, element) })

override fun subList(fromIndex: Int, toIndex: Int): ImmutableList<T> =
super<PersistentList>.subList(fromIndex, toIndex)
}

fun <T> fakePersistentListOf(): PersistentList<T> = FakePersistentList(emptyList<T>())
6 changes: 3 additions & 3 deletions benchmarks/src/main/kotlin/benchmarks/hashCodeTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private fun generateIntWrappers(hashCodeType: String, size: Int): List<IntWrappe
fun generateKeys(hashCodeType: String, size: Int) = generateIntWrappers(hashCodeType, size)
fun generateElements(hashCodeType: String, size: Int) = generateIntWrappers(hashCodeType, size)

const val ORDERED_HAMT_IMPL = "ordered_hamt"
const val HAMT_IMPL = "hamt"
const val KOTLIN_IMPL = "kotlin"
const val KOTLIN_ORDERED_IMPL = "kotlin_ordered"
const val TREAP_IMPL = "treap"
const val HASH_MAP_IMPL = "hash_map"
const val JAVA_IMPL = "java"
60 changes: 60 additions & 0 deletions benchmarks/src/main/kotlin/benchmarks/immutableList/Add.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Modified from the kotlinx.collections.immutable sources, which contained the following notice:
* Copyright 2016-2019 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package benchmarks.immutableList

import benchmarks.*
import kotlinx.collections.immutable.*
import kotlinx.benchmark.*

@State(Scope.Benchmark)
open class Add {
@Param(KOTLIN_IMPL, TREAP_IMPL, JAVA_IMPL)
var implementation = ""

@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
var size: Int = 0

var initial = persistentListOf<String>()

@Setup
fun prepare() {
initial = persistentListAdd(implementation, size)
}

@Benchmark
fun addLast(): ImmutableList<String> {
return initial.add("another element")
}

/**
* Adds [size] - 1 elements to an empty persistent list
* and then inserts one element at the beginning.
*
* Measures mean time and memory spent per `add` operation.
*
* Expected time: nearly constant.
* Expected memory: nearly constant.
*/
@Benchmark
fun addFirst(): ImmutableList<String> {
return initial.add(0, "another element")
}

/**
* Adds [size] - 1 elements to an empty persistent list
* and then inserts one element at the middle.
*
* Measures mean time and memory spent per `add` operation.
*
* Expected time: nearly constant.
* Expected memory: nearly constant.
*/
@Benchmark
fun addMiddle(): ImmutableList<String> {
return initial.add(initial.size / 2, "another element")
}
}
107 changes: 107 additions & 0 deletions benchmarks/src/main/kotlin/benchmarks/immutableList/AddAll.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Modified from the kotlinx.collections.immutable sources, which contained the following notice:
* Copyright 2016-2019 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package benchmarks.immutableList

import benchmarks.*
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.benchmark.*

@State(Scope.Benchmark)
open class AddAll {
@Param(KOTLIN_IMPL, TREAP_IMPL, JAVA_IMPL)
var implementation = ""

@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
var size: Int = 0

private var initialHalf = persistentListOf<String>()
private var initialTwoThirds = persistentListOf<String>()

private var listToAdd = emptyList<String>()
private var halfList = emptyList<String>()
private var oneThirdList = emptyList<String>()

@Setup
fun prepare() {
listToAdd = persistentListAdd(implementation, size)
halfList = persistentListAdd(implementation, size / 2)
initialHalf = persistentListAdd(implementation, size - halfList.size)
oneThirdList = persistentListAdd(implementation, size / 3)
initialTwoThirds = persistentListAdd(implementation, size - oneThirdList.size)
}

// Results of the following benchmarks do not indicate memory or time spent per operation,
// however regressions there do indicate changes.
//
// the benchmarks measure mean time and memory spent per added element.
//
// Expected time: nearly constant.
// Expected memory: nearly constant.

/**
* Adds [size] elements to an empty persistent list using `addAll` operation.
*/
@Benchmark
fun addAllLast(): ImmutableList<String> {
return emptyPersistentList<String>(implementation).addAll(listToAdd)
}

/**
* Adds `size / 2` elements to an empty persistent list
* and then adds `size - size / 2` elements using `addAll` operation.
*/
@Benchmark
fun addAllLast_Half(): ImmutableList<String> {
return initialHalf.addAll(halfList)
}

/**
* Adds `size - size / 3` elements to an empty persistent list
* and then adds `size / 3` elements using `addAll` operation.
*/
@Benchmark
fun addAllLast_OneThird(): ImmutableList<String> {
return initialTwoThirds.addAll(oneThirdList)
}

/**
* Adds `size / 2` elements to an empty persistent list
* and then inserts `size - size / 2` elements at the beginning using `addAll` operation.
*/
@Benchmark
fun addAllFirst_Half(): ImmutableList<String> {
return initialHalf.addAll(0, halfList)
}

/**
* Adds `size - size / 3` elements to an empty persistent list
* and then inserts `size / 3` elements at the beginning using `addAll` operation.
*/
@Benchmark
fun addAllFirst_OneThird(): ImmutableList<String> {
return initialTwoThirds.addAll(0, oneThirdList)
}

/**
* Adds `size / 2` elements to an empty persistent list
* and then inserts `size - size / 2` elements at the middle using `addAll` operation.
*/
@Benchmark
fun addAllMiddle_Half(): ImmutableList<String> {
return initialHalf.addAll(initialHalf.size / 2, halfList)
}

/**
* Adds `size - size / 3` elements to an empty persistent list builder
* and then inserts `size / 3` elements at the middle using `addAll` operation.
*/
@Benchmark
fun addAllMiddle_OneThird(): ImmutableList<String> {
return initialTwoThirds.addAll(initialTwoThirds.size / 2, oneThirdList)
}
}
37 changes: 37 additions & 0 deletions benchmarks/src/main/kotlin/benchmarks/immutableList/Construct.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package benchmarks.immutableList

import benchmarks.*
import kotlinx.collections.immutable.*
import kotlinx.benchmark.*

@State(Scope.Benchmark)
open class Construct {
@Param(KOTLIN_IMPL, TREAP_IMPL, JAVA_IMPL)
var implementation = ""

@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
var size: Int = 0

var toAdd = listOf<Int>()

@Setup
fun prepare() {
toAdd = (1..size).toList()
}

@Benchmark
fun oneAtATime(): ImmutableList<Int> {
var list = emptyPersistentList<Int>(implementation)
toAdd.forEach {
list = list.add(it)
}
return list
}

@Benchmark
fun addAll(): ImmutableList<Int> {
var list = emptyPersistentList<Int>(implementation)
list = list.addAll(toAdd)
return list
}
}
35 changes: 35 additions & 0 deletions benchmarks/src/main/kotlin/benchmarks/immutableList/Get.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Modified from the kotlinx.collections.immutable sources, which contained the following notice:
* Copyright 2016-2019 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package benchmarks.immutableList

import benchmarks.*
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.benchmark.*

@State(Scope.Benchmark)
open class Get {
@Param(KOTLIN_IMPL, TREAP_IMPL, JAVA_IMPL)
var implementation = ""

@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
var size: Int = 0

private var persistentList: PersistentList<String> = persistentListOf()

@Setup
fun prepare() {
persistentList = persistentListAdd(implementation, size)
}

@Benchmark
fun getByIndex(bh: Blackhole) {
for (i in 0 until size) {
bh.consume(persistentList[i])
}
}
}
57 changes: 57 additions & 0 deletions benchmarks/src/main/kotlin/benchmarks/immutableList/Iterate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Modified from the kotlinx.collections.immutable sources, which contained the following notice:
* Copyright 2016-2019 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package benchmarks.immutableList

import benchmarks.*
import com.certora.collect.TreapList
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.benchmark.*

@State(Scope.Benchmark)
open class Iterate {
@Param(KOTLIN_IMPL, TREAP_IMPL, JAVA_IMPL)
var implementation = ""

@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
var size: Int = 0

private var persistentList: PersistentList<String> = persistentListOf()

@Setup
fun prepare() {
persistentList = persistentListAdd(implementation, size)
}

@Benchmark
fun firstToLast(bh: Blackhole) {
for (e in persistentList) {
bh.consume(e)
}
}

@Benchmark
fun lastToFirst(bh: Blackhole) {
val iterator = persistentList.listIterator(size)

while (iterator.hasPrevious()) {
bh.consume(iterator.previous())
}
}

@Benchmark
fun forEachElement(bh: Blackhole) {
when (val list = persistentList) {
is TreapList<*> -> list.forEachElement { e ->
bh.consume(e)
}
else -> list.forEach { e ->
bh.consume(e)
}
}
}
}
Loading
Loading