diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index c6d2a883..9255011f 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -13,6 +13,7 @@ import org.embeddedt.modernfix.classloading.FastAccessTransformerList; import org.embeddedt.modernfix.classloading.ModernFixResourceFinder; import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig; import org.embeddedt.modernfix.core.config.Option; +import org.embeddedt.modernfix.load.ModWorkManagerQueue; import org.embeddedt.modernfix.util.DummyList; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; @@ -83,6 +84,7 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { } FastAccessTransformerList.attemptReplace(); + ModWorkManagerQueue.replace(); /* https://github.com/FabricMC/Mixin/pull/99 */ try { diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index d3cbb02d..83080de9 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -56,7 +56,6 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.async_jei", modPresent("jei")); this.addMixinRule("perf.thread_priorities", true); this.addMixinRule("perf.preload_block_classes", false); - this.addMixinRule("perf.sync_executor_sleep", true); this.addMixinRule("perf.scan_cache", true); this.addMixinRule("perf.compress_biome_container", true); this.addMixinRule("perf.nuke_empty_chunk_sections", true); diff --git a/src/main/java/org/embeddedt/modernfix/load/ModWorkManagerQueue.java b/src/main/java/org/embeddedt/modernfix/load/ModWorkManagerQueue.java new file mode 100644 index 00000000..e6a870b0 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/load/ModWorkManagerQueue.java @@ -0,0 +1,60 @@ +package org.embeddedt.modernfix.load; + +import net.minecraftforge.fml.ModWorkManager; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; + +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; + +public class ModWorkManagerQueue extends ConcurrentLinkedDeque { + private static final long PARK_TIME = TimeUnit.MILLISECONDS.toNanos(25); + + private static final Runnable DUMMY_TASK = () -> {}; + + private boolean shouldReturnDummyTask = false; + + /** + * Sleep for a bit if there are no tasks. + */ + @Override + public Runnable pollFirst() { + Runnable r = super.pollFirst(); + if(r == null) { + LockSupport.parkNanos(PARK_TIME); + boolean isReturning = shouldReturnDummyTask; + shouldReturnDummyTask = !shouldReturnDummyTask; + /* + * We need to kick FML to redraw the loading screen periodically, + * but also allow actually exiting the executor loop, so that + * loading can complete if async work is done. + * + * This is accomplished by alternating between returning a dummy + * task and nothing. + */ + return isReturning ? DUMMY_TASK : null; + } else { + return r; + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static void replace() { + try { + Class syncExecutorClass = Class.forName("net.minecraftforge.fml.ModWorkManager$SyncExecutor"); + ConcurrentLinkedDeque taskQueue = (ConcurrentLinkedDeque)ObfuscationReflectionHelper.getPrivateValue((Class)syncExecutorClass, (Object)ModWorkManager.syncExecutor(), "tasks"); + ModWorkManagerQueue q = new ModWorkManagerQueue(); + Runnable task; + do { + task = taskQueue.pollFirst(); + if(task != null) + q.push(task); + } while(task != null); + ObfuscationReflectionHelper.setPrivateValue((Class)syncExecutorClass, (Object)ModWorkManager.syncExecutor(), q, "tasks"); + } catch(ReflectiveOperationException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/sync_executor_sleep/SyncExecutorMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/sync_executor_sleep/SyncExecutorMixin.java deleted file mode 100644 index 81d59b09..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/sync_executor_sleep/SyncExecutorMixin.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.sync_executor_sleep; - -import net.minecraftforge.fml.ModWorkManager; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; - -@Mixin(targets = "net/minecraftforge/fml/ModWorkManager$SyncExecutor") -public abstract class SyncExecutorMixin { - @Shadow(remap = false) public abstract boolean driveOne(); - - private static final long PARK_TIME = TimeUnit.MILLISECONDS.toNanos(50); - - /** - * Currently FML spins in driveOne while waiting for the modloading workers. We can improve this - * by sleeping for 50ms at a time. - * - * Also, render FML splash screen regardless of task availability. - * @author embeddedt - * @reason improve CPU efficiency - */ - public void drive(Runnable ticker) { - int executions = 0; - do { - executions++; - ticker.run(); - } while(driveOne()); - if(executions < 2) - LockSupport.parkNanos(PARK_TIME); - } -} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index a0e39552..58795e9f 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -30,7 +30,6 @@ "perf.reduce_blockstate_cache_rebuilds.BlocksMixin", "perf.reduce_blockstate_cache_rebuilds.BlockStateBaseMixin", "perf.deduplicate_location.MixinResourceLocation", - "perf.sync_executor_sleep.SyncExecutorMixin", "perf.compress_biome_container.MixinBiomeContainer", "perf.nuke_empty_chunk_sections.MixinChunk", "perf.cache_blockstate_cache_arrays.AbstractBlockStateCacheMixin",