From 6a33c4b4bf03f02a7111045efbf2a4a5958be30a Mon Sep 17 00:00:00 2001 From: Sotr Date: Sun, 27 May 2018 22:54:40 +0800 Subject: [PATCH] Parallel loading libraries --- .../akarin/server/mixin/core/Bootstrap.java | 2 +- .../server/mixin/core/MixinMetrics.java | 2 - .../server/mixin/core/ParallelRegistry.java | 141 ++++++++++++++++++ .../main/resources/mixins.akarin.core.json | 3 +- 4 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java diff --git a/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java b/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java index 9ef5f801b..0df273a7a 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java @@ -45,6 +45,6 @@ public class Bootstrap { args = "ldc=Loading libraries, please wait..." )) private static void notifyLoading(PrintStream stream, String text) { - LogWrapper.logger.info("Loading libraries, please wait.."); + LogWrapper.logger.info("Loading libraries as parallel capable.."); } } diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinMetrics.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinMetrics.java index 5a13747b7..762632b3c 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinMetrics.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinMetrics.java @@ -16,8 +16,6 @@ import org.spongepowered.asm.mixin.Shadow; import com.destroystokyo.paper.Metrics; import com.destroystokyo.paper.Metrics.CustomChart; -import io.akarin.api.LogWrapper; - @Mixin(value = Metrics.class, remap = false) public class MixinMetrics { // The url to which the data is sent - bukkit/Torch (keep our old name) diff --git a/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java b/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java new file mode 100644 index 000000000..92ca12b19 --- /dev/null +++ b/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java @@ -0,0 +1,141 @@ +package io.akarin.server.mixin.core; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import io.akarin.api.LogWrapper; +import net.minecraft.server.BiomeBase; +import net.minecraft.server.Block; +import net.minecraft.server.BlockFire; +import net.minecraft.server.DispenserRegistry; +import net.minecraft.server.Enchantment; +import net.minecraft.server.EntityTypes; +import net.minecraft.server.Item; +import net.minecraft.server.MobEffectList; +import net.minecraft.server.PotionBrewer; +import net.minecraft.server.PotionRegistry; +import net.minecraft.server.SoundEffect; + +@Mixin(value = DispenserRegistry.class, remap = false) +public class ParallelRegistry { + private static final ThreadFactory STAGE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Parallel Registry Thread - %1$d").build(); + + /** + * Registry order: SoundEffect -> Block -> BlockFire -> Item -> PotionBrewer -> BiomeBase + */ + private static final ExecutorService STAGE_A = Executors.newSingleThreadExecutor(STAGE_FACTORY); // TODO go deeper! + /** + * Registry order: MobEffectList -> PotionRegistry + */ + private static final ExecutorService STAGE_B = Executors.newSingleThreadExecutor(STAGE_FACTORY); + /** + * Registry order: Enchantment -> EntityTypes + */ + private static final ExecutorService STAGE_C = Executors.newSingleThreadExecutor(STAGE_FACTORY); + + private static final int TERMINATION_IN_SEC = 30; + + @Redirect(method = "c()V", at = @At( + value = "INVOKE", + target = "net/minecraft/server/SoundEffect.b()V" + )) + private static void soundEffect() { + STAGE_A.execute(() -> SoundEffect.b()); + } + + @Redirect(method = "c()V", at = @At( + value = "INVOKE", + target = "net/minecraft/server/Block.w()V" + )) + private static void block() { + STAGE_A.execute(() -> Block.w()); + } + + @Redirect(method = "c()V", at = @At( + value = "INVOKE", + target = "net/minecraft/server/BlockFire.e()V" + )) + private static void blockFire() { + STAGE_A.execute(() -> BlockFire.e()); + } + + @Redirect(method = "c()V", at = @At( + value = "INVOKE", + target = "net/minecraft/server/MobEffectList.k()V" + )) + private static void mobEffectList() { + STAGE_B.execute(() -> MobEffectList.k()); + } + + @Redirect(method = "c()V", at = @At( + value = "INVOKE", + target = "net/minecraft/server/Enchantment.g()V" + )) + private static void enchantment() { + STAGE_C.execute(() -> Enchantment.g()); + } + + @Redirect(method = "c()V", at = @At( + value = "INVOKE", + target = "net/minecraft/server/Item.t()V" + )) + private static void item() { + STAGE_A.execute(() -> Item.t()); + } + + @Redirect(method = "c", at = @At( + value = "INVOKE", + target = "net/minecraft/server/PotionRegistry.b()V" + )) + private static void potionRegistry() { + STAGE_B.execute(() -> PotionRegistry.b()); + } + + @Redirect(method = "c", at = @At( + value = "INVOKE", + target = "net/minecraft/server/PotionBrewer.a()V" + )) + private static void potionBrewer() { + STAGE_A.execute(() -> PotionBrewer.a()); + } + + @Redirect(method = "c", at = @At( + value = "INVOKE", + target = "net/minecraft/server/EntityTypes.c()V" + )) + private static void entityTypes() { + STAGE_C.execute(() -> EntityTypes.c()); + } + + @Redirect(method = "c", at = @At( + value = "INVOKE", + target = "net/minecraft/server/BiomeBase.q()V" + )) + private static void biomeBase() { + STAGE_A.execute(() -> BiomeBase.q()); + } + + @Inject(method = "c", at = @At( + value = "INVOKE", + target = "net/minecraft/server/DispenserRegistry.b()V", + shift = At.Shift.BEFORE + )) + private static void await(CallbackInfo info) throws InterruptedException { + STAGE_A.shutdown(); + STAGE_B.shutdown(); + STAGE_C.shutdown(); + STAGE_A.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); + STAGE_B.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); + STAGE_C.awaitTermination(TERMINATION_IN_SEC, TimeUnit.SECONDS); + } +} diff --git a/sources/src/main/resources/mixins.akarin.core.json b/sources/src/main/resources/mixins.akarin.core.json index e9d003c03..d4b94d28c 100644 --- a/sources/src/main/resources/mixins.akarin.core.json +++ b/sources/src/main/resources/mixins.akarin.core.json @@ -5,9 +5,10 @@ "target": "@env(DEFAULT)", "compatibilityLevel": "JAVA_8", "server": [ + "Watchcat", "Bootstrap", "DummyEula", - "Watchcat", + "ParallelRegistry", "MixinMetrics", "MixinPaperConfig",