diff options
Diffstat (limited to 'patches/server/0687-Execute-chunk-tasks-mid-tick.patch')
-rw-r--r-- | patches/server/0687-Execute-chunk-tasks-mid-tick.patch | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/patches/server/0687-Execute-chunk-tasks-mid-tick.patch b/patches/server/0687-Execute-chunk-tasks-mid-tick.patch new file mode 100644 index 0000000000..3a0637b6e5 --- /dev/null +++ b/patches/server/0687-Execute-chunk-tasks-mid-tick.patch @@ -0,0 +1,179 @@ +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 678a31fb85947ee8807d02d0fe4e11a73d2dafaa..0fc4feb00940079c4eb9554a3a48d19cbbeeb7bc 100644 +--- a/src/main/java/co/aikar/timings/MinecraftTimings.java ++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java +@@ -49,6 +49,8 @@ public final class MinecraftTimings { + public static final Timing scoreboardScoreSearch = Timings.ofSafe("Scoreboard score search"); // Paper - add timings for scoreboard search + + ++ 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 d74313b58b660f3c03b8a6db4f80b6b073b6b795..f7c1d07c95f7b67e32bd6679af88612aec74f54f 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1285,6 +1285,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()) { +@@ -2704,4 +2705,74 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + } + } + // Paper end ++ ++ // 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 + } +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index 4e58f31e4852a0811f85596653f6db630a75b069..8907396dc21dbfb31ff15286a7daa2110f6e34c0 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -571,6 +571,7 @@ public class ServerChunkCache extends ChunkSource { + // Paper end + Iterator iterator1 = list.iterator(); + ++ int chunksTicked = 0; // Paper + while (iterator1.hasNext()) { + ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next(); + LevelChunk chunk1 = chunkproviderserver_a.chunk; +@@ -584,6 +585,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 + } + } + } +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 48513493d92ea0fe5e2cb4f021c843b10caab062..82867a6d6e2277355269712e9e45602fc7afac45 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -215,6 +215,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + private final StructureCheck structureCheck; + private final boolean tickTime; + private final RandomSequences randomSequences; ++ public long lastMidTickExecuteFailure; // Paper - execute chunk tasks mid tick + + // CraftBukkit start + public final LevelStorageSource.LevelStorageAccess convertable; +@@ -1187,6 +1188,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + if (fluid1.is(fluid)) { + fluid1.tick(this, pos); + } ++ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick + + } + +@@ -1196,6 +1198,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + if (iblockdata.is(block)) { + iblockdata.tick(this, pos, this.random); + } ++ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick + + } + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 6bd9b680fa1e84d058ada2354fa6a5b876185dc4..795be71432c4d834004bcfb70a8d1927cf22bfda 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -918,6 +918,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + // Spigot end + } else if (this.shouldTickBlocksAt(tickingblockentity.getPos())) { + tickingblockentity.tick(); ++ // Paper start - execute chunk tasks during tick ++ if ((this.tileTickPosition & 7) == 0) { ++ MinecraftServer.getServer().executeMidTickTasks(); ++ } ++ // Paper end - execute chunk tasks during tick + } + } + this.blockEntityTickers.removeAll(toRemove); +@@ -932,6 +937,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 |