Mirror von
https://github.com/PaperMC/Paper.git
synchronisiert 2024-11-15 04:20:04 +01:00
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.
Dieser Commit ist enthalten in:
Ursprung
7a2b345b55
Commit
a76bc4029d
@ -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
|
||||
|
114
Spigot-Server-Patches/0533-Improve-Chunk-Status-Transition-Speed.patch
Normale Datei
114
Spigot-Server-Patches/0533-Improve-Chunk-Status-Transition-Speed.patch
Normale Datei
@ -0,0 +1,114 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
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<Runnable> executor;
|
||||
+ final java.util.concurrent.Executor mainInvokingExecutor; // Paper
|
||||
public final ChunkGenerator<?> chunkGenerator;
|
||||
private final Supplier<WorldPersistentData> l; public final Supplier<WorldPersistentData> 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<Runnable> 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
|
||||
});
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren