improve thread pool (performance), improve culling performance

This commit is contained in:
Bixilon 2021-11-15 17:45:26 +01:00
parent ec7ef10add
commit 7344fdda6c
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
6 changed files with 42 additions and 72 deletions

View File

@ -36,7 +36,7 @@ class ChunkSection(
var light: IntArray, // packed (skyLight: 0xF0, blockLight: 0x0F) var light: IntArray, // packed (skyLight: 0xF0, blockLight: 0x0F)
) { ) {
constructor(registries: Registries) : this(RegistrySectionDataProvider<BlockState?>(registries.blockStateRegistry.unsafeCast(), checkSize = true), RegistrySectionDataProvider(registries.biomeRegistry, checkSize = false), SectionDataProvider(checkSize = true), IntArray(ProtocolDefinition.BLOCKS_PER_SECTION)) constructor(registries: Registries) : this(RegistrySectionDataProvider<BlockState?>(registries.blockStateRegistry.unsafeCast(), checkSize = true), RegistrySectionDataProvider(registries.biomeRegistry, checkSize = false), SectionDataProvider(checkSize = false), IntArray(ProtocolDefinition.BLOCKS_PER_SECTION))
fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) { fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) {
if (blockEntities.isEmpty) { if (blockEntities.isEmpty) {

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class RegistrySectionDataProvider<T>( class RegistrySectionDataProvider<T>(
val registry: AbstractRegistry<T>, val registry: AbstractRegistry<T>,
data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), data: Array<Any?>? = null,
checkSize: Boolean = false, checkSize: Boolean = false,
) : SectionDataProvider<T>(data, checkSize = checkSize) { ) : SectionDataProvider<T>(data, checkSize = checkSize) {

View File

@ -13,15 +13,16 @@
package de.bixilon.minosoft.data.world.container package de.bixilon.minosoft.data.world.container
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.SemaphoreLock import de.bixilon.minosoft.util.SemaphoreLock
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
open class SectionDataProvider<T>( open class SectionDataProvider<T>(
data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), data: Array<Any?>? = null,
val checkSize: Boolean = false, val checkSize: Boolean = false,
) : Iterable<T> { ) : Iterable<T> {
protected var data = data protected var data = data ?: arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
private set private set
protected val lock = SemaphoreLock() // lock while reading (blocks writing) protected val lock = SemaphoreLock() // lock while reading (blocks writing)
var count: Int = 0 var count: Int = 0
@ -34,7 +35,12 @@ open class SectionDataProvider<T>(
private set private set
init { init {
recalculate() if (data != null) {
recalculate()
} else {
minPosition = Vec3i.EMPTY
maxPosition = Vec3i.EMPTY
}
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -55,9 +61,9 @@ open class SectionDataProvider<T>(
return data[y shl 8 or (z shl 4) or x] as T return data[y shl 8 or (z shl 4) or x] as T
} }
private fun recalculate() { private fun recalculate() {
var count = 0 var count = 0
var value: Any?
var minX = 16 var minX = 16
var minY = 16 var minY = 16

View File

@ -5,12 +5,16 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparenci
object CullUtil { object CullUtil {
fun Array<FaceProperties>.canCull(properties: FaceProperties, sameBlock: Boolean): Boolean { fun Array<FaceProperties>.canCull(properties: FaceProperties, sameBlock: Boolean): Boolean {
val sizeStartX = properties.sizeStart.x
val sizeStartY = properties.sizeStart.y
val sizeEndX = properties.sizeEnd.x
val sizeEndY = properties.sizeEnd.y
for (property in this) { for (property in this) {
if ( if (
property.sizeStart.x <= properties.sizeStart.x property.sizeStart.x <= sizeStartX
&& property.sizeStart.y <= properties.sizeStart.y && property.sizeStart.y <= sizeStartY
&& property.sizeEnd.x >= properties.sizeEnd.x && property.sizeEnd.x >= sizeEndX
&& property.sizeEnd.y >= properties.sizeEnd.y && property.sizeEnd.y >= sizeEndY
&& !((properties.transparency == TextureTransparencies.OPAQUE && property.transparency != TextureTransparencies.OPAQUE) && !((properties.transparency == TextureTransparencies.OPAQUE && property.transparency != TextureTransparencies.OPAQUE)
|| (properties.transparency != TextureTransparencies.OPAQUE && property.transparency == properties.transparency && !sameBlock) || (properties.transparency != TextureTransparencies.OPAQUE && property.transparency == properties.transparency && !sameBlock)
|| (properties.transparency == TextureTransparencies.TRANSPARENT && property.transparency == TextureTransparencies.TRANSLUCENT)) || (properties.transparency == TextureTransparencies.TRANSPARENT && property.transparency == TextureTransparencies.TRANSLUCENT))

View File

@ -13,22 +13,17 @@
package de.bixilon.minosoft.util.task.pool package de.bixilon.minosoft.util.task.pool
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf import de.bixilon.minosoft.util.KUtil.synchronizedListOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedList import de.bixilon.minosoft.util.KUtil.toSynchronizedList
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet import java.util.concurrent.*
import java.util.concurrent.Callable
import java.util.concurrent.ExecutorService
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
open class ThreadPool( open class ThreadPool(
val threadCount: Int = Runtime.getRuntime().availableProcessors(), val threadCount: Int = Runtime.getRuntime().availableProcessors(),
private val name: String = "Worker#%d", private val name: String = "Worker#%d",
) : ExecutorService { ) : ExecutorService {
private var state = ThreadPoolStates.STARTING private var state = ThreadPoolStates.STARTING
private val threads: MutableSet<Thread> = synchronizedSetOf() private var threads: MutableList<Thread> = synchronizedListOf()
private val availableThreads: MutableSet<Thread> = synchronizedSetOf() private var queue: PriorityBlockingQueue<ThreadPoolRunnable> = PriorityBlockingQueue()
private var pending: MutableSet<ThreadPoolRunnable> = sortedSetOf<ThreadPoolRunnable>({ a, b -> a.priority - b.priority }).toSynchronizedSet()
private var nextThreadId = 0 private var nextThreadId = 0
init { init {
@ -37,43 +32,24 @@ open class ThreadPool(
state = ThreadPoolStates.STARTED state = ThreadPoolStates.STARTED
} }
val pendingCount: Int val queueSize: Int
get() = pending.size get() = queue.size
@Synchronized @Synchronized
private fun checkThreads() { private fun checkThreads() {
fun wait() {
try {
availableThreads += Thread.currentThread()
Thread.sleep(Long.MAX_VALUE)
} catch (exception: InterruptedException) {
// Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Thread (${Thread.currentThread()} sleeping got interrupted" }
}
availableThreads -= Thread.currentThread()
}
for (i in 0 until threadCount - threads.size) { for (i in 0 until threadCount - threads.size) {
var runnable: ThreadPoolRunnable
val thread = Thread { val thread = Thread {
while (true) { while (true) {
if (state == ThreadPoolStates.STOPPING) { if (state == ThreadPoolStates.STOPPING) {
break break
} }
if (pending.isEmpty()) { try {
wait() runnable = queue.take()
} catch (exception: InterruptedException) {
break
} }
val runnable: ThreadPoolRunnable?
synchronized(pending) {
if (pending.isNotEmpty()) {
runnable = pending.iterator().next()
pending.remove(runnable)
} else {
runnable = null
}
}
if (runnable == null) {
continue
}
try { try {
runnable.thread = Thread.currentThread() runnable.thread = Thread.currentThread()
runnable.runnable.run() runnable.runnable.run()
@ -83,9 +59,7 @@ open class ThreadPool(
if (exception is InterruptedException) { if (exception is InterruptedException) {
// Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Thread ${Thread.currentThread()} was interrupted" } // Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Thread ${Thread.currentThread()} was interrupted" }
runnable.wasInterrupted = true runnable.wasInterrupted = true
if (!runnable.interuptable) { queue += runnable
pending += runnable
}
if (state == ThreadPoolStates.STOPPING) { if (state == ThreadPoolStates.STOPPING) {
break break
@ -94,30 +68,18 @@ open class ThreadPool(
exception.printStackTrace() exception.printStackTrace()
} }
} }
if (pending.isNotEmpty()) {
continue
}
wait()
} }
threads -= Thread.currentThread() threads -= Thread.currentThread()
} }
thread.name = name.format(nextThreadId++) thread.name = name.format(nextThreadId++)
threads += thread
thread.start() thread.start()
threads += thread
} }
} }
@Synchronized
fun execute(runnable: ThreadPoolRunnable) { fun execute(runnable: ThreadPoolRunnable) {
pending += runnable queue += runnable
synchronized(availableThreads) {
if (availableThreads.isNotEmpty()) {
val thread = availableThreads.iterator().next()
availableThreads.remove(thread)
thread.interrupt()
// Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Interrupting thread $thread" }
}
}
} }
override fun execute(runnable: Runnable) { override fun execute(runnable: Runnable) {
@ -138,9 +100,7 @@ open class ThreadPool(
state = ThreadPoolStates.STOPPING state = ThreadPoolStates.STOPPING
synchronized(threads) { synchronized(threads) {
for (thread in threads.toSynchronizedList()) { for (thread in threads.toSynchronizedList()) {
if (thread.state == Thread.State.TIMED_WAITING) { thread.interrupt()
thread.interrupt()
}
} }
} }
while (threads.isNotEmpty()) { while (threads.isNotEmpty()) {
@ -156,12 +116,8 @@ open class ThreadPool(
thread.interrupt() thread.interrupt()
} }
} }
while (threads.isNotEmpty()) {
Thread.sleep(1L)
}
state = ThreadPoolStates.STOPPED state = ThreadPoolStates.STOPPED
return mutableListOf()
return mutableListOf() // ToDo
} }
override fun isShutdown(): Boolean { override fun isShutdown(): Boolean {

View File

@ -17,7 +17,7 @@ class ThreadPoolRunnable(
val priority: Int = ThreadPool.NORMAL, val priority: Int = ThreadPool.NORMAL,
var interuptable: Boolean = false, var interuptable: Boolean = false,
val runnable: Runnable, val runnable: Runnable,
) { ) : Comparable<ThreadPoolRunnable> {
var wasInterrupted = false var wasInterrupted = false
var thread: Thread? = null var thread: Thread? = null
@ -27,4 +27,8 @@ class ThreadPoolRunnable(
// Log.log(LogMessageType.OTHER, LogLevels.VERBOSE){"Interrupting runnable in thread $thread"} // Log.log(LogMessageType.OTHER, LogLevels.VERBOSE){"Interrupting runnable in thread $thread"}
} }
} }
override fun compareTo(other: ThreadPoolRunnable): Int {
return priority - other.priority
}
} }