diff --git a/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java b/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java index 99b1c1d..79a8acf 100644 --- a/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java +++ b/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java @@ -570,6 +570,9 @@ public static class Performance { @Config.Name("EnderIOConduits") public final EnderIOConduits enderIOConduits = new EnderIOConduits(); + @Config.Name("FluxNetworks") + public final FluxNetworks fluxNetworks = new FluxNetworks(); + @Config.Name("FTBLib") public final FTBLib ftbLib = new FTBLib(); @@ -1020,6 +1023,18 @@ public static class EnderIOConduits { } + public static class FluxNetworks { + + @Config.Comment("(Server Performance | Experimental) Rewriting the flux network calculation logic to improve performance using multithreading.") + @Config.Name("ParallelNetworkCalculation") + public boolean parallelNetworkCalculation = false; + + @Config.Comment("(Server Performance) Removing the secondary judgement of energy transfer may help improve performance.") + @Config.Name("ConnectionTransferImprovements") + public boolean connectionTransfer = true; + + } + public static class FTBLib { @Config.Comment("(Server Performance) Improved some of the judgments so that it doesn't consume a lot of time sending network packets.") diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/ebwizardry/MixinDispenserCastingData.java b/src/main/java/github/kasuminova/stellarcore/mixin/ebwizardry/MixinDispenserCastingData.java index cb2a467..8f9a7f8 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/ebwizardry/MixinDispenserCastingData.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/ebwizardry/MixinDispenserCastingData.java @@ -2,21 +2,21 @@ import electroblob.wizardry.data.DispenserCastingData; import github.kasuminova.stellarcore.common.config.StellarCoreConfig; +import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityDispenser; import net.minecraftforge.fml.common.gameevent.TickEvent; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @Mixin(value = DispenserCastingData.class, remap = false) public abstract class MixinDispenserCastingData { - @SuppressWarnings("SimplifyStreamApiCallChains") @Inject(method = "onWorldTickEvent", at = @At("HEAD"), cancellable = true) private static void injectOnWorldTickEvent(final TickEvent.WorldTickEvent event, final CallbackInfo ci) { if (!StellarCoreConfig.PERFORMANCE.ebWizardry.dispenserCastingData) { @@ -28,13 +28,22 @@ private static void injectOnWorldTickEvent(final TickEvent.WorldTickEvent event, ci.cancel(); // Use parallel stream to find Capability to improve performance. - new ArrayList<>(event.world.loadedTileEntityList) - .parallelStream() + try { + stellar_core$executeParallel(event.world.loadedTileEntityList); + } catch (ConcurrentModificationException | NullPointerException e) { + // CME? + stellar_core$executeParallel(new ArrayList<>(event.world.loadedTileEntityList)); + } + } + + @Unique + private static void stellar_core$executeParallel(final List tileEntityList) { + tileEntityList.parallelStream() .filter(TileEntityDispenser.class::isInstance) .map(TileEntityDispenser.class::cast) .map(DispenserCastingData::get) .filter(Objects::nonNull) - .collect(Collectors.toList()) + .collect(Collectors.toCollection(LinkedList::new)) .forEach(DispenserCastingData::update); } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java index 0763030..320e355 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java @@ -6,7 +6,6 @@ import crazypants.enderio.conduits.conduit.power.PowerConduitNetwork; import crazypants.enderio.conduits.conduit.power.PowerTracker; import github.kasuminova.stellarcore.common.config.StellarCoreConfig; -import github.kasuminova.stellarcore.common.util.StellarLog; import github.kasuminova.stellarcore.mixin.util.ICapBankSupply; import github.kasuminova.stellarcore.mixin.util.IStellarNetworkPowerManager; import github.kasuminova.stellarcore.mixin.util.ReceptorPowerInterface; @@ -24,8 +23,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; @Mixin(value = NetworkPowerManager.class, remap = false) public abstract class MixinNetworkPowerManager implements IStellarNetworkPowerManager { @@ -74,7 +73,7 @@ public abstract class MixinNetworkPowerManager implements IStellarNetworkPowerMa private final List stellar_core$collectedPowerInterface = new ObjectArrayList<>(); @Unique - private Future stellar_core$parallelTask = null; + private ForkJoinTask stellar_core$parallelTask = null; @Unique private volatile boolean stellar_core$shouldFinalApply = false; @@ -98,7 +97,7 @@ public void doApplyRecievedPower(final Profiler theProfiler, final CallbackInfo trackerStartTick(); checkReceptors(); - stellar_core$parallelTask = CompletableFuture.runAsync(() -> { + stellar_core$parallelTask = ForkJoinPool.commonPool().submit(() -> { // Update our energy stored based on what's in our conduits updateNetworkStorage(); networkPowerTracker.tickStart(energyStored); @@ -136,11 +135,7 @@ public void finalApplyReceivedPower() { } if (stellar_core$parallelTask != null && !stellar_core$parallelTask.isDone()) { - try { - stellar_core$parallelTask.get(); - } catch (Throwable e) { - StellarLog.LOG.warn("[StellarCore-MixinNetworkPowerManager] Error while waiting for parallel task to finish!", e); - } + stellar_core$parallelTask.join(); } stellar_core$parallelTask = null; if (!stellar_core$shouldFinalApply) { diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java index 9f7a2c1..2a1cd75 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java @@ -1,5 +1,6 @@ package github.kasuminova.stellarcore.mixin.fluxnetworks; +import github.kasuminova.stellarcore.common.config.StellarCoreConfig; import github.kasuminova.stellarcore.mixin.util.IStellarFluxNetwork; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraftforge.fml.common.gameevent.TickEvent; @@ -20,6 +21,9 @@ public class MixinCommonProxy { @Inject(method = "onServerTick", at = @At("HEAD")) private void injectOnServerTick(final TickEvent.ServerTickEvent event, final CallbackInfo ci) { + if (!StellarCoreConfig.PERFORMANCE.fluxNetworks.parallelNetworkCalculation) { + return; + } if (event.phase == TickEvent.Phase.END) { Collection networks = FluxNetworkCache.instance.getAllNetworks(); List runnableList = new ObjectArrayList<>(networks.size() + 1); diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java index 83b9885..70a08a0 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java @@ -1,8 +1,15 @@ package github.kasuminova.stellarcore.mixin.fluxnetworks; +import github.kasuminova.stellarcore.common.config.StellarCoreConfig; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; -import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import sonar.fluxnetworks.api.energy.ITileEnergyHandler; import sonar.fluxnetworks.common.connection.transfer.ConnectionTransfer; @@ -31,24 +38,30 @@ public class MixinConnectionTransfer { * @author Kasumi_Nova * @reason Selective judgement */ - @Overwrite - public long sendToTile(long amount, boolean simulate) { + @Inject(method = "sendToTile", at = @At("HEAD")) + public void sendToTile(final long amount, final boolean simulate, final CallbackInfoReturnable cir) { + if (!StellarCoreConfig.PERFORMANCE.fluxNetworks.connectionTransfer) { + return; + } if (simulate) { if (energyHandler.canAddEnergy(tile, side)) { stellar_core$canAddEnergy = true; - return energyHandler.addEnergy(amount, tile, side, true); + cir.setReturnValue(energyHandler.addEnergy(amount, tile, side, true)); + return; } stellar_core$canAddEnergy = false; - return 0; + cir.setReturnValue(0L); + return; } if (stellar_core$canAddEnergy) { stellar_core$canAddEnergy = false; long added = energyHandler.addEnergy(amount, tile, side, false); inbound += added; - return added; + cir.setReturnValue(added); + return; } - return 0; + cir.setReturnValue(0L); } } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java index 89c1f46..a82bc8c 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java @@ -11,10 +11,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import sonar.fluxnetworks.api.network.AccessLevel; -import sonar.fluxnetworks.api.network.FluxLogicType; -import sonar.fluxnetworks.api.network.IFluxNetwork; -import sonar.fluxnetworks.api.network.NetworkMember; +import sonar.fluxnetworks.api.network.*; import sonar.fluxnetworks.api.tiles.IFluxConnector; import sonar.fluxnetworks.api.tiles.IFluxPlug; import sonar.fluxnetworks.api.tiles.IFluxPoint; @@ -22,6 +19,7 @@ import sonar.fluxnetworks.common.connection.FluxNetworkServer; import sonar.fluxnetworks.common.connection.PriorityGroup; import sonar.fluxnetworks.common.connection.TransferIterator; +import sonar.fluxnetworks.common.connection.transfer.FluxControllerHandler; import java.util.List; import java.util.Optional; @@ -59,7 +57,16 @@ public Runnable getCycleStartRunnable() { handleConnectionQueue(); return () -> { List devices = getConnections(FluxLogicType.ANY); - devices.parallelStream().forEach(device -> device.getTransferHandler().onCycleStart()); + devices.parallelStream().forEach(device -> { + ITransferHandler handler = device.getTransferHandler(); + if (handler instanceof FluxControllerHandler) { + synchronized (FluxControllerHandler.class) { + handler.onCycleStart(); + } + } else { + handler.onCycleStart(); + } + }); }; } @@ -67,8 +74,13 @@ public Runnable getCycleStartRunnable() { * @author Kasumi_Nova * @reason Parallel Execution */ - @Overwrite - public void onEndServerTick() { + @Inject(method = "onEndServerTick", at = @At("HEAD")) + public void onEndServerTick(final CallbackInfo ci) { + if (!StellarCoreConfig.PERFORMANCE.fluxNetworks.parallelNetworkCalculation) { + return; + } + ci.cancel(); + network_stats.getValue().startProfiling(); bufferLimiter = 0;