diff options
Diffstat (limited to 'patches/server/0752-Execute-chunk-tasks-mid-tick.patch')
-rw-r--r-- | patches/server/0752-Execute-chunk-tasks-mid-tick.patch | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/patches/server/0752-Execute-chunk-tasks-mid-tick.patch b/patches/server/0752-Execute-chunk-tasks-mid-tick.patch new file mode 100644 index 0000000000..9f14b511e7 --- /dev/null +++ b/patches/server/0752-Execute-chunk-tasks-mid-tick.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +Date: Mon, 6 Apr 2020 04:20:44 -0700 +Subject: [PATCH] Execute chunk tasks mid-tick + +This will help the server load chunks if tick times are high. + +diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java +index b27021a42cbed3f0648a8d0903d00d03922ae221..eada966d7f108a6081be7a848f5c1dfcb1eed676 100644 +--- a/src/main/java/co/aikar/timings/MinecraftTimings.java ++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java +@@ -45,6 +45,8 @@ public final class MinecraftTimings { + public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update"); + public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate"); + ++ public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks"); ++ + private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap(); + + private MinecraftTimings() {} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 088334869cb62797a1e1d1bbb6187f03189d852d..c245c1f4611f7273c8da629f774e0c64e9f98fc2 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -332,6 +332,76 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + return s0; + } + ++ // Paper start - execute chunk tasks mid tick ++ static final long CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME = 25L * 1000L; // 25us ++ static final long MAX_CHUNK_EXEC_TIME = 1000L; // 1us ++ ++ static final long TASK_EXECUTION_FAILURE_BACKOFF = 5L * 1000L; // 5us ++ ++ private static long lastMidTickExecute; ++ private static long lastMidTickExecuteFailure; ++ ++ private boolean tickMidTickTasks() { ++ // give all worlds a fair chance at by targetting them all. ++ // if we execute too many tasks, that's fine - we have logic to correctly handle overuse of allocated time. ++ boolean executed = false; ++ for (ServerLevel world : this.getAllLevels()) { ++ long currTime = System.nanoTime(); ++ if (currTime - world.lastMidTickExecuteFailure <= TASK_EXECUTION_FAILURE_BACKOFF) { ++ continue; ++ } ++ if (!world.getChunkSource().pollTask()) { ++ // we need to back off if this fails ++ world.lastMidTickExecuteFailure = currTime; ++ } else { ++ executed = true; ++ } ++ } ++ ++ return executed; ++ } ++ ++ public final void executeMidTickTasks() { ++ 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) { ++ // it's shown to be bad to constantly hit the queue (chunk loads slow to a crawl), even if no tasks are executed. ++ // so, backoff to prevent this ++ return; ++ } ++ ++ co.aikar.timings.MinecraftTimings.midTickChunkTasks.startTiming(); ++ try { ++ for (;;) { ++ boolean moreTasks = this.tickMidTickTasks(); ++ long currTime = System.nanoTime(); ++ long diff = currTime - startTime; ++ ++ if (!moreTasks || diff >= MAX_CHUNK_EXEC_TIME) { ++ if (!moreTasks) { ++ lastMidTickExecuteFailure = currTime; ++ } ++ ++ // note: negative values reduce the time ++ long overuse = diff - MAX_CHUNK_EXEC_TIME; ++ if (overuse >= (10L * 1000L * 1000L)) { // 10ms ++ // make sure something like a GC or dumb plugin doesn't screw us over... ++ overuse = 10L * 1000L * 1000L; // 10ms ++ } ++ ++ double overuseCount = (double)overuse/(double)MAX_CHUNK_EXEC_TIME; ++ long extraSleep = (long)Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME); ++ ++ lastMidTickExecute = currTime + extraSleep; ++ return; ++ } ++ } ++ } finally { ++ co.aikar.timings.MinecraftTimings.midTickChunkTasks.stopTiming(); ++ } ++ } ++ // Paper end - execute chunk tasks mid tick ++ + public MinecraftServer(OptionSet options, DataPackConfig datapackconfiguration, Thread thread, RegistryAccess.RegistryHolder iregistrycustom_dimension, LevelStorageSource.LevelStorageAccess convertable_conversionsession, WorldData savedata, PackRepository resourcepackrepository, Proxy proxy, DataFixer datafixer, ServerResources datapackresources, @Nullable MinecraftSessionService minecraftsessionservice, @Nullable GameProfileRepository gameprofilerepository, @Nullable GameProfileCache usercache, ChunkProgressListenerFactory worldloadlistenerfactory) { + super("Server"); + SERVER = this; // Paper - better singleton +@@ -1312,6 +1382,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + + private boolean pollTaskInternal() { + if (super.pollTask()) { ++ this.executeMidTickTasks(); // Paper - execute chunk tasks mid tick + return true; + } else { + if (this.haveTime()) { +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index ad352b4b67632f9984c4d10994a9acfe434a4996..df415f79dfd2ae9a709747b112022b38437daac4 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -1023,6 +1023,7 @@ public class ServerChunkCache extends ChunkSource { + iterator1 = shuffled.iterator(); + } + ++ int chunksTicked = 0; // Paper + try { + while (iterator1.hasNext()) { + LevelChunk chunk1 = iterator1.next(); +@@ -1044,6 +1045,7 @@ public class ServerChunkCache extends ChunkSource { + + if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { + this.level.tickChunk(chunk1, k); ++ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper + } + } + // Paper start - optimise chunk tick iteration +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 5e65df1a9a8282c4ffa06801379b79ab0ed1b45c..7e837b2896cac64a982d9025c4e190dfa7ebc451 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -201,7 +201,9 @@ public class ServerLevel extends Level implements WorldGenLevel { + private final StructureFeatureManager structureFeatureManager; + private final StructureCheck structureCheck; + private final boolean tickTime; +- ++ // Paper start - execute chunk tasks mid tick ++ public long lastMidTickExecuteFailure; ++ // Paper end - execute chunk tasks mid tick + + // CraftBukkit start + private int tickPosition; +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 3831895e2219d846022500553d9b714c7d654b3a..86bcedec97f1bc95621380da6ad074bdcc4bfeab 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -896,6 +896,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) { + try { + tickConsumer.accept(entity); ++ MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick + } catch (Throwable throwable) { + if (throwable instanceof ThreadDeath) throw throwable; // Paper + // Paper start - Prevent tile entity and entity crashes |