Use common ForkJoinPool for light calculations

This commit is contained in:
DBotThePony 2023-10-03 14:34:20 +07:00
parent 425494e104
commit f874b880ef
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 20 additions and 73 deletions

View File

@ -75,7 +75,7 @@ fun main() {
for (chunkX in 0 .. 100) { for (chunkX in 0 .. 100) {
//for (chunkX in 0 .. 17) { //for (chunkX in 0 .. 17) {
// for (chunkY in 21 .. 21) { // for (chunkY in 21 .. 21) {
for (chunkY in 0 .. 24) { for (chunkY in 18 .. 24) {
val data = db.read(byteArrayOf(1, 0, chunkX.toByte(), 0, chunkY.toByte())) val data = db.read(byteArrayOf(1, 0, chunkX.toByte(), 0, chunkY.toByte()))
val data2 = db.read(byteArrayOf(2, 0, chunkX.toByte(), 0, chunkY.toByte())) val data2 = db.read(byteArrayOf(2, 0, chunkX.toByte(), 0, chunkY.toByte()))

View File

@ -88,7 +88,7 @@ class StarboundClient : Closeable {
val thread: Thread = Thread.currentThread() val thread: Thread = Thread.currentThread()
// client specific executor which will accept tasks which involve probable // client specific executor which will accept tasks which involve probable
// callback to foreground executor to initialize thread-unsafe data // callback to foreground executor to initialize thread-unsafe data
// In above case multiple threads will introduce big congestion for resources // In above case too many threads will introduce big congestion for resources, stalling entire workload; wasting cpu resources
val backgroundExecutor = ForkJoinPool(Runtime.getRuntime().availableProcessors().coerceAtMost(4)) val backgroundExecutor = ForkJoinPool(Runtime.getRuntime().availableProcessors().coerceAtMost(4))
val foregroundExecutor = ManualExecutorService(thread) val foregroundExecutor = ManualExecutorService(thread)
val capabilities: GLCapabilities val capabilities: GLCapabilities

View File

@ -8,8 +8,13 @@ import ru.dbotthepony.kvector.arrays.Object2DArray
import ru.dbotthepony.kvector.util.linearInterpolation import ru.dbotthepony.kvector.util.linearInterpolation
import ru.dbotthepony.kvector.vector.RGBAColor import ru.dbotthepony.kvector.vector.RGBAColor
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.util.concurrent.Callable
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.Future
import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.LockSupport
import java.util.function.Supplier
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.random.Random import kotlin.random.Random
@ -380,10 +385,9 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
// perform multithreaded calculation only when it makes sense // perform multithreaded calculation only when it makes sense
if (multithreaded && pointLights.size > 1) { if (multithreaded && pointLights.size > 1) {
val thread = Thread.currentThread() val thread = Thread.currentThread()
// calculate k-means clusters of point lights // calculate k-means clusters of point lights
// to effectively utilize CPU cores // to effectively utilize CPU cores
val clusterCount = threads.size.coerceAtMost(pointLights.size) val clusterCount = ForkJoinPool.commonPool().parallelism.coerceAtMost(pointLights.size)
val clusters = ArrayList<TaskCluster>(clusterCount) val clusters = ArrayList<TaskCluster>(clusterCount)
val startingPoints = IntArraySet() val startingPoints = IntArraySet()
// val rand = Random(System.nanoTime()) // val rand = Random(System.nanoTime())
@ -394,7 +398,7 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
} }
for (index in startingPoints.intIterator()) { for (index in startingPoints.intIterator()) {
clusters.add(TaskCluster(pointLights[index].x.toDouble(), pointLights[index].y.toDouble(), this, thread)) clusters.add(TaskCluster(pointLights[index].x.toDouble(), pointLights[index].y.toDouble(), this))
} }
var converged = false var converged = false
@ -459,25 +463,14 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
} }
} }
/*for ((i, cluster) in clusters.withIndex()) { val tasks = ArrayList<Future<Grid>>()
val (r, g, b) = clusterColors[i] clusters.forEach { tasks.add(CompletableFuture.supplyAsync(it, ForkJoinPool.commonPool()).also { it.thenApply { LockSupport.unpark(thread); it } }) }
for (light in cluster.lights) { while (tasks.isNotEmpty()) {
light.red = r tasks.removeIf {
light.green = g if (it.isDone) {
light.blue = b val grid = it.get()
}
}*/
tasks.addAll(clusters)
wakeup()
while (clusters.isNotEmpty()) {
clusters.removeIf {
val grid = it.grid
// wait until thread local caches are refreshed
if (grid != null) {
if (targetMem != null) { if (targetMem != null) {
for (x in grid.minX - 1 .. grid.maxX) { for (x in grid.minX - 1 .. grid.maxX) {
for (y in grid.minY - 1 .. grid.maxY) { for (y in grid.minY - 1 .. grid.maxY) {
@ -522,10 +515,10 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
} }
} }
grid != null it.isDone
} }
LockSupport.parkNanos(500_000) LockSupport.parkNanos(500_000L)
} }
} else { } else {
val grid = Grid() val grid = Grid()
@ -589,8 +582,7 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
var x: Double, var x: Double,
var y: Double, var y: Double,
val parent: LightCalculator, val parent: LightCalculator,
val parentThread: Thread ) : Supplier<Grid> {
) {
val lights = ArrayList<PointLight>() val lights = ArrayList<PointLight>()
fun updateCenter() { fun updateCenter() {
@ -608,13 +600,7 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
y /= lights.size y /= lights.size
} }
@Volatile override fun get(): Grid {
var grid: Grid? = null
private set
fun execute() {
if (grid != null) return
val grid = parent.Grid() val grid = parent.Grid()
for (light in lights) { for (light in lights) {
@ -635,46 +621,7 @@ class LightCalculator(val parent: ICellAccess, val width: Int, val height: Int)
} }
grid.calculateSpread() grid.calculateSpread()
this.grid = grid return grid
LockSupport.unpark(parentThread)
}
}
companion object {
private val tasks = ConcurrentLinkedQueue<TaskCluster>()
private val threads = ArrayList<Thread>()
private val clusterColors = ArrayList<RGBAColor>()
private fun wakeup() {
for (thread in threads) {
LockSupport.unpark(thread)
}
}
private fun thread() {
while (true) {
val next = tasks.poll()
if (next == null) {
LockSupport.park()
continue
}
next.execute()
}
}
init {
for (i in 0 until Runtime.getRuntime().availableProcessors()) {
Thread(::thread, "Starbound Lighting Thread $i").also { threads.add(it); it.isDaemon = true }.start()
}
val rand = Random(System.nanoTime())
for (i in threads.indices) {
clusterColors.add(RGBAColor(rand.nextFloat() * 0.5f + 0.5f, rand.nextFloat() * 0.5f + 0.5f, rand.nextFloat() * 0.5f + 0.5f))
}
} }
} }
} }