[K/N] Benches for parallel mark: life + splay with mark helpers
Merge-request: KOTLIN-MR-669 Merged-by: Aleksej Glushko <aleksei.glushko@jetbrains.com>
This commit is contained in:
committed by
Space Cloud
parent
8173091fee
commit
cfa481d38f
@@ -62,6 +62,7 @@ class RingLauncher : Launcher() {
|
|||||||
"Singleton.access" to BenchmarkEntryWithInit.create(::SingletonBenchmark, { access() }),
|
"Singleton.access" to BenchmarkEntryWithInit.create(::SingletonBenchmark, { access() }),
|
||||||
"Splay" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmark, { runSplay() }, { splayTearDown() }),
|
"Splay" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmark, { runSplay() }, { splayTearDown() }),
|
||||||
"SplayWithWorkers" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmarkUsingWorkers, { runSplayWorkers() }, { splayTearDownWorkers() }),
|
"SplayWithWorkers" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmarkUsingWorkers, { runSplayWorkers() }, { splayTearDownWorkers() }),
|
||||||
|
"SplayWithMarkHelpers" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmarkWithMarkHelpers, { runSplayWithMarkHelpers() }, { splayTearDownMarkHelpers() }),
|
||||||
"String.stringConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcat() }),
|
"String.stringConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcat() }),
|
||||||
"String.stringBuilderConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcat() }),
|
"String.stringBuilderConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcat() }),
|
||||||
"String.stringBuilderConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcatNullable() }),
|
"String.stringBuilderConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcatNullable() }),
|
||||||
@@ -206,6 +207,8 @@ class RingLauncher : Launcher() {
|
|||||||
"Lambda.mutatingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambda() }),
|
"Lambda.mutatingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambda() }),
|
||||||
"Lambda.mutatingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambdaNoInline() }),
|
"Lambda.mutatingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambdaNoInline() }),
|
||||||
"Lambda.methodReferenceNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { methodReferenceNoInline() }),
|
"Lambda.methodReferenceNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { methodReferenceNoInline() }),
|
||||||
|
"Life" to BenchmarkEntryWithInit.create(::LifeBenchmark, { bench() }),
|
||||||
|
"LifeWithMarkHelpers" to BenchmarkEntryWithInitAndValidation.create(::LifeWithMarkHelpersBenchmark, { bench() }, { terminate() }),
|
||||||
"Loop.arrayIndexLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayIndexLoop() }),
|
"Loop.arrayIndexLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayIndexLoop() }),
|
||||||
"Loop.arrayListLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListLoop() }),
|
"Loop.arrayListLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListLoop() }),
|
||||||
"ParameterNotNull.invokeOneArgWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithNullCheck() }),
|
"ParameterNotNull.invokeOneArgWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithNullCheck() }),
|
||||||
@@ -242,6 +245,8 @@ class RingLauncher : Launcher() {
|
|||||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||||
if (!isExperimentalMM()) {
|
if (!isExperimentalMM()) {
|
||||||
baseBenchmarksSet -= listOf("SplayWithWorkers")
|
baseBenchmarksSet -= listOf("SplayWithWorkers")
|
||||||
|
baseBenchmarksSet -= listOf("SplayWithMarkHelpers")
|
||||||
|
extendedBenchmarksSet -= listOf("LifeWithMarkHelpers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package org.jetbrains.ring
|
||||||
|
|
||||||
|
import kotlin.native.concurrent.*
|
||||||
|
import kotlin.concurrent.*
|
||||||
|
import org.jetbrains.benchmarksLauncher.Blackhole
|
||||||
|
import org.jetbrains.benchmarksLauncher.Random
|
||||||
|
|
||||||
|
data class Pos(val i: Int, val j: Int)
|
||||||
|
|
||||||
|
data class Cell(val isAlive: Boolean = false)
|
||||||
|
|
||||||
|
class Generation(private val width: Int, private val height: Int) {
|
||||||
|
val cells = Array(height) { _ -> Array(width) { _ -> Cell() } }
|
||||||
|
|
||||||
|
fun evolve(): Generation {
|
||||||
|
val newGen = Generation(width, height)
|
||||||
|
|
||||||
|
for (i in 0 until height) {
|
||||||
|
for (j in 0 until width) {
|
||||||
|
val neighborhood = mutableListOf<Pos>()
|
||||||
|
for (di in -1..1) {
|
||||||
|
for (dj in -1..1) {
|
||||||
|
if (di != 0 || dj != 0) {
|
||||||
|
neighborhood.add(Pos(i + di, j + dj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(neighborhood.size == 8)
|
||||||
|
val aliveNeighbours = neighborhood
|
||||||
|
.map { wrapOverEdge(it) }
|
||||||
|
.map { cells[it.i][it.j] }
|
||||||
|
.count { it.isAlive }
|
||||||
|
|
||||||
|
val newAlive =
|
||||||
|
if (cells[i][j].isAlive) aliveNeighbours in 2..3
|
||||||
|
else aliveNeighbours == 3
|
||||||
|
|
||||||
|
newGen.cells[i][j] = Cell(newAlive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newGen
|
||||||
|
}
|
||||||
|
|
||||||
|
// good luck in scalar replacement?
|
||||||
|
private fun wrapOverEdge(orig: Pos) =
|
||||||
|
if (orig.i in 0 until height && orig.j in 0 until width) orig
|
||||||
|
else Pos((orig.i + height) % height, (orig.j + width) % width)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean = when {
|
||||||
|
other is Generation -> {
|
||||||
|
other.cells.size == cells.size &&
|
||||||
|
cells.zip(other.cells).all { (a, b) -> a contentEquals b }
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun random(width: Int, height: Int): Generation {
|
||||||
|
val gen = Generation(width, height)
|
||||||
|
|
||||||
|
for (i in 0 until height) {
|
||||||
|
for (j in 0 until width) {
|
||||||
|
gen.cells[i][j] = Cell(Random.nextInt() % 2 == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Universe(val width: Int, val height: Int) {
|
||||||
|
var gen = Generation.random(width, height)
|
||||||
|
|
||||||
|
fun evolve() {
|
||||||
|
gen = gen.evolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun run(space: Int, time: Int) {
|
||||||
|
val width = space
|
||||||
|
val height = space
|
||||||
|
val universe = Universe(width, height)
|
||||||
|
for (i in 0 until time) {
|
||||||
|
universe.evolve()
|
||||||
|
}
|
||||||
|
Blackhole.consume(universe)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class LifeBenchmark {
|
||||||
|
val spaceScale = BENCHMARK_SIZE / 40
|
||||||
|
val timeScale = 5
|
||||||
|
|
||||||
|
fun bench() {
|
||||||
|
run(spaceScale, timeScale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LifeWithMarkHelpersBenchmark : LifeBenchmark() {
|
||||||
|
val numberOfMarkHelpers = 5;
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
var done = false
|
||||||
|
val markHelpers = Array(numberOfMarkHelpers, { _ -> Worker.start() })
|
||||||
|
val markHelperJobs = markHelpers.map {
|
||||||
|
it.execute(TransferMode.SAFE, { this }) {
|
||||||
|
// run some thread-local work in a loop without allocations or external calls
|
||||||
|
fun fib(n: Int): Int {
|
||||||
|
if (n == 0) return 0
|
||||||
|
var prev = 0
|
||||||
|
var cur = 1
|
||||||
|
for (i in 2..n) {
|
||||||
|
val next = cur + prev
|
||||||
|
prev = cur
|
||||||
|
cur = next
|
||||||
|
}
|
||||||
|
return cur
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum = 0
|
||||||
|
while (!it.done) {
|
||||||
|
sum += fib(100)
|
||||||
|
}
|
||||||
|
return@execute sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun terminate() {
|
||||||
|
done = true
|
||||||
|
markHelperJobs.forEach { it.result }
|
||||||
|
markHelpers.forEach { it.requestTermination().result }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
// graph.
|
// graph.
|
||||||
|
|
||||||
import kotlin.native.concurrent.*
|
import kotlin.native.concurrent.*
|
||||||
|
import kotlin.concurrent.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
// A splay tree is a self-balancing binary search tree with the additional
|
// A splay tree is a self-balancing binary search tree with the additional
|
||||||
@@ -319,3 +320,46 @@ class SplayBenchmarkUsingWorkers {
|
|||||||
workers.forEach { it.requestTermination().result }
|
workers.forEach { it.requestTermination().result }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SplayBenchmarkWithMarkHelpers {
|
||||||
|
val numberOfMarkHelpers = 5;
|
||||||
|
val markHelpers = Array(numberOfMarkHelpers, { _ -> Worker.start() })
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
var done = false
|
||||||
|
val markHelperJobs = markHelpers.map {
|
||||||
|
it.execute(TransferMode.SAFE, { this }) {
|
||||||
|
// run some thread-local work in a loop without allocations or external calls
|
||||||
|
fun fib(n: Int): Int {
|
||||||
|
if (n == 0) return 0
|
||||||
|
var prev = 0
|
||||||
|
var cur = 1
|
||||||
|
for (i in 2..n) {
|
||||||
|
val next = cur + prev
|
||||||
|
prev = cur
|
||||||
|
cur = next
|
||||||
|
}
|
||||||
|
return cur
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum = 0
|
||||||
|
while (!it.done) {
|
||||||
|
sum += fib(100)
|
||||||
|
}
|
||||||
|
return@execute sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val splay = SplayBenchmark()
|
||||||
|
|
||||||
|
fun runSplayWithMarkHelpers() {
|
||||||
|
splay.runSplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun splayTearDownMarkHelpers() {
|
||||||
|
done = true
|
||||||
|
splay.splayTearDown()
|
||||||
|
markHelperJobs.forEach { it.result }
|
||||||
|
markHelpers.forEach { it.requestTermination().result }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user