diff options
Diffstat (limited to 'patches/server/1021-Execute-chunk-tasks-mid-tick.patch')
-rw-r--r-- | patches/server/1021-Execute-chunk-tasks-mid-tick.patch | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/patches/server/1021-Execute-chunk-tasks-mid-tick.patch b/patches/server/1021-Execute-chunk-tasks-mid-tick.patch new file mode 100644 index 0000000000..1a20c77ced --- /dev/null +++ b/patches/server/1021-Execute-chunk-tasks-mid-tick.patch @@ -0,0 +1,176 @@ +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 6b3cde6d4d1e63bec01f502f2027ee9fddac08aa..46449728f69ee7d4f78470f8da23c055acd53a3b 100644 +--- a/src/main/java/co/aikar/timings/MinecraftTimings.java ++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java +@@ -48,6 +48,8 @@ public final class MinecraftTimings { + public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate"); + 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 af558f9f5f094d6aea6ba5e85e9a18740f1c7b76..100cccf92efae2b87be7dff1f21cb5038c823c5a 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1293,8 +1293,79 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + return flag; + } + ++ // 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 ++ + private boolean pollTaskInternal() { + if (super.pollTask()) { ++ this.executeMidTickTasks(); // Paper - execute chunk tasks mid tick + return true; + } else { + boolean ret = false; // Paper - force execution of all worlds, do not just bias the first +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index 4e0f80b26f1a1703184e38d739996b9919699fec..2b33a3d8fdb86024acb2a3ee9d0a4a7dd4989c98 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -568,6 +568,7 @@ public class ServerChunkCache extends ChunkSource { + boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit + Iterator iterator1 = list.iterator(); + ++ int chunksTicked = 0; // Paper + while (iterator1.hasNext()) { + ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next(); + LevelChunk chunk1 = chunkproviderserver_a.chunk; +@@ -581,6 +582,7 @@ public class ServerChunkCache extends ChunkSource { + + if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { + this.level.tickChunk(chunk1, l); ++ 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 f24734f2a38eb5f2dc39f418a1f506a600127a79..3535f86b92c4e61fd84defbbf37e074690a30019 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -216,6 +216,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; +@@ -1205,6 +1206,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 + + } + +@@ -1214,6 +1216,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 c07cfd8fdf056bb613ab5b64a58975d0ed9446ee..e221fe55d6ec5e77a82d33570a2ac1a77c221112 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -929,6 +929,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + // Spigot end + } else if (flag && 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); // Paper - Fix MC-117075 +@@ -943,6 +948,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 block entity and entity crashes |