Simplify K/N ArrayList

This commit specializes the existing Kotlin/Native stdlib ArrayList into
two subclasses:
 * ArrayList
 * ArraySubList
This avoids repeatedly checking whether a basic ArrayList is created as a
sublist of another ArrayList.

In the iterators, checkForComodification is marked for inlining, since
this significantly improves iterations performance.

A number of benchmarks are added to the native ring benchmark suite, to
test whether the changed runtime type of ArrayList.subList(...) has an
impact.
This commit is contained in:
Troels Bjerre Lund
2023-08-29 13:54:49 +02:00
committed by Space Cloud
parent 39fda3535a
commit d62dbbb1bd
3 changed files with 510 additions and 115 deletions
@@ -218,6 +218,15 @@ class RingLauncher : Launcher() {
"ParameterNotNull.invokeEightArgsWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeEightArgsWithNullCheck() }),
"ParameterNotNull.invokeEightArgsWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeEightArgsWithoutNullCheck() }),
"String.stringConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcatNullable() }),
"SubList.concatenate" to BenchmarkEntryWithInit.create(::SubListBenchmark, { concatenate() }),
"SubList.concatenateManual" to BenchmarkEntryWithInit.create(::SubListBenchmark, { concatenateManual() }),
"SubList.filterAndCount" to BenchmarkEntryWithInit.create(::SubListBenchmark, { filterAndCount() }),
"SubList.filterAndCountWithLambda" to BenchmarkEntryWithInit.create(::SubListBenchmark, { filterAndCountWithLambda() }),
"SubList.countWithLambda" to BenchmarkEntryWithInit.create(::SubListBenchmark, { countWithLambda() }),
"SubList.filterManual" to BenchmarkEntryWithInit.create(::SubListBenchmark, { filterManual() }),
"SubList.countFilteredManual" to BenchmarkEntryWithInit.create(::SubListBenchmark, { countFilteredManual() }),
"SubList.countFiltered" to BenchmarkEntryWithInit.create(::SubListBenchmark, { countFiltered() }),
"SubList.reduce" to BenchmarkEntryWithInit.create(::SubListBenchmark, { reduce() }),
"Switch.testSparseIntSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testSparseIntSwitch() }),
"Switch.testDenseIntSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testDenseIntSwitch() }),
"Switch.testConstSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testConstSwitch() }),
@@ -0,0 +1,121 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.ring
class SubListBenchmark {
private var _data: List<Value>? = null
fun getData(subList: Boolean): List<Value> {
val data: List<Value> = _data!!
// 1 to ensure that .subList can't return the list itself
if (subList) return data.subList(1, data.size)
else return data
}
init {
val list = ArrayList<Value>(BENCHMARK_SIZE)
for (n in classValues(BENCHMARK_SIZE))
list.add(n)
_data = list
}
//Benchmark
fun concatenate(): List<Value> {
return getData(false) + getData(true)
}
//Benchmark
fun concatenateManual(): List<Value> {
val list = ArrayList<Value>(2 * BENCHMARK_SIZE)
// outer loop to ensure single call site for list and sublist
for (data in listOf(getData(false), getData(true))) {
for (item in data) {
list.add(item)
}
}
return list
}
//Benchmark
fun filterAndCount(): Int {
var count = 0
for (data in listOf(getData(false), getData(true))) {
count += data.filter { filterLoad(it) }.count()
}
return count
}
//Benchmark
fun filterAndCountWithLambda(): Int {
var count = 0
for (data in listOf(getData(false), getData(true))) {
count += data.filter { it.value % 2 == 0 }.count()
}
return count
}
//Benchmark
fun countWithLambda(): Int {
var count = 0
for (data in listOf(getData(false), getData(true))) {
count += data.count { it.value % 2 == 0 }
}
return count
}
//Benchmark
fun filterManual(): List<Value> {
val list = ArrayList<Value>()
for (data in listOf(getData(false), getData(true))) {
for (it in data) {
if (filterLoad(it))
list.add(it)
}
}
return list
}
//Benchmark
fun countFilteredManual(): Int {
var count = 0
for (data in listOf(getData(false), getData(true))) {
for (it in data) {
if (filterLoad(it))
count++
}
}
return count
}
//Benchmark
fun countFiltered(): Int {
var count = 0
for (data in listOf(getData(false), getData(true))) {
count += data.count { filterLoad(it) }
}
return count
}
//Benchmark
fun reduce(): Int {
var res = 0
for (data in listOf(getData(false), getData(true))) {
res = data.fold(res) { acc, it -> if (filterLoad(it)) acc + 1 else acc }
}
return res
}
}