diff options
Diffstat (limited to 'patches/server/0765-Execute-chunk-tasks-mid-tick.patch')
-rw-r--r-- | patches/server/0765-Execute-chunk-tasks-mid-tick.patch | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/patches/server/0765-Execute-chunk-tasks-mid-tick.patch b/patches/server/0765-Execute-chunk-tasks-mid-tick.patch new file mode 100644 index 0000000000..a1266038ec --- /dev/null +++ b/patches/server/0765-Execute-chunk-tasks-mid-tick.patch @@ -0,0 +1,168 @@ +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/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java +index 5fdaefc128956581be4bb9b34199fd6410563991..b7edc1121797bc1c57e25f540ed0124fa8b36b7a 100644 +--- a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java ++++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java +@@ -312,6 +312,7 @@ public final class PaperTickList<T> extends ServerTickList<T> { // extend to avo + toTick.tickState = STATE_SCHEDULED; + this.addToNotTickingReady(toTick); + } ++ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick + } catch (final Throwable thr) { + // start copy from TickListServer // TODO check on update + CrashReport crashreport = CrashReport.forThrowable(thr, "Exception while ticking"); +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 98eb8318413014f0650dc5c80125aa84b51cfc93..57cb2722e973cfc8edc845bc7154b8b8bbb11e12 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -330,6 +330,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 +@@ -1325,6 +1395,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 d6981bbcf480c5856b51960013d144beba2361b3..39840403da99252c5d634e99e1da19f6066dee7c 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 { + Collections.shuffle(shuffled); + iterator = shuffled.iterator(); + } ++ int chunksTicked = 0; // Paper + try { while (iterator.hasNext()) { + LevelChunk chunk = iterator.next(); + ChunkHolder playerchunk = chunk.playerChunk; +@@ -1045,6 +1046,7 @@ public class ServerChunkCache extends ChunkSource { + this.level.tickChunk(chunk, k); + // this.level.timings.doTickTiles.stopTiming(); // Spigot // Paper + } ++ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper + } + } // Paper start - optimise chunk tick iteration + } finally { +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 5c588c39de11bbabdc2f50ef4204007c622fdc6a..e219e385df356531639cb1b4bf993dca9034aa1d 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -190,7 +190,9 @@ public class ServerLevel extends Level implements WorldGenLevel { + final Int2ObjectMap<EnderDragonPart> dragonParts; + private final StructureFeatureManager structureFeatureManager; + 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 1dd2e968bde16da2d2da63ca3c30515e1fd5b620..3a6f79233cec7aee87be20787b6deae4b313f0ac 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -903,6 +903,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 |