From bf74ab5a80375db6143660bc64864d912c9c7024 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:40:42 -0400 Subject: [PATCH] Mitigate excessive resource usage from Night Config --- .../config/NightConfigWatchThrottler.java | 56 +++++++++++++++++++ .../forge/ModernFixPlatformHooksImpl.java | 2 + 2 files changed, 58 insertions(+) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/config/NightConfigWatchThrottler.java diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/config/NightConfigWatchThrottler.java b/forge/src/main/java/org/embeddedt/modernfix/forge/config/NightConfigWatchThrottler.java new file mode 100644 index 00000000..ae75e00f --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/config/NightConfigWatchThrottler.java @@ -0,0 +1,56 @@ +package org.embeddedt.modernfix.forge.config; + +import com.electronwill.nightconfig.core.file.FileWatcher; +import com.google.common.collect.ForwardingCollection; +import com.google.common.collect.ForwardingMap; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; + +/** + * Throttle NightConfig's file watching. There are reports of this consuming excessive CPU time + * (example) and the spammed iterator calls + * end up being 10% of allocations when testing in a dev environment. + */ +public class NightConfigWatchThrottler { + private static final long DELAY = TimeUnit.MILLISECONDS.toNanos(1000); + + @SuppressWarnings("rawtypes") + public static void throttle() { + Map watchedDirs = ObfuscationReflectionHelper.getPrivateValue(FileWatcher.class, FileWatcher.defaultInstance(), "watchedDirs"); + ObfuscationReflectionHelper.setPrivateValue(FileWatcher.class, FileWatcher.defaultInstance(), new ForwardingMap() { + @Override + protected Map delegate() { + return watchedDirs; + } + + private Collection cachedValues; + + @Override + public Collection values() { + if(cachedValues == null) { + Collection values = super.values(); + cachedValues = new ForwardingCollection() { + @Override + protected Collection delegate() { + return values; + } + + @Override + public Iterator iterator() { + // iterator() is called at the beginning of each iteration of the watch loop, + // so it is a good spot to inject the delay. + LockSupport.parkNanos(DELAY); + return super.iterator(); + } + }; + } + return cachedValues; + } + }, "watchedDirs"); + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java b/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java index b9c3fe2b..3eb8a2c0 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java +++ b/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java @@ -31,6 +31,7 @@ import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.embeddedt.modernfix.forge.classloading.FastAccessTransformerList; import org.embeddedt.modernfix.forge.classloading.ModernFixResourceFinder; import org.embeddedt.modernfix.forge.config.NightConfigFixer; +import org.embeddedt.modernfix.forge.config.NightConfigWatchThrottler; import org.embeddedt.modernfix.forge.init.ModernFixForge; import org.embeddedt.modernfix.forge.packet.PacketHandler; import org.embeddedt.modernfix.forge.spark.SparkLaunchProfiler; @@ -192,6 +193,7 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks { } NightConfigFixer.monitorFileWatcher(); + NightConfigWatchThrottler.throttle(); MixinExtrasBootstrap.init(); }