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)
) {
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) {
if (blockEntities.isEmpty) {

View File

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

View File

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

View File

@ -5,12 +5,16 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparenci
object CullUtil {
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) {
if (
property.sizeStart.x <= properties.sizeStart.x
&& property.sizeStart.y <= properties.sizeStart.y
&& property.sizeEnd.x >= properties.sizeEnd.x
&& property.sizeEnd.y >= properties.sizeEnd.y
property.sizeStart.x <= sizeStartX
&& property.sizeStart.y <= sizeStartY
&& property.sizeEnd.x >= sizeEndX
&& property.sizeEnd.y >= sizeEndY
&& !((properties.transparency == TextureTransparencies.OPAQUE && property.transparency != TextureTransparencies.OPAQUE)
|| (properties.transparency != TextureTransparencies.OPAQUE && property.transparency == properties.transparency && !sameBlock)
|| (properties.transparency == TextureTransparencies.TRANSPARENT && property.transparency == TextureTransparencies.TRANSLUCENT))

View File

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

View File

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