diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/WindowsBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/WindowsBindings.kt new file mode 100644 index 00000000..020b12d0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/WindowsBindings.kt @@ -0,0 +1,23 @@ +package ru.dbotthepony.kstarbound + +import jnr.ffi.LibraryLoader +import org.apache.logging.log4j.LogManager +import java.nio.LongBuffer + +interface WindowsBindings { + fun NtQueryTimerResolution(minimumResolution: LongBuffer, maximumResolution: LongBuffer, currentResolution: LongBuffer) + fun NtSetTimerResolution(desiredResolution: Long, setResolution: Boolean, currentResolution: LongBuffer) + + companion object { + private val LOGGER = LogManager.getLogger() + + val INSTANCE by lazy { + try { + LibraryLoader.create(WindowsBindings::class.java).load("ntdll") + } catch (err: Throwable) { + LOGGER.error("Failed to link against ntdll.dll, if we are not on Windows then ignore this message", err) + null + } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt index 0aa1d01e..7c9f7e45 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/ExecutionSpinner.kt @@ -1,8 +1,10 @@ package ru.dbotthepony.kstarbound.util import org.apache.logging.log4j.LogManager +import org.lwjgl.system.MemoryStack import ru.dbotthepony.kommons.util.MailboxExecutorService import ru.dbotthepony.kstarbound.Starbound +import ru.dbotthepony.kstarbound.WindowsBindings import java.util.concurrent.locks.LockSupport import java.util.function.BooleanSupplier @@ -54,7 +56,7 @@ class ExecutionSpinner(private val executor: MailboxExecutorService, private val while (diff > 0L) { executor.executeQueuedTasks() diff = timeUntilNextFrame() - if (diff > 400_000L) LockSupport.parkNanos(100_000L) + if (diff > SYSTEM_SCHEDULER_RESOLUTION) LockSupport.parkNanos(500_000L) } val mark = System.nanoTime() @@ -73,9 +75,33 @@ class ExecutionSpinner(private val executor: MailboxExecutorService, private val companion object { private val LOGGER = LogManager.getLogger() + private var SYSTEM_SCHEDULER_RESOLUTION = 1_000_000L init { - val thread = object : Thread("Fix God Damn Windows Process Scheduler For Once Please") { + val bindings = WindowsBindings.INSTANCE + + if (bindings != null) { + MemoryStack.stackPush().use { stack -> + val minimum = stack.mallocLong(1) + val maximum = stack.mallocLong(1) + val current = stack.mallocLong(1) + + minimum.put(0L) + maximum.put(0L) + current.put(0L) + + minimum.position(0) + maximum.position(0) + current.position(0) + + bindings.NtQueryTimerResolution(minimum, maximum, current) + + SYSTEM_SCHEDULER_RESOLUTION = current[0] * 150L // give some room for error + LOGGER.info("NtQueryTimerResolution(): {} ns/{} ns/{} ns min/max/current", minimum[0] * 100L, maximum[0] * 100L, current[0] * 100L) + } + } + + val thread = object : Thread("Process scheduler timer hack thread") { override fun run() { while (true) { try {