Skip to content

Commit a6d45f5

Browse files
author
Abduqodiri Qurbonzoda
committed
Persistent list batch update tests and benchmarks
1 parent 2036d5e commit a6d45f5

File tree

10 files changed

+781
-0
lines changed

10 files changed

+781
-0
lines changed

benchmarks-mpp/src/jvmMain/kotlin/benchmarks/immutableList/Add.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,32 @@ open class Add {
3535
bh.consume(list[i])
3636
}
3737
}
38+
39+
/**
40+
* Adds [size] - 1 elements to an empty persistent list
41+
* and then inserts one element at the beginning.
42+
*
43+
* Measures mean time and memory spent per `add` operation.
44+
*
45+
* Expected time: nearly constant.
46+
* Expected memory: nearly constant.
47+
*/
48+
@Benchmark
49+
fun addFirst(): ImmutableList<String> {
50+
return persistentListAdd(size - 1).add(0, "another element")
51+
}
52+
53+
/**
54+
* Adds [size] - 1 elements to an empty persistent list
55+
* and then inserts one element at the middle.
56+
*
57+
* Measures mean time and memory spent per `add` operation.
58+
*
59+
* Expected time: nearly constant.
60+
* Expected memory: nearly constant.
61+
*/
62+
@Benchmark
63+
fun addMiddle(): ImmutableList<String> {
64+
return persistentListAdd(size - 1).add(size / 2, "another element")
65+
}
3866
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2016-2019 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package benchmarks.immutableList
18+
19+
import benchmarks.*
20+
import kotlinx.collections.immutable.ImmutableList
21+
import kotlinx.collections.immutable.persistentListOf
22+
import org.openjdk.jmh.annotations.*
23+
24+
@State(Scope.Thread)
25+
open class AddAll {
26+
@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
27+
var size: Int = 0
28+
29+
private var listToAdd = emptyList<String>()
30+
31+
@Setup
32+
fun prepare() {
33+
listToAdd = List(size) { "another element" }
34+
}
35+
36+
// Results of the following benchmarks do not indicate memory or time spent per operation,
37+
// however regressions there do indicate changes.
38+
//
39+
// the benchmarks measure mean time and memory spent per added element.
40+
//
41+
// Expected time: nearly constant.
42+
// Expected memory: nearly constant.
43+
44+
/**
45+
* Adds [size] elements to an empty persistent list using `addAll` operation.
46+
*/
47+
@Benchmark
48+
fun addAllLast(): ImmutableList<String> {
49+
return persistentListOf<String>().addAll(listToAdd)
50+
}
51+
52+
/**
53+
* Adds `size / 2` elements to an empty persistent list
54+
* and then adds `size - size / 2` elements using `addAll` operation.
55+
*/
56+
@Benchmark
57+
fun addAllLast_Half(): ImmutableList<String> {
58+
val initialSize = size / 2
59+
val subListToAdd = listToAdd.subList(0, size - initialSize) // assuming subList creation is neglectable
60+
return persistentListAdd(initialSize).addAll(subListToAdd)
61+
}
62+
63+
/**
64+
* Adds `size - size / 3` elements to an empty persistent list
65+
* and then adds `size / 3` elements using `addAll` operation.
66+
*/
67+
@Benchmark
68+
fun addAllLast_OneThird(): ImmutableList<String> {
69+
val initialSize = size - size / 3
70+
val subListToAdd = listToAdd.subList(0, size - initialSize)
71+
return persistentListAdd(initialSize).addAll(subListToAdd)
72+
}
73+
74+
/**
75+
* Adds `size / 2` elements to an empty persistent list
76+
* and then inserts `size - size / 2` elements at the beginning using `addAll` operation.
77+
*/
78+
@Benchmark
79+
fun addAllFirst_Half(): ImmutableList<String> {
80+
val initialSize = size / 2
81+
val subListToAdd = listToAdd.subList(0, size - initialSize)
82+
return persistentListAdd(initialSize).addAll(0, subListToAdd)
83+
}
84+
85+
/**
86+
* Adds `size - size / 3` elements to an empty persistent list
87+
* and then inserts `size / 3` elements at the beginning using `addAll` operation.
88+
*/
89+
@Benchmark
90+
fun addAllFirst_OneThird(): ImmutableList<String> {
91+
val initialSize = size - size / 3
92+
val subListToAdd = listToAdd.subList(0, size - initialSize)
93+
return persistentListAdd(initialSize).addAll(0, subListToAdd)
94+
}
95+
96+
/**
97+
* Adds `size / 2` elements to an empty persistent list
98+
* and then inserts `size - size / 2` elements at the middle using `addAll` operation.
99+
*/
100+
@Benchmark
101+
fun addAllMiddle_Half(): ImmutableList<String> {
102+
val initialSize = size / 2
103+
val index = initialSize / 2
104+
val subListToAdd = listToAdd.subList(0, size - initialSize)
105+
return persistentListAdd(initialSize).addAll(index, subListToAdd)
106+
}
107+
108+
/**
109+
* Adds `size - size / 3` elements to an empty persistent list builder
110+
* and then inserts `size / 3` elements at the middle using `addAll` operation.
111+
*/
112+
@Benchmark
113+
fun addAllMiddle_OneThird(): ImmutableList<String> {
114+
val initialSize = size - size / 3
115+
val index = initialSize / 2
116+
val subListToAdd = listToAdd.subList(0, size - initialSize)
117+
return persistentListAdd(initialSize).addAll(index, subListToAdd)
118+
}
119+
}

benchmarks-mpp/src/jvmMain/kotlin/benchmarks/immutableList/Remove.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,32 @@ open class Remove {
3131
}
3232
return list
3333
}
34+
35+
/**
36+
* Removes one element from the beginning.
37+
*
38+
* Measures (time and memory spent on `removeAt` operation) / size.
39+
*
40+
* Expected time: nearly constant.
41+
* Expected memory: nearly constant.
42+
*/
43+
@Benchmark
44+
fun removeFirst(): ImmutableList<String> {
45+
val list = persistentList
46+
return list.removeAt(0)
47+
}
48+
49+
/**
50+
* Removes one element from the middle.
51+
*
52+
* Measures (time and memory spent on `removeAt` operation) / size.
53+
*
54+
* Expected time: nearly constant.
55+
* Expected memory: nearly constant.
56+
*/
57+
@Benchmark
58+
fun removeMiddle(): ImmutableList<String> {
59+
val list = persistentList
60+
return list.removeAt(size / 2)
61+
}
3462
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2016-2019 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package benchmarks.immutableList
18+
19+
import benchmarks.*
20+
import kotlinx.collections.immutable.PersistentList
21+
import kotlinx.collections.immutable.persistentListOf
22+
import org.openjdk.jmh.annotations.*
23+
24+
@State(Scope.Thread)
25+
open class RemoveAll {
26+
@Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000)
27+
var size: Int = 0
28+
29+
private var persistentList: PersistentList<Int> = persistentListOf()
30+
31+
@Setup(Level.Trial)
32+
fun prepare() {
33+
persistentList = persistentListOf<Int>().addAll(List(size) { it })
34+
}
35+
36+
// Results of the following benchmarks do not indicate memory or time spent per operation,
37+
// however regressions there do indicate changes.
38+
//
39+
// The benchmarks measure (time and memory spent on `removeAll` operation) / size
40+
//
41+
// Expected time: nearly constant
42+
// Expected memory: nearly constant
43+
44+
/**
45+
* Removes all elements using `removeAll(elements)` operation.
46+
*/
47+
@Benchmark
48+
fun removeAll_All(): PersistentList<Int> {
49+
val list = persistentList
50+
val elementsToRemove = List(size) { it }
51+
return list.removeAll(elementsToRemove)
52+
}
53+
54+
/**
55+
* Removes half of the elements using `removeAll(elements)` operation.
56+
*/
57+
@Benchmark
58+
fun removeAll_RandomHalf(): PersistentList<Int> {
59+
val list = persistentList
60+
val elementsToRemove = randomIndexes(size / 2)
61+
return list.removeAll(elementsToRemove)
62+
}
63+
64+
/**
65+
* Removes 10 random elements using `removeAll(elements)` operation.
66+
*/
67+
@Benchmark
68+
fun removeAll_RandomTen(): PersistentList<Int> {
69+
val list = persistentList
70+
val elementsToRemove = randomIndexes(10)
71+
return list.removeAll(elementsToRemove)
72+
}
73+
74+
/**
75+
* Removes last [tailSize] elements using `removeAll(elements)` operation.
76+
*/
77+
@Benchmark
78+
fun removeAll_Tail(): PersistentList<Int> {
79+
val list = persistentList
80+
val elementsToRemove = List(tailSize()) { size - 1 - it }
81+
return list.removeAll(elementsToRemove)
82+
}
83+
84+
/**
85+
* Removes 10 non-existing elements using `removeAll(elements)` operation.
86+
*/
87+
@Benchmark
88+
fun removeAll_NonExisting(): PersistentList<Int> {
89+
val list = persistentList
90+
val elementsToRemove = randomIndexes(10).map { size + it }
91+
return list.removeAll(elementsToRemove)
92+
}
93+
94+
private fun randomIndexes(count: Int): List<Int> {
95+
val random = java.util.Random()
96+
return List(count) { random.nextInt(size) }
97+
}
98+
99+
private fun tailSize(): Int {
100+
val bufferSize = 32
101+
return (size and (bufferSize - 1)).let { if (it == 0) bufferSize else it }
102+
}
103+
}

benchmarks-mpp/src/jvmMain/kotlin/benchmarks/immutableList/builder/Add.kt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,36 @@ open class Add {
3838
bh.consume(builder[i])
3939
}
4040
}
41+
42+
/**
43+
* Adds [size] - 1 elements to an empty persistent list builder
44+
* and then inserts one element at the beginning.
45+
*
46+
* Measures mean time and memory spent per `add` operation.
47+
*
48+
* Expected time: nearly constant.
49+
* Expected memory: nearly constant.
50+
*/
51+
@Benchmark
52+
fun addFirst(): PersistentList.Builder<String> {
53+
val builder = persistentListBuilderAdd(size - 1, immutablePercentage)
54+
builder.add(0, "another element")
55+
return builder
56+
}
57+
58+
/**
59+
* Adds [size] - 1 elements to an empty persistent list builder
60+
* and then inserts one element at the middle.
61+
*
62+
* Measures mean time and memory spent per `add` operation.
63+
*
64+
* Expected time: nearly constant.
65+
* Expected memory: nearly constant.
66+
*/
67+
@Benchmark
68+
fun addMiddle(): PersistentList.Builder<String> {
69+
val builder = persistentListBuilderAdd(size - 1, immutablePercentage)
70+
builder.add(size / 2, "another element")
71+
return builder
72+
}
4173
}

0 commit comments

Comments
 (0)