From 3e2872ea5e9daed234de5e4de0a0a0bac41c3b0b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 4 Feb 2024 13:42:13 +0700 Subject: [PATCH] Execution spinner for unified and improved spinning --- .../kstarbound/util/ExecutionSpinner.kt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt new file mode 100644 index 00000000..6550a84a --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt @@ -0,0 +1,74 @@ +package ru.dbotthepony.kstarbound.util + +import ru.dbotthepony.kommons.util.MailboxExecutorService +import ru.dbotthepony.kstarbound.Starbound +import java.util.concurrent.locks.LockSupport +import java.util.function.BooleanSupplier + +class ExecutionSpinner(private val executor: MailboxExecutorService, private val spinner: BooleanSupplier, private val timeBetweenFrames: Long) : Runnable { + private var lastRender = System.nanoTime() + private var frameRenderTime = 0L + private val frameRenderTimes = LongArray(60) { 1L } + private var frameRenderIndex = 0 + private val renderWaitTimes = LongArray(60) { 1L } + private var renderWaitIndex = 0 + + val averageRenderWait: Double get() { + var sum = 0.0 + + for (value in renderWaitTimes) + sum += value + + if (sum == 0.0) + return 0.0 + + sum /= 1_000_000_000.0 + return sum / renderWaitTimes.size + } + + val averageRenderTime: Double get() { + var sum = 0.0 + + for (value in frameRenderTimes) + sum += value + + if (sum == 0.0) + return 0.0 + + sum /= 1_000_000_000.0 + return sum / frameRenderTimes.size + } + + private fun timeUntilNextFrame(): Long { + return Starbound.TICK_TIME_ADVANCE_NANOS - (System.nanoTime() - lastRender) - frameRenderTime + } + + fun spin(): Boolean { + var diff = timeUntilNextFrame() + + while (diff > 1_000_000L) { + executor.executeQueuedTasks() + diff = timeUntilNextFrame() + if (diff > 1_000_000L) LockSupport.parkNanos(diff - 400_000L) + } + + while (diff > 0L) { + executor.executeQueuedTasks() + diff = timeUntilNextFrame() + if (diff > 0L) Thread.yield() + } + + val mark = System.nanoTime() + val result = spinner.asBoolean + frameRenderTime = System.nanoTime() - mark + frameRenderTimes[++frameRenderIndex % frameRenderTimes.size] = frameRenderTime + renderWaitTimes[++renderWaitIndex % renderWaitTimes.size] = System.nanoTime() - lastRender + lastRender = System.nanoTime() + + return result + } + + override fun run() { + while (spin()) {} + } +}