diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index ef9af07e..c713816c 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -9,6 +9,7 @@ import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; +import org.embeddedt.modernfix.spark.SparkLaunchProfiler; import org.embeddedt.modernfix.util.ClassInfoManager; import org.embeddedt.modernfix.world.IntegratedWatchdog; @@ -90,6 +91,9 @@ public class ModernFixClient { ModernFix.LOGGER.warn("Time from main menu to in-game was " + timeSpentLoading + " seconds"); ModernFix.LOGGER.warn("Total time to load game and open world was " + (timeSpentLoading + gameStartTimeSeconds) + " seconds"); } + if (ModernFixPlatformHooks.INSTANCE.modPresent("spark") && ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_world_join.WorldJoin")) { + SparkLaunchProfiler.stop("world_join"); + } resetWorldLoadStateMachine(); } } diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/spark_profile_world_join/MinecraftMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/spark_profile_world_join/MinecraftMixin.java new file mode 100644 index 00000000..f817ec71 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/spark_profile_world_join/MinecraftMixin.java @@ -0,0 +1,18 @@ +package org.embeddedt.modernfix.common.mixin.feature.spark_profile_world_join; + +import net.minecraft.client.Minecraft; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.spark.SparkLaunchProfiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +@ClientOnlyMixin +public class MinecraftMixin { + @Inject(method = "prepareForMultiplayer", at = @At("HEAD")) + private void startProfiling(CallbackInfo ci) { + SparkLaunchProfiler.start("world_join"); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/spark_profile_world_join/WorldLoaderMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/spark_profile_world_join/WorldLoaderMixin.java new file mode 100644 index 00000000..713886b7 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/spark_profile_world_join/WorldLoaderMixin.java @@ -0,0 +1,18 @@ +package org.embeddedt.modernfix.common.mixin.feature.spark_profile_world_join; + +import net.minecraft.server.WorldLoader; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.spark.SparkLaunchProfiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(WorldLoader.class) +@ClientOnlyMixin +public class WorldLoaderMixin { + @Inject(method = "load", at = @At("HEAD")) + private static void startProfiling(CallbackInfoReturnable cir) { + SparkLaunchProfiler.start("world_join"); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/memoize_creative_tab_build/CreativeModeTabMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/memoize_creative_tab_build/CreativeModeTabMixin.java index c74bb4a2..989e8066 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/memoize_creative_tab_build/CreativeModeTabMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/memoize_creative_tab_build/CreativeModeTabMixin.java @@ -2,15 +2,22 @@ package org.embeddedt.modernfix.common.mixin.perf.memoize_creative_tab_build; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.CreativeModeTab; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @Mixin(CreativeModeTab.class) -public class CreativeModeTabMixin { +public abstract class CreativeModeTabMixin { + @Shadow public abstract CreativeModeTab.Type getType(); + @Unique private CreativeModeTab.ItemDisplayParameters mfix$oldParameters; + @Unique + private static boolean MFIX$REBUILT_NON_CATEGORY = false; + /** * @author embeddedt * @reason Vanilla already does similar memoization in the CreativeModeTabs class, but mods often have to bypass @@ -20,9 +27,26 @@ public class CreativeModeTabMixin { */ @WrapMethod(method = "buildContents") private synchronized void buildContentsIfChanged(CreativeModeTab.ItemDisplayParameters parameters, Operation original) { - if (mfix$oldParameters == null || mfix$oldParameters.needsUpdate(parameters.enabledFeatures(), parameters.hasPermissions(), parameters.holders())) { - original.call(parameters); + synchronized (CreativeModeTab.class) { + if (mfix$oldParameters == null || mfix$oldParameters.needsUpdate(parameters.enabledFeatures(), parameters.hasPermissions(), parameters.holders())) { + original.call(parameters); + if (this.getType() == CreativeModeTab.Type.CATEGORY) { + if (MFIX$REBUILT_NON_CATEGORY) { + // We must mark every other tab that's not a category as needing rebuild. Not doing this causes mods + // that build a search tab early on without having built the dependencies to permanently leave it + // in a broken state. + for (CreativeModeTab tab : BuiltInRegistries.CREATIVE_MODE_TAB) { + if (tab.getType() != CreativeModeTab.Type.CATEGORY) { + ((CreativeModeTabMixin)(Object)tab).mfix$oldParameters = null; + } + } + MFIX$REBUILT_NON_CATEGORY = false; + } + } else { + MFIX$REBUILT_NON_CATEGORY = true; + } + } + mfix$oldParameters = parameters; } - mfix$oldParameters = parameters; } } diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTag1Mixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTag1Mixin.java deleted file mode 100644 index ed71f082..00000000 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTag1Mixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.embeddedt.modernfix.common.mixin.perf.nbt_memory_usage; - -import net.minecraft.nbt.Tag; -import org.embeddedt.modernfix.util.CanonizingStringMap; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -import java.util.Map; - -@Mixin(targets = "net/minecraft/nbt/CompoundTag$1") -public class CompoundTag1Mixin { - @ModifyVariable(method = "loadCompound", at = @At(value = "INVOKE_ASSIGN", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;", remap = false)) - private static Map modifyMap(Map map) { - CanonizingStringMap newMap = new CanonizingStringMap<>(); - if(map != null) - newMap.putAll(map); - return newMap; - } -} \ No newline at end of file diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java deleted file mode 100644 index 274af319..00000000 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.embeddedt.modernfix.common.mixin.perf.nbt_memory_usage; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import org.embeddedt.modernfix.util.CanonizingStringMap; -import org.spongepowered.asm.mixin.*; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.Map; - -@Mixin(CompoundTag.class) -public class CompoundTagMixin { - @Shadow @Final - private Map tags; - - /** - * Ensure that the default backing map is a CanonizingStringMap. - */ - @ModifyArg(method = "()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/CompoundTag;(Ljava/util/Map;)V"), index = 0) - private static Map useCanonizingStringMap(Map incoming) { - CanonizingStringMap newMap = new CanonizingStringMap<>(); - if(incoming != null) - newMap.putAll(incoming); - return newMap; - } - - /** - * @author embeddedt - * @reason use more efficient method when copying canonizing string map - */ - @Inject(method = "copy()Lnet/minecraft/nbt/CompoundTag;", at = @At("HEAD"), cancellable = true) - public void copyEfficient(CallbackInfoReturnable cir) { - if(this.tags instanceof CanonizingStringMap) { - cir.setReturnValue(new CompoundTag(CanonizingStringMap.deepCopy((CanonizingStringMap)this.tags, Tag::copy))); - } - } -} diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 10c194dc..375c5320 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -181,6 +181,7 @@ public class ModernFixEarlyConfig { .put("mixin.feature.snapshot_easter_egg", true) .put("mixin.feature.warn_missing_perf_mods", true) .put("mixin.feature.spark_profile_launch", false) + .put("mixin.feature.spark_profile_world_join", false) .put("mixin.feature.log_stdout_in_log_files", true) .put("mixin.devenv", isDevEnv) .putConditionally(() -> !isFabric, "mixin.bugfix.fix_config_crashes", true) @@ -237,6 +238,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.bugfix.buffer_builder_leak", "isometric-renders", "witherstormmod"); disableIfModPresent("mixin.feature.remove_chat_signing", "nochatreports"); disableIfModPresent("mixin.perf.faster_texture_loading", "stitch", "optifine", "changed"); + disableIfModPresent("mixin.perf.faster_ingredients", "vmp"); if(isFabric) { disableIfModPresent("mixin.bugfix.packet_leak", "memoryleakfix"); } diff --git a/common/src/main/java/org/embeddedt/modernfix/spark/SparkLaunchProfiler.java b/common/src/main/java/org/embeddedt/modernfix/spark/SparkLaunchProfiler.java index 874819d2..92d5a1f0 100644 --- a/common/src/main/java/org/embeddedt/modernfix/spark/SparkLaunchProfiler.java +++ b/common/src/main/java/org/embeddedt/modernfix/spark/SparkLaunchProfiler.java @@ -36,17 +36,19 @@ public class SparkLaunchProfiler { private static ExecutorService executor = Executors.newSingleThreadScheduledExecutor((new ThreadFactoryBuilder()).setNameFormat("spark-modernfix-async-worker").build()); private static final SparkPlatform platform = new SparkPlatform(new ModernFixSparkPlugin()); - private static final boolean USE_JAVA_SAMPLER_FOR_LAUNCH = true; //Boolean.getBoolean("modernfix.profileLaunchWithJavaSampler"); + private static final boolean USE_JAVA_SAMPLER_FOR_LAUNCH = !Boolean.getBoolean("modernfix.profileWithAsyncSampler"); + private static final int SAMPLING_INTERVAL = Integer.getInteger("modernfix.profileSamplingIntervalMicroseconds", 4000); + private static final String THREAD_GROUPER = System.getProperty("modernfix.profileSamplingThreadGrouper", "by-pool"); public static void start(String key) { if (!ongoingSamplers.containsKey(key)) { Sampler sampler; - SamplerSettings settings = new SamplerSettings(4000, ThreadDumper.ALL, ThreadGrouper.BY_NAME.get(), -1, false, true); + SamplerSettings settings = new SamplerSettings(SAMPLING_INTERVAL, ThreadDumper.ALL, ThreadGrouper.parseConfigSetting(THREAD_GROUPER).get(), -1, false, true); try { if(USE_JAVA_SAMPLER_FOR_LAUNCH) { throw new UnsupportedOperationException(); } - sampler = new AsyncSampler(platform, settings, new SampleCollector.Execution(4000)); + sampler = new AsyncSampler(platform, settings, new SampleCollector.Execution(SAMPLING_INTERVAL)); } catch (UnsupportedOperationException e) { sampler = new JavaSampler(platform, settings); }