diff --git a/Spigot-Server-Patches/0529-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/Spigot-Server-Patches/0529-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch index f6753d021b..9d0acfe24e 100644 --- a/Spigot-Server-Patches/0529-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch +++ b/Spigot-Server-Patches/0529-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch @@ -337,6 +337,32 @@ index 07a6fc3d88e7d44bfab7f3d6a0eef7dc132ab422..d60f659b368500e3a8c3305f99e60ffc for (int i = 0; i < this.inventory.getSize(); ++i) { ItemStack itemstack = this.inventory.getItem(i); +diff --git a/src/main/java/net/minecraft/server/LightEngineThreaded.java b/src/main/java/net/minecraft/server/LightEngineThreaded.java +index 8776799de033f02b0f87e9ea7e4a4ce912e94dd4..402f305c8bd3de1d9b288dcc91a1a70324f37fed 100644 +--- a/src/main/java/net/minecraft/server/LightEngineThreaded.java ++++ b/src/main/java/net/minecraft/server/LightEngineThreaded.java +@@ -134,7 +134,11 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { + ChunkCoordIntPair chunkcoordintpair = ichunkaccess.getPos(); + + ichunkaccess.b(false); +- this.a(chunkcoordintpair.x, chunkcoordintpair.z, LightEngineThreaded.Update.PRE_UPDATE, SystemUtils.a(() -> { ++ // Paper start ++ IntSupplier defSupplier = this.d.c(chunkcoordintpair.pair()); ++ IntSupplier priority = () -> Math.max(defSupplier.getAsInt() - (flag ? 2 : 0), 1); ++ // Paper end ++ this.a(chunkcoordintpair.x, chunkcoordintpair.z, priority, LightEngineThreaded.Update.PRE_UPDATE, SystemUtils.a(() -> { // Paper - boost light priority + ChunkSection[] achunksection = ichunkaccess.getSections(); + + for (int i = 0; i < 16; ++i) { +@@ -161,7 +165,7 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { + super.b(chunkcoordintpair, false); + return ichunkaccess; + }, (runnable) -> { +- this.a(chunkcoordintpair.x, chunkcoordintpair.z, LightEngineThreaded.Update.POST_UPDATE, runnable); ++ this.a(chunkcoordintpair.x, chunkcoordintpair.z, priority, LightEngineThreaded.Update.POST_UPDATE, runnable); // Paper - boost light priority + }); + } + diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java index 0d1065688b19ceca9440bc8bf2bf65910f03fa46..8a349964578e07e5ed13f801c57de68459220da9 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java diff --git a/Spigot-Server-Patches/0533-Improve-Chunk-Status-Transition-Speed.patch b/Spigot-Server-Patches/0533-Improve-Chunk-Status-Transition-Speed.patch new file mode 100644 index 0000000000..0624abdd9a --- /dev/null +++ b/Spigot-Server-Patches/0533-Improve-Chunk-Status-Transition-Speed.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 29 May 2020 23:32:14 -0400 +Subject: [PATCH] Improve Chunk Status Transition Speed + +When a chunk is loaded from disk that has already been generated, +the server has to promote the chunk through the system to reach +it's current desired status level. + +This results in every single status transition going from the main thread +to the world gen threads, only to discover it has no work it actually +needs to do.... and then it returns back to main. + +This back and forth costs a lot of time and can really delay chunk loads +when the server is under high TPS due to their being a lot of time in +between chunk load times, as well as hogs up the chunk threads from doing +actual generation and light work. + +Additionally, the whole task system uses a lot of CPU on the server threads anyways. + +So by optimizing status transitions for status's that are already complete, +we can run them to the desired level while on main thread (where it has +to happen anyways) instead of ever jumping to world gen thread. + +This will improve chunk loading effeciency to be reduced down to the following +scenario / path: + +1) MAIN: Chunk Requested, Load Request sent to ChunkTaskManager / IO Queue +2) IO: Once position in queue comes, submit read IO data and schedule to chunk task thread +3) CHUNK: Once IO is loaded and position in queue comes, deserialize the chunk data, process conversions, submit to main queue +4) MAIN: next Chunk Task process (Mid Tick or End Of Tick), load chunk data into world (POI, main thread tasks) +5) MAIN: process status transitions all the way to LIGHT, light schedules Threaded task +6) SERVER: Light tasks register light enablement for chunk and any lighting needing to be done +7) MAIN: Task returns to main, finish processing to FULL/TICKING status + +Previously would have hopped to SERVER around 12+ times there extra. + +diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java +index b8fe42e8123e972b1ec97b048c35d90118076e66..a924abd32c4e0fc3bb9b97f634185264aa1d1093 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunk.java ++++ b/src/main/java/net/minecraft/server/PlayerChunk.java +@@ -56,6 +56,13 @@ public class PlayerChunk { + this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); + } + // Paper end - optimise isOutsideOfRange ++ // Paper start - optimize chunk status progression without jumping through thread pool ++ public boolean canAdvanceStatus() { ++ ChunkStatus status = getChunkHolderStatus(); ++ IChunkAccess chunk = getAvailableChunkNow(); ++ return chunk != null && (status == null || chunk.getChunkStatus().isAtLeastStatus(getNextStatus(status))); ++ } ++ // Paper end + + // Paper start - no-tick view distance + public final Chunk getSendingChunk() { +diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java +index f42507f5a17f9388db738218f58ca76f863274ff..d35b0b3a9548db6b6b651a7a1d824f2418b7732f 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -88,6 +88,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + public final WorldServer world; + private final LightEngineThreaded lightEngine; + private final IAsyncTaskHandler executor; ++ final java.util.concurrent.Executor mainInvokingExecutor; // Paper + public final ChunkGenerator chunkGenerator; + private final Supplier l; public final Supplier getWorldPersistentDataSupplier() { return this.l; } // Paper - OBFHELPER + private final VillagePlace m; +@@ -285,6 +286,15 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + this.world = worldserver; + this.chunkGenerator = chunkgenerator; + this.executor = iasynctaskhandler; ++ // Paper start - optimize chunk status progression without jumping through thread pool ++ this.mainInvokingExecutor = (run) -> { ++ if (MCUtil.isMainThread()) { ++ run.run(); ++ } else { ++ iasynctaskhandler.execute(run); ++ } ++ }; ++ // Paper end + ThreadedMailbox threadedmailbox = ThreadedMailbox.a(executor, "worldgen"); + + iasynctaskhandler.getClass(); +@@ -690,7 +700,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + return either.mapLeft((list) -> { + return (Chunk) list.get(list.size() / 2); + }); +- }, this.executor); ++ }, this.mainInvokingExecutor); // Paper + } + + @Nullable +@@ -1056,7 +1066,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + return this.b(playerchunk, chunkstatus); + } + } +- }, this.executor); ++ }, this.mainInvokingExecutor); // Paper - optimize chunk status progression without jumping through thread pool + } + } + +@@ -1167,6 +1177,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + return CompletableFuture.completedFuture(Either.right(playerchunk_failure)); + }); + }, (runnable) -> { ++ // Paper start - optimize chunk status progression without jumping through thread pool ++ if (playerchunk.canAdvanceStatus()) { ++ this.mainInvokingExecutor.execute(runnable); ++ return; ++ } ++ // Paper end + this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable)); // CraftBukkit - decompile error + }); + }