From c8675f646cfc8088fd532f802c5da27be6899231 Mon Sep 17 00:00:00 2001 From: Martijn Muijsers Date: Mon, 6 Feb 2023 18:41:44 +0100 Subject: [PATCH] Notify ServerChunkCache of completed chunk worker tasks to trigger chunk manager mid tick --- patches/server/0148-Base-thread-pool.patch | 196 ++++++++++++------ ...c-executor-tasks-on-base-thread-pool.patch | 10 +- ...un-cleaner-tasks-on-base-thread-pool.patch | 4 +- ...hunk-cache-tasks-on-base-thread-pool.patch | 37 ++-- ...read-chunk-tasks-on-base-thread-pool.patch | 10 +- ...unk-worker-tasks-on-base-thread-pool.patch | 20 +- patches/server/0162-Split-tick-steps.patch | 18 +- 7 files changed, 189 insertions(+), 106 deletions(-) diff --git a/patches/server/0148-Base-thread-pool.patch b/patches/server/0148-Base-thread-pool.patch index 48eef00..f2fea67 100644 --- a/patches/server/0148-Base-thread-pool.patch +++ b/patches/server/0148-Base-thread-pool.patch @@ -557,7 +557,7 @@ index 0c4c62674b4c7e8e3921c7eb3ef726759ac75075..40f20806cc06106b4aa8e708467dcea9 WorldLoader.InitConfig worldloader_c = Main.loadOrCreateConfig(dedicatedserversettings.getProperties(), convertable_conversionsession, flag, resourcepackrepository); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a135c63f23c 100644 +index eb951c9fda85d9620d3038a3db22d578db45e878..fe2892e20dcb0b76d30b81bca7a13e29a1c45723 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -40,10 +40,8 @@ import java.util.Optional; @@ -591,7 +591,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 import net.minecraft.world.Difficulty; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.village.VillageSiege; -@@ -161,7 +148,15 @@ import net.minecraft.world.level.storage.loot.PredicateManager; +@@ -161,7 +148,16 @@ import net.minecraft.world.level.storage.loot.PredicateManager; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.Validate; @@ -600,6 +600,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 +import org.galemc.gale.executor.annotation.thread.OriginalServerThreadOnly; +import org.galemc.gale.executor.queue.BaseTaskQueues; +import org.galemc.gale.executor.queue.ScheduledServerThreadTaskQueues; ++import org.galemc.gale.executor.thread.BaseThread; +import org.galemc.gale.executor.thread.OriginalServerThread; +import org.galemc.gale.executor.thread.SignalReason; +import org.galemc.gale.executor.thread.pool.BaseThreadActivation; @@ -607,7 +608,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 import org.slf4j.Logger; // CraftBukkit start -@@ -181,23 +176,26 @@ import net.minecraft.world.level.levelgen.PatrolSpawner; +@@ -181,23 +177,26 @@ import net.minecraft.world.level.levelgen.PatrolSpawner; import net.minecraft.world.level.levelgen.PhantomSpawner; import net.minecraft.world.level.levelgen.WorldDimensions; import net.minecraft.world.level.levelgen.presets.WorldPresets; @@ -642,7 +643,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 public static final String VANILLA_BRAND = "vanilla"; private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F; private static final int TICK_STATS_SPAN = 100; -@@ -226,6 +224,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop registries; private Map, ServerLevel> levels; @@ -653,7 +654,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 private PlayerList playerList; private volatile boolean running; private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart -@@ -255,10 +257,114 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; public Commands vanillaCommandDispatcher; @@ -781,7 +782,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 // CraftBukkit end // Spigot start public static final int TPS = 20; -@@ -303,9 +409,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop holdergetter = this.registries.compositeAccess().registryOrThrow(Registries.BLOCK).asLookup().filterFeatures(this.worldData.enabledFeatures()); this.structureTemplateManager = new StructureTemplateManager(worldstem.resourceManager(), convertable_conversionsession, datafixer, holdergetter); @@ -828,7 +829,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 this.executor = Util.backgroundExecutor(); } // CraftBukkit start -@@ -599,7 +711,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop optional = Optional.of(this.getFile("server-icon.png")).filter(File::isFile); -@@ -1378,14 +1486,19 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= 5000000000L) { this.lastServerStatus = i; -@@ -1420,7 +1533,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { this.playerList.saveAll(playerSaveInterval); } @@ -1147,7 +1148,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 if (level.paperConfig().chunks.autoSaveInterval.value() > 0) { level.saveIncrementally(fullSave); } -@@ -1432,7 +1545,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper -@@ -1569,7 +1680,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); newLevels.put(level.dimension(), level); this.levels = Collections.unmodifiableMap(newLevels); @@ -1213,7 +1214,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 } public void removeLevel(ServerLevel level) { -@@ -1598,6 +1721,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); newLevels.remove(level.dimension()); this.levels = Collections.unmodifiableMap(newLevels); @@ -1228,7 +1229,7 @@ index eb951c9fda85d9620d3038a3db22d578db45e878..ac12cabaf15bc3520ff74d09faa48a13 } // CraftBukkit end -@@ -1605,8 +1736,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { ++ return; ++ } ++ // Gale end - base thread pool + org.spigotmc.AsyncCatcher.catchOp("mid tick chunk task execution"); + long startTime = System.nanoTime(); + if ((startTime - lastMidTickExecute) <= CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME || (startTime - lastMidTickExecuteFailure) <= TASK_EXECUTION_FAILURE_BACKOFF) { diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java index f0a7a8df3caa2ea765bb0a87cfede71d0995d276..16f3475b059d2b6b85d2b342e84ab32de8e86ac0 100644 --- a/src/main/java/net/minecraft/server/commands/TimeCommand.java @@ -2342,14 +2356,16 @@ index 0000000000000000000000000000000000000000..84aa4f8e3f823cedc8cf958663fa2168 +} diff --git a/src/main/java/org/galemc/gale/executor/TaskSpan.java b/src/main/java/org/galemc/gale/executor/TaskSpan.java new file mode 100644 -index 0000000000000000000000000000000000000000..1d5bb1ba545200f954c886a2afb9d8ee2a3cc4d1 +index 0000000000000000000000000000000000000000..99dcb582bf6557c54d9e1477434710ba92b2d87a --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/TaskSpan.java -@@ -0,0 +1,62 @@ +@@ -0,0 +1,70 @@ +// Gale - base thread pool + +package org.galemc.gale.executor; + ++import java.util.Arrays; ++ +/** + * An enum for the behaviour of a task, in terms of its potential to yield + * and its expected time cost to finish. @@ -2407,6 +2423,12 @@ index 0000000000000000000000000000000000000000..1d5bb1ba545200f954c886a2afb9d8ee + */ + public static final int length = VALUES.length; + ++ /** ++ * Equal to {@link #VALUES} for which {@link #isNotYielding} is true. ++ */ ++ public static final TaskSpan[] NON_YIELDING_VALUES = Arrays.stream(VALUES).filter(span -> span.isNotYielding).toList().toArray(new TaskSpan[length - 1]); ++ ++ +} diff --git a/src/main/java/org/galemc/gale/executor/annotation/PotentiallyBlocking.java b/src/main/java/org/galemc/gale/executor/annotation/PotentiallyBlocking.java index a4dc0ebe48fdd352387f06be42ff46fc11ee5822..d324c303245bcbedaaaab573803d73caff941901 100644 @@ -3035,10 +3057,10 @@ index 0000000000000000000000000000000000000000..552e82a33c59261b06911b479400a7b1 +} diff --git a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..2eb121798b2feb2a5ce5ebb60316660dbff87de3 +index 0000000000000000000000000000000000000000..657c3663ed54043e7e4e6660d34903ef746fd8e7 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java -@@ -0,0 +1,130 @@ +@@ -0,0 +1,133 @@ +// Gale - base thread pool + +package org.galemc.gale.executor.queue; @@ -3122,6 +3144,9 @@ index 0000000000000000000000000000000000000000..2eb121798b2feb2a5ce5ebb60316660d + if (MinecraftServer.isInSpareTimeAndHaveNoMoreTimeAndNotAlreadyBlocking || !MinecraftServer.isConstructed) { + return null; + } ++ if (this.span.isYielding && !currentThread.canStartYieldingTasks) { ++ return null; ++ } + ServerLevel[] levels = MinecraftServer.SERVER.getAllLevelsArray(); + int startIndex = this.levelIterationIndex = Math.min(this.levelIterationIndex, levels.length - 1); + // Paper - force execution of all worlds, do not just bias the first @@ -3204,10 +3229,10 @@ index 0000000000000000000000000000000000000000..690979cb9b7ec3dedbd7d0c45d0c183a +} diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java new file mode 100644 -index 0000000000000000000000000000000000000000..e4a0b3085cb22f25246010c43919129283a3b872 +index 0000000000000000000000000000000000000000..7e24854f1e727e5e40108c68933466d0845bdca1 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -@@ -0,0 +1,125 @@ +@@ -0,0 +1,127 @@ +// Gale - base thread pool + +package org.galemc.gale.executor.queue; @@ -3218,6 +3243,7 @@ index 0000000000000000000000000000000000000000..e4a0b3085cb22f25246010c439191292 +import net.minecraft.world.entity.Entity; +import org.galemc.gale.executor.TaskSpan; +import org.galemc.gale.executor.thread.AssistThread; ++import org.galemc.gale.executor.thread.BaseThread; +import org.galemc.gale.executor.thread.ServerThread; + +import java.util.Arrays; @@ -3257,12 +3283,13 @@ index 0000000000000000000000000000000000000000..e4a0b3085cb22f25246010c439191292 + * subject (like an entity or chunk) with tasks that will be run on whichever ticking thread is the + * ticking thread for that subject at the time of polling. + *
-+ * Note that a {@link ServerThread} can only yield to {@link TaskSpan#TINY} tasks ++ * Note that a {@link ServerThread} can only yield to {@link TaskSpan#TINY} tasks in other tiers + * (since there are no higher tiers, and threads can only yield to lower tiers when -+ * the task yielded to is{@link TaskSpan#TINY}. ++ * the task yielded to is{@link TaskSpan#TINY}, or other non-yielding tasks in its own tier (since it ++ * has a {@link BaseThread#maximumYieldDepth} of 1). + * Yielding to other tasks in this same tier is somewhat risky, since this means that the tasks that were + * yielded to must assume that although they are running on the server thread, they may be running at -+ * some unknown point in execution of the main thread. Therefore, scheduling any {@link TaskSpan#TINY} tasks to ++ * some unknown point in execution of the main thread. Therefore, scheduling any non-yielding tasks to + * a queue in this tier must be done with the utmost care that the task cannot disrupt, or be disrupted by, + * the surrounding code that yields to it. + */ @@ -5596,10 +5623,10 @@ index 0000000000000000000000000000000000000000..77fe10e51b00115da520cfc211bf84ba +} diff --git a/src/main/java/org/galemc/gale/executor/thread/pool/BaseThreadActivation.java b/src/main/java/org/galemc/gale/executor/thread/pool/BaseThreadActivation.java new file mode 100644 -index 0000000000000000000000000000000000000000..a22b63a15fcc737494454c0d91c35eef5bb21d9e +index 0000000000000000000000000000000000000000..5554f23c4cca4e9f0be036e11c9e2c69ad6293ce --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/thread/pool/BaseThreadActivation.java -@@ -0,0 +1,552 @@ +@@ -0,0 +1,593 @@ +// Gale - base thread pool + +package org.galemc.gale.executor.thread.pool; @@ -5611,6 +5638,7 @@ index 0000000000000000000000000000000000000000..a22b63a15fcc737494454c0d91c35eef +import org.galemc.gale.executor.lock.YieldingLock; +import org.galemc.gale.executor.queue.BaseTaskQueueTier; +import org.galemc.gale.executor.thread.BaseThread; ++import org.galemc.gale.executor.thread.ServerThread; +import org.galemc.gale.executor.thread.SignalReason; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @@ -5851,6 +5879,54 @@ index 0000000000000000000000000000000000000000..a22b63a15fcc737494454c0d91c35eef + } + + /** ++ * Determines whether it could be useful to activate the given thread. ++ * This does not into account whether tasks {@linkplain #thereMayBeTasks may exist} at all, ++ * except for the checking on non-yielding {@link BaseTaskQueueTier#SERVER} tasks for the purpose explained below. ++ *
++ * We only activate threads that can start yielding tasks ++ * (it seems wasteful to take the effort to activate threads that can not), ++ * or threads that are waiting for a lock that is not currently locked. ++ *
++ * Note that for the server thread, if it cannot start yielding tasks, ++ * there is never an alternative thread that can, so we also allow it, ++ * as a special case, to be activated purely based on the existence of non-yielding tasks. ++ *
++ * This method must only be called from {@link #update}. ++ * ++ * @param thread The thread to consider. ++ * @param lockWaitingFor The pre-computed value of {@link BaseThread#lockWaitingFor}. ++ * @param isServerThread Whether the given thread is a {@link ServerThread}. ++ * @return Whether it could be useful to activate the given thread. ++ */ ++ private static boolean couldBeUsefullyActivatedForTasksOrLock(BaseThread thread, @Nullable YieldingLock lockWaitingFor, boolean isServerThread) { ++ if (!thread.isWaitingAndNeedsSignal()) { ++ // There is no point in activating the thread because it is not waiting ++ return false; ++ } ++ if (lockWaitingFor != null && !lockWaitingFor.isLocked()) { ++ // Activating the thread would be useful because there is a lock that can be acquired ++ return true; ++ } ++ if (thread.canStartYieldingTasks) { ++ // Activating the thread would be useful because it can start yielding tasks ++ return true; ++ } ++ if (isServerThread) { ++ // The server thread can be activated whenever there are any non-yielding tasks ++ for (TaskSpan span : TaskSpan.NON_YIELDING_VALUES) { ++ if (thereMayBeTasks[BaseTaskQueueTier.SERVER.ordinal][span.ordinal].get() > 0) { ++ return true; ++ } ++ } ++ } ++ /* ++ There is no point in activating this thread (for anything that the thread could do, ++ it would be better to activate a different or newly instantiated thread). ++ */ ++ return false; ++ } ++ ++ /** + * Activates threads as necessary, and computes whether threads must de-activate themselves when they can. + *
+ * This method is called from {@link #callForUpdate()} if necessary. @@ -6063,17 +6139,9 @@ index 0000000000000000000000000000000000000000..a22b63a15fcc737494454c0d91c35eef + for (int threadI = tryThreadsStart; threadI < tryThreadsEnd; threadI++) { + BaseThread thread = threads[threadI]; + if (thread != null) { -+ /* -+ Note that we only activate threads that can start yielding tasks -+ (it seems wasteful to take the effort to activate threads that can not). -+ or threads that are waiting for a lock that is not currently locked. -+ Note that for the server thread, if it cannot start yielding tasks, -+ there is never an alternative thread that can, so we also allow it, -+ as a special case. -+ */ + @Nullable YieldingLock lockWaitingFor = thread.lockWaitingFor; -+ if (thread.isWaitingAndNeedsSignal() && (tierI == 0 || (lockWaitingFor != null && !lockWaitingFor.isLocked()) || thread.canStartYieldingTasks)) { -+ /* ++ if (couldBeUsefullyActivatedForTasksOrLock(thread, lockWaitingFor, tierI == 0)) { ++ /* + Tasks of a certain tier may yield to tasks of the same or a higher + tier, and they may also yield to tiny tasks of a lower tier. + We do not want to wake up a thread just for tiny tasks @@ -6122,7 +6190,7 @@ index 0000000000000000000000000000000000000000..a22b63a15fcc737494454c0d91c35eef + // Check if the thread still seems valid and attempt to activate it + BaseThread thread = threads[threadIToUpdate]; + @Nullable YieldingLock lockWaitingFor = thread.lockWaitingFor; -+ if (thread.isWaitingAndNeedsSignal() && (tierI == 0 || (lockWaitingFor != null && !lockWaitingFor.isLocked()) || thread.canStartYieldingTasks)) { ++ if (couldBeUsefullyActivatedForTasksOrLock(thread, lockWaitingFor, tierI == 0)) { + // Wake up the thread + if (thread.signal(thereAreTasks ? SignalReason.TASK : SignalReason.YIELDING_LOCK)) { + // Do another update diff --git a/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch b/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch index 216b3e5..dd90a7b 100644 --- a/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch +++ b/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch @@ -27,10 +27,10 @@ index 4b8da38db72d7ebc2d498ec3d711d3b30911096c..80f9e70d5c4330e079feccc9a4b1b595 1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ac12cabaf15bc3520ff74d09faa48a135c63f23c..0019e5eefc4b638526a75dd3706a54033dd9b811 100644 +index fe2892e20dcb0b76d30b81bca7a13e29a1c45723..313d45dae086ac7c1bd0dd71540020c18a9e5d86 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1080,9 +1080,6 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1081,9 +1081,6 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop MinecraftServer.LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), ioexception1); } // Spigot start @@ -40,7 +40,7 @@ index ac12cabaf15bc3520ff74d09faa48a135c63f23c..0019e5eefc4b638526a75dd3706a5403 if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { MinecraftServer.LOGGER.info("Saving usercache.json"); this.getProfileCache().save(false); // Paper -@@ -1092,6 +1089,12 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1093,6 +1090,12 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop LOGGER.info("Flushing Chunk IO"); io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system LOGGER.info("Closing Thread Pool"); @@ -54,10 +54,10 @@ index ac12cabaf15bc3520ff74d09faa48a135c63f23c..0019e5eefc4b638526a75dd3706a5403 LOGGER.info("Closing Server"); try { diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -index e4a0b3085cb22f25246010c43919129283a3b872..52c413990fd8aaca72e371c3bc8f1f145a172abc 100644 +index 7e24854f1e727e5e40108c68933466d0845bdca1..fb185e7f6344f21ed861e56c137ce470e891e766 100644 --- a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java +++ b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -@@ -73,7 +73,9 @@ public enum BaseTaskQueueTier { +@@ -75,7 +75,9 @@ public enum BaseTaskQueueTier { * asynchronously with respect to the {@link ServerThread} and the ticking of the server. * Execution of */ diff --git a/patches/server/0157-Run-cleaner-tasks-on-base-thread-pool.patch b/patches/server/0157-Run-cleaner-tasks-on-base-thread-pool.patch index 9a51203..c63a1e8 100644 --- a/patches/server/0157-Run-cleaner-tasks-on-base-thread-pool.patch +++ b/patches/server/0157-Run-cleaner-tasks-on-base-thread-pool.patch @@ -77,10 +77,10 @@ index 80f9e70d5c4330e079feccc9a4b1b5957c79ef45..e4955e8d04735b74007aae0bf3230281 public static final long INVALID_CHUNK_KEY = getCoordinateKey(Integer.MAX_VALUE, Integer.MAX_VALUE); diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -index 52c413990fd8aaca72e371c3bc8f1f145a172abc..85f467b3cedef57b6b51f04eb34316d43e192d87 100644 +index fb185e7f6344f21ed861e56c137ce470e891e766..f4adcdcad96b2748c60aecb8f5c25370ee6e8f5b 100644 --- a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java +++ b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -@@ -74,6 +74,8 @@ public enum BaseTaskQueueTier { +@@ -76,6 +76,8 @@ public enum BaseTaskQueueTier { * Execution of */ ASYNC(new AbstractTaskQueue[]{ diff --git a/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch b/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch index b21b25b..9cb2be8 100644 --- a/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch +++ b/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch @@ -7,7 +7,7 @@ License: AGPL-3.0 (https://www.gnu.org/licenses/agpl-3.0.html) Gale - https://galemc.org diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..2a0cbe5146eb444a8cb7ab4960904143af4456a7 100644 +index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..f1aaf1cae3335f7c7340104cfd6dbc3dd62f6ab3 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -11,7 +11,6 @@ import java.util.Collections; @@ -44,16 +44,26 @@ index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..2a0cbe5146eb444a8cb7ab4960904143 } else { completablefuture = CompletableFuture.supplyAsync(() -> { return this.getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create); -@@ -973,6 +973,8 @@ public class ServerChunkCache extends ChunkSource { +@@ -973,6 +973,18 @@ public class ServerChunkCache extends ChunkSource { public final class MainThreadExecutor extends BlockableEventLoop { -+ private @Nullable YieldingLock yieldingLockToNotifyOnNewTasks = null; // Gale - base thread pool ++ // Gale start - base thread pool ++ private static volatile boolean chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield; ++ public static @Nullable YieldingLock yieldingLockToNotifyForNewChunkCacheTasks; ++ ++ public static void notifyOfCompletedChunkWorkerTasks() { ++ if (yieldingLockToNotifyForNewChunkCacheTasks != null) { ++ chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield = true; ++ yieldingLockToNotifyForNewChunkCacheTasks.unlock(); ++ } ++ } ++ // Gale end - base thread pool + MainThreadExecutor(Level world) { super("Chunk source main thread executor for " + world.dimension().location()); } -@@ -1002,6 +1004,39 @@ public class ServerChunkCache extends ChunkSource { +@@ -1002,6 +1014,40 @@ public class ServerChunkCache extends ChunkSource { super.doRunTask(task); } @@ -63,8 +73,8 @@ index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..2a0cbe5146eb444a8cb7ab4960904143 + super.tell(runnable); + MinecraftServer.nextTimeAssumeWeMayHaveDelayedTasks = true; + BaseTaskQueues.allLevelsScheduledChunkCache.newTaskWasAdded(); -+ if (this.yieldingLockToNotifyOnNewTasks != null) { -+ this.yieldingLockToNotifyOnNewTasks.unlock(); ++ if (yieldingLockToNotifyForNewChunkCacheTasks != null) { ++ yieldingLockToNotifyForNewChunkCacheTasks.unlock(); + } + } + @@ -79,10 +89,11 @@ index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..2a0cbe5146eb444a8cb7ab4960904143 + var currentThread = AbstractYieldingThread.currentYieldingThread(); + while (!future.isDone()) { + if (!this.pollTask()) { -+ currentThread.yieldUntilFuture(this::hasPendingTasks, future, autoCompletingLock -> this.yieldingLockToNotifyOnNewTasks = autoCompletingLock); ++ currentThread.yieldUntilFuture(() -> this.hasPendingTasks() || chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield, future, autoCompletingLock -> yieldingLockToNotifyForNewChunkCacheTasks = autoCompletingLock); ++ chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield = false; + } + } -+ this.yieldingLockToNotifyOnNewTasks = null; ++ yieldingLockToNotifyForNewChunkCacheTasks = null; + } finally { + --this.blockingCount; + } @@ -121,7 +132,7 @@ index 949feba1264bcafb8dc2dcecd0a566fea80a2ba0..9eae3862abb5f1d7755a8e777fd4bf9a } diff --git a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledChunkCacheTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledChunkCacheTaskQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..60a3b6e935fcea6cf27c31e2b967bf3758283274 +index 0000000000000000000000000000000000000000..fe2e06a827555d81a30697f8b08667692a3eeade --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledChunkCacheTaskQueue.java @@ -0,0 +1,52 @@ @@ -154,7 +165,7 @@ index 0000000000000000000000000000000000000000..60a3b6e935fcea6cf27c31e2b967bf37 +public final class AllLevelsScheduledChunkCacheTaskQueue extends AllLevelsScheduledTaskQueue { + + AllLevelsScheduledChunkCacheTaskQueue() { -+ super(TaskSpan.FREE, false); // TODO Gale could be TINY maybe? Should check the type of tasks scheduled ++ super(TaskSpan.YIELDING, false); + } + + @Override @@ -178,7 +189,7 @@ index 0000000000000000000000000000000000000000..60a3b6e935fcea6cf27c31e2b967bf37 + +} diff --git a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java -index 2eb121798b2feb2a5ce5ebb60316660dbff87de3..c9ded5f30e5465c8e15719ac785797cf476474f1 100644 +index 657c3663ed54043e7e4e6660d34903ef746fd8e7..c2acd36b3101042f39afe1436836078dcce2100d 100644 --- a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java +++ b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java @@ -12,7 +12,8 @@ import org.galemc.gale.executor.thread.pool.BaseThreadActivation; @@ -192,10 +203,10 @@ index 2eb121798b2feb2a5ce5ebb60316660dbff87de3..c9ded5f30e5465c8e15719ac785797cf * All tasks provided by this queue must be yield-free. * diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -index 85f467b3cedef57b6b51f04eb34316d43e192d87..152d3c9805365ff157e484e644b982febdcb6693 100644 +index f4adcdcad96b2748c60aecb8f5c25370ee6e8f5b..8465ce8de44d823aac4784fbc5183b9fc49b2825 100644 --- a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java +++ b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -@@ -59,7 +59,8 @@ public enum BaseTaskQueueTier { +@@ -61,7 +61,8 @@ public enum BaseTaskQueueTier { SERVER(new AbstractTaskQueue[]{ BaseTaskQueues.deferredToServerThread, BaseTaskQueues.serverThreadTick, diff --git a/patches/server/0159-Run-TickThread-chunk-tasks-on-base-thread-pool.patch b/patches/server/0159-Run-TickThread-chunk-tasks-on-base-thread-pool.patch index 780f331..ed412bf 100644 --- a/patches/server/0159-Run-TickThread-chunk-tasks-on-base-thread-pool.patch +++ b/patches/server/0159-Run-TickThread-chunk-tasks-on-base-thread-pool.patch @@ -83,7 +83,7 @@ index 84cc9397237fa0c17aa1012dfb5683c90eb6d3b8..f5c15d40094c2ddc6220b0595597d121 final ReentrantLock schedulingLock = new ReentrantLock(); public final ChunkHolderManager chunkHolderManager; diff --git a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java -index c9ded5f30e5465c8e15719ac785797cf476474f1..2d5a6d60d87b34d03d2d8bbda6d92fddec86924a 100644 +index c2acd36b3101042f39afe1436836078dcce2100d..36b844cfe3a3877496931ec739f6d5af84f32748 100644 --- a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java +++ b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTaskQueue.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable; @@ -97,7 +97,7 @@ index c9ded5f30e5465c8e15719ac785797cf476474f1..2d5a6d60d87b34d03d2d8bbda6d92fdd * diff --git a/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTickThreadChunkTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTickThreadChunkTaskQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..117797c4ac2a81218e9f3e977467b62a18e8136f +index 0000000000000000000000000000000000000000..0e893e7fca1ae3831c3de3a8966e086616e1003c --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/AllLevelsScheduledTickThreadChunkTaskQueue.java @@ -0,0 +1,54 @@ @@ -132,7 +132,7 @@ index 0000000000000000000000000000000000000000..117797c4ac2a81218e9f3e977467b62a +public final class AllLevelsScheduledTickThreadChunkTaskQueue extends AllLevelsScheduledTaskQueue { + + AllLevelsScheduledTickThreadChunkTaskQueue() { -+ super(TaskSpan.FREE, true); // TODO Gale could be TINY maybe? But probably not? Should check the type of tasks scheduled ++ super(TaskSpan.YIELDING, true); + } + + @Override @@ -156,10 +156,10 @@ index 0000000000000000000000000000000000000000..117797c4ac2a81218e9f3e977467b62a + +} diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -index 152d3c9805365ff157e484e644b982febdcb6693..303bdcf41c7836c35bbe0fe00e0d14b5472df072 100644 +index 8465ce8de44d823aac4784fbc5183b9fc49b2825..0035d638667c6e0707ecf3e3c040f0123f8e68d5 100644 --- a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java +++ b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -@@ -60,7 +60,8 @@ public enum BaseTaskQueueTier { +@@ -62,7 +62,8 @@ public enum BaseTaskQueueTier { BaseTaskQueues.deferredToServerThread, BaseTaskQueues.serverThreadTick, BaseTaskQueues.anyTickScheduledServerThread, diff --git a/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch b/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch index ee253ee..1156455 100644 --- a/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch +++ b/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch @@ -480,10 +480,10 @@ index f5c15d40094c2ddc6220b0595597d12103fcf425..79ef41d2bb30beee2355d1de3dc99c9e } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0019e5eefc4b638526a75dd3706a54033dd9b811..7ed820d2483bf6741a355b062f062a04866ba938 100644 +index 313d45dae086ac7c1bd0dd71540020c18a9e5d86..c14b593bd450d244209d17b637fe7c03a1f746f4 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1069,6 +1069,10 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1070,6 +1070,10 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop } } @@ -507,10 +507,10 @@ index abdec5529763b77126494ae0c2be9b48de900bc1..35233587de14cf52da30324df89d9ec7 * This class is a copy of {@link PrioritisedQueueExecutorThread}, with the notable difference * that it does not extend {@link Thread}, but may be instantiated on its own, as an agent representing diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -index 303bdcf41c7836c35bbe0fe00e0d14b5472df072..e9b9d016309e8fac445b223b4412c479a5aca0e8 100644 +index 0035d638667c6e0707ecf3e3c040f0123f8e68d5..afd25cb20200baea7c62cf6b3081e19e4188997a 100644 --- a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java +++ b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java -@@ -73,7 +73,6 @@ public enum BaseTaskQueueTier { +@@ -75,7 +75,6 @@ public enum BaseTaskQueueTier { /** * A tier for queues that contain general tasks that must be performed at some point in time, * asynchronously with respect to the {@link ServerThread} and the ticking of the server. @@ -518,7 +518,7 @@ index 303bdcf41c7836c35bbe0fe00e0d14b5472df072..e9b9d016309e8fac445b223b4412c479 */ ASYNC(new AbstractTaskQueue[]{ // The cleaner queue has high priority because it releases resources back to a pool, thereby saving memory -@@ -84,7 +83,9 @@ public enum BaseTaskQueueTier { +@@ -86,7 +85,9 @@ public enum BaseTaskQueueTier { * A tier for queues that contain tasks with the same considerations as {@link #ASYNC}, * but with a low priority. */ @@ -545,16 +545,17 @@ index ed3ccf2e64539363a7be2d507c68c40b5913f75c..a12250e5aaed02995b7bf09a8018a93f } diff --git a/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..6f78603c87517bb681ae473d0c72b75e23db6689 +index 0000000000000000000000000000000000000000..221f9e6f10c56c92e00fc8f41e09a977a7ed9e76 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java -@@ -0,0 +1,102 @@ +@@ -0,0 +1,106 @@ +// Gale - base thread pool - chunk worker task queue + +package org.galemc.gale.executor.queue; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedQueueExecutorThread; +import io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler; ++import net.minecraft.server.level.ServerChunkCache; +import org.galemc.gale.executor.TaskSpan; +import org.galemc.gale.executor.annotation.YieldFree; +import org.galemc.gale.executor.annotation.thread.AnyThreadSafe; @@ -620,8 +621,11 @@ index 0000000000000000000000000000000000000000..6f78603c87517bb681ae473d0c72b75e + return () -> { + var workerAgent = currentThread.getChunkWorkerAgent(); + ChunkTaskScheduler.workerThreads.activeThreads.add(workerAgent); -+ workerAgent.pollTasks(); ++ boolean performedTasks = workerAgent.pollTasks(); + ChunkTaskScheduler.workerThreads.activeThreads.remove(workerAgent); ++ if (performedTasks) { ++ ServerChunkCache.MainThreadExecutor.notifyOfCompletedChunkWorkerTasks(); ++ } + }; + } + diff --git a/patches/server/0162-Split-tick-steps.patch b/patches/server/0162-Split-tick-steps.patch index 9ff1cda..4467f4f 100644 --- a/patches/server/0162-Split-tick-steps.patch +++ b/patches/server/0162-Split-tick-steps.patch @@ -7,18 +7,18 @@ License: AGPL-3.0 (https://www.gnu.org/licenses/agpl-3.0.html) Gale - https://galemc.org diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7ed820d2483bf6741a355b062f062a04866ba938..575f8ba79cf3547b837abb5957fed0aa29e1d0cf 100644 +index c14b593bd450d244209d17b637fe7c03a1f746f4..88f65137337cd5dcec80c09b80595270fec17eb3 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -154,7 +154,6 @@ import org.galemc.gale.executor.annotation.thread.OriginalServerThreadOnly; - import org.galemc.gale.executor.queue.BaseTaskQueues; +@@ -155,7 +155,6 @@ import org.galemc.gale.executor.queue.BaseTaskQueues; import org.galemc.gale.executor.queue.ScheduledServerThreadTaskQueues; + import org.galemc.gale.executor.thread.BaseThread; import org.galemc.gale.executor.thread.OriginalServerThread; -import org.galemc.gale.executor.thread.SignalReason; import org.galemc.gale.executor.thread.pool.BaseThreadActivation; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; -@@ -1576,15 +1575,53 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1577,15 +1576,53 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTimingFullServerTick(); // Paper // Gale - final timings calls } @@ -73,7 +73,7 @@ index 7ed820d2483bf6741a355b062f062a04866ba938..575f8ba79cf3547b837abb5957fed0aa // CraftBukkit start // Run tasks that are waiting on processing MinecraftTimings.processQueueTimer.startTiming(); // Spigot -@@ -1592,11 +1629,14 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1593,11 +1630,14 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop this.processQueue.remove().run(); } MinecraftTimings.processQueueTimer.stopTiming(); // Spigot @@ -89,7 +89,7 @@ index 7ed820d2483bf6741a355b062f062a04866ba938..575f8ba79cf3547b837abb5957fed0aa final boolean doDaylight = world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT); final long dayTime = world.getDayTime(); long worldTime = world.getGameTime(); -@@ -1611,15 +1651,23 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1612,15 +1652,23 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop new ClientboundSetTimePacket(worldTime, playerTime, doDaylight); entityplayer.connection.send(packet); // Add support for per player time } @@ -115,7 +115,7 @@ index 7ed820d2483bf6741a355b062f062a04866ba938..575f8ba79cf3547b837abb5957fed0aa /* Drop global time updates if (this.tickCount % 20 == 0) { -@@ -1629,16 +1677,28 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1630,16 +1678,28 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop } // CraftBukkit end */ @@ -149,7 +149,7 @@ index 7ed820d2483bf6741a355b062f062a04866ba938..575f8ba79cf3547b837abb5957fed0aa // Spigot Start CrashReport crashreport; try { -@@ -1651,22 +1711,47 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop +@@ -1652,22 +1712,47 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop worldserver.fillReportDetails(crashreport); throw new ReportedException(crashreport); @@ -200,7 +200,7 @@ index 7ed820d2483bf6741a355b062f062a04866ba938..575f8ba79cf3547b837abb5957fed0aa for (int i = 0; i < this.tickables.size(); ++i) { ((Runnable) this.tickables.get(i)).run(); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 2a0cbe5146eb444a8cb7ab4960904143af4456a7..aa49a3d3827128c7d4c7b424211f80abd7e2ff80 100644 +index f1aaf1cae3335f7c7340104cfd6dbc3dd62f6ab3..1d50e234955ae22f7ba32006757af3e78310ab8b 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -630,23 +630,99 @@ public class ServerChunkCache extends ChunkSource {