Use reflection instead of mixins for SyncExecutor patch

This commit is contained in:
embeddedt 2023-04-13 13:00:43 -04:00
parent 9443c41273
commit c4fbde015e
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
5 changed files with 62 additions and 40 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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<Runnable> {
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<Runnable> taskQueue = (ConcurrentLinkedDeque<Runnable>)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();
}
}
}

View File

@ -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);
}
}

View File

@ -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",