[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() }),
|
||||
"Splay" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmark, { runSplay() }, { splayTearDown() }),
|
||||
"SplayWithWorkers" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmarkUsingWorkers, { runSplayWorkers() }, { splayTearDownWorkers() }),
|
||||
"SplayWithMarkHelpers" to BenchmarkEntryWithInitAndValidation.create(::SplayBenchmarkWithMarkHelpers, { runSplayWithMarkHelpers() }, { splayTearDownMarkHelpers() }),
|
||||
"String.stringConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcat() }),
|
||||
"String.stringBuilderConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcat() }),
|
||||
"String.stringBuilderConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcatNullable() }),
|
||||
@@ -206,6 +207,8 @@ class RingLauncher : Launcher() {
|
||||
"Lambda.mutatingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambda() }),
|
||||
"Lambda.mutatingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambdaNoInline() }),
|
||||
"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.arrayListLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListLoop() }),
|
||||
"ParameterNotNull.invokeOneArgWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithNullCheck() }),
|
||||
@@ -242,6 +245,8 @@ class RingLauncher : Launcher() {
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
if (!isExperimentalMM()) {
|
||||
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.
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.random.Random
|
||||
|
||||
// A splay tree is a self-balancing binary search tree with the additional
|
||||
@@ -319,3 +320,46 @@ class SplayBenchmarkUsingWorkers {
|
||||
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