diff options
Diffstat (limited to 'patches/server/0713-Execute-chunk-tasks-mid-tick.patch')
-rw-r--r-- | patches/server/0713-Execute-chunk-tasks-mid-tick.patch | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/patches/server/0713-Execute-chunk-tasks-mid-tick.patch b/patches/server/0713-Execute-chunk-tasks-mid-tick.patch new file mode 100644 index 0000000000..974b755ba3 --- /dev/null +++ b/patches/server/0713-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 23e564b05ba438924180c91f9b19a60731eedd1b..5ec241d49ff5e3a161a39006f05823a5de847c5e 100644 +--- a/src/main/java/co/aikar/timings/MinecraftTimings.java ++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java +@@ -46,6 +46,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 79c4ee2dd842fcf29eb91a69e536960c814c1a0d..207c1fb92493757de90f1a583a66ae4ad18b0e3f 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1298,6 +1298,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()) { +@@ -2669,4 +2670,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 cfcb3ba96569f3eb24d1035d770c50085f60b772..89ecb5c6c25246d0c71b14cc089386d4c4b83093 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -748,6 +748,7 @@ public class ServerChunkCache extends ChunkSource { + iterator1 = shuffled.iterator(); + } + ++ int chunksTicked = 0; // Paper + try { + while (iterator1.hasNext()) { + LevelChunk chunk1 = iterator1.next(); +@@ -765,6 +766,7 @@ public class ServerChunkCache extends ChunkSource { + + if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - the chunk is known ticking + 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 4fa19370e05600391e60b9b416f343834362cbac..b4b7aa2f7d602fe996ebc320ab9641866b672abe 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -212,6 +212,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + private final StructureManager structureManager; + private final StructureCheck structureCheck; + private final boolean tickTime; ++ public long lastMidTickExecuteFailure; // Paper - execute chunk tasks mid tick + + // CraftBukkit start + public final LevelStorageSource.LevelStorageAccess convertable; +@@ -1024,6 +1025,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 + + } + +@@ -1033,6 +1035,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 e30414e1a5e7907c59917c5cd182bca65bc65825..4a3cfc66fdbff749f098a384c16a2c7cfc72e294 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -804,6 +804,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); +@@ -818,6 +823,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 |