mirror of https://github.com/YatopiaMC/Yatopia.git
344 lines
17 KiB
Diff
344 lines
17 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
|
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/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
|
|
index 4666d6582535d6e49c5bd40d4fcdcdfe07590aa9..b870cca05f0ba354e6976a70511235636093d13c 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
|
|
@@ -310,6 +310,7 @@ public final class PaperTickList<T> extends TickListServer<T> { // extend to avo
|
|
if (toTick.tickState == STATE_TICKING) {
|
|
toTick.tickState = STATE_TICKED;
|
|
} // else it's STATE_CANCELLED_TICK
|
|
+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - exec chunk tasks during world tick
|
|
} else {
|
|
// re-schedule eventually
|
|
toTick.tickState = STATE_SCHEDULED;
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 419d17d0eb9426e4f3f9f97a504e567401d175f3..dae8824a6034cdaaecbedeba5e05c62f4565583f 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -1115,7 +1115,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
// Paper end
|
|
tickSection = curTime;
|
|
}
|
|
- midTickChunksTasksRan = 0; // Paper
|
|
+ // Tuinity - replace logic
|
|
// Spigot end
|
|
|
|
//MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
|
|
@@ -1208,6 +1208,76 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
}
|
|
// Paper end
|
|
|
|
+ // Tuinity 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 (WorldServer world : this.getWorlds()) {
|
|
+ long currTime = System.nanoTime();
|
|
+ if (currTime - world.lastMidTickExecuteFailure <= TASK_EXECUTION_FAILURE_BACKOFF) {
|
|
+ continue;
|
|
+ }
|
|
+ if (!world.getChunkProvider().runTasks()) {
|
|
+ // 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();
|
|
+ }
|
|
+ }
|
|
+ // Tuinity end - execute chunk tasks mid tick
|
|
+
|
|
private void executeModerately() {
|
|
this.executeAll();
|
|
java.util.concurrent.locks.LockSupport.parkNanos("executing tasks", 1000L);
|
|
@@ -1221,22 +1291,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
});
|
|
}
|
|
|
|
- // Paper start
|
|
- public int midTickChunksTasksRan = 0;
|
|
- private long midTickLastRan = 0;
|
|
- public void midTickLoadChunks() {
|
|
- if (!isMainThread() || System.nanoTime() - midTickLastRan < 1000000) {
|
|
- // only check once per 0.25ms incase this code is called in a hot method
|
|
- return;
|
|
- }
|
|
- try (co.aikar.timings.Timing ignored = co.aikar.timings.MinecraftTimings.midTickChunkTasks.startTiming()) {
|
|
- for (WorldServer value : this.getWorlds()) {
|
|
- value.getChunkProvider().serverThreadQueue.midTickLoadChunks();
|
|
- }
|
|
- midTickLastRan = System.nanoTime();
|
|
- }
|
|
- }
|
|
- // Paper end
|
|
+ // Tuinity - replace logic
|
|
|
|
@Override
|
|
public TickTask postToMainThread(Runnable runnable) {
|
|
@@ -1263,6 +1318,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
|
|
private boolean bb() {
|
|
if (super.executeNext()) {
|
|
+ this.executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick
|
|
return true;
|
|
} else {
|
|
if (this.canSleepForTick()) {
|
|
@@ -1330,7 +1386,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
// Paper start - move oversleep into full server tick
|
|
isOversleep = true;MinecraftTimings.serverOversleep.startTiming();
|
|
this.awaitTasks(() -> {
|
|
- midTickLoadChunks(); // will only do loads since we are still considered !canSleepForTick
|
|
+ // Tuinity - replace logic
|
|
return !this.canOversleep();
|
|
});
|
|
isOversleep = false;MinecraftTimings.serverOversleep.stopTiming();
|
|
@@ -1421,16 +1477,16 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
}
|
|
|
|
protected void b(BooleanSupplier booleansupplier) {
|
|
- midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper
|
|
this.server.getScheduler().mainThreadHeartbeat(this.ticks); // CraftBukkit
|
|
MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper
|
|
- midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
this.methodProfiler.enter("commandFunctions");
|
|
MinecraftTimings.commandFunctionsTimer.startTiming(); // Spigot // Paper
|
|
this.getFunctionData().tick();
|
|
MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper
|
|
- midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
this.methodProfiler.exitEnter("levels");
|
|
Iterator iterator = this.getWorlds().iterator();
|
|
|
|
@@ -1441,7 +1497,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
processQueue.remove().run();
|
|
}
|
|
MinecraftTimings.processQueueTimer.stopTiming(); // Spigot
|
|
- midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper
|
|
// Send time updates to everyone, it will get the right time from the world the player is in.
|
|
// Paper start - optimize time updates
|
|
@@ -1484,7 +1540,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
this.methodProfiler.enter("tick");
|
|
|
|
try {
|
|
- midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
worldserver.timings.doTick.startTiming(); // Spigot
|
|
worldserver.doTick(booleansupplier);
|
|
// Tuinity start
|
|
@@ -1493,7 +1549,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
}
|
|
// Tuinity end
|
|
worldserver.timings.doTick.stopTiming(); // Spigot
|
|
- midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
} catch (Throwable throwable) {
|
|
// Spigot Start
|
|
CrashReport crashreport;
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
|
|
index c5038aa66703484a9243579ba4a6c92d138fc388..e38e507ccc26058b4f4d2e8fe061188525e7ac92 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
|
|
@@ -918,7 +918,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
this.world.getMethodProfiler().enter("purge");
|
|
this.world.timings.doChunkMap.startTiming(); // Spigot
|
|
this.chunkMapDistance.purgeTickets();
|
|
- this.world.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
this.tickDistanceManager();
|
|
this.world.timings.doChunkMap.stopTiming(); // Spigot
|
|
this.world.getMethodProfiler().exitEnter("chunks");
|
|
@@ -928,7 +928,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
this.world.timings.doChunkUnload.startTiming(); // Spigot
|
|
this.world.getMethodProfiler().exitEnter("unload");
|
|
this.playerChunkMap.unloadChunks(booleansupplier);
|
|
- this.world.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
this.world.timings.doChunkUnload.stopTiming(); // Spigot
|
|
this.world.getMethodProfiler().exit();
|
|
this.clearCache();
|
|
@@ -1000,6 +1000,8 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
// Paper end
|
|
this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings
|
|
|
|
+ int ticked = 0; // Tuinity - exec chunk tasks during world tick
|
|
+
|
|
this.p = spawnercreature_d;
|
|
this.world.getMethodProfiler().exit();
|
|
//List<PlayerChunk> list = Lists.newArrayList(this.playerChunkMap.f()); // Paper
|
|
@@ -1029,7 +1031,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
this.world.timings.chunkTicks.startTiming(); // Spigot // Paper
|
|
this.world.a(chunk, k);
|
|
this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper
|
|
- if (chunksTicked[0]++ % 10 == 0) this.world.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ if ((++ticked & 1) == 0) MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - exec chunk tasks during world tick
|
|
}
|
|
}
|
|
}
|
|
@@ -1185,41 +1187,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
ChunkProviderServer.this.world.getMethodProfiler().c("runTask");
|
|
super.executeTask(runnable);
|
|
}
|
|
-
|
|
- // Paper start
|
|
- private long lastMidTickChunkTask = 0;
|
|
- public boolean pollChunkLoadTasks() {
|
|
- if (com.destroystokyo.paper.io.chunk.ChunkTaskManager.pollChunkWaitQueue() || ChunkProviderServer.this.world.asyncChunkTaskManager.pollNextChunkTask()) {
|
|
- try {
|
|
- ChunkProviderServer.this.tickDistanceManager();
|
|
- } finally {
|
|
- // from below: process pending Chunk loadCallback() and unloadCallback() after each run task
|
|
- playerChunkMap.callbackExecutor.run();
|
|
- }
|
|
- return true;
|
|
- }
|
|
- return false;
|
|
- }
|
|
- public void midTickLoadChunks() {
|
|
- MinecraftServer server = ChunkProviderServer.this.world.getMinecraftServer();
|
|
- // always try to load chunks, restrain generation/other updates only. don't count these towards tick count
|
|
- //noinspection StatementWithEmptyBody
|
|
- while (pollChunkLoadTasks()) {}
|
|
-
|
|
- if (System.nanoTime() - lastMidTickChunkTask < 200000) {
|
|
- return;
|
|
- }
|
|
-
|
|
- for (;server.midTickChunksTasksRan < com.destroystokyo.paper.PaperConfig.midTickChunkTasks && server.canSleepForTick();) {
|
|
- if (this.executeNext()) {
|
|
- server.midTickChunksTasksRan++;
|
|
- lastMidTickChunkTask = System.nanoTime();
|
|
- } else {
|
|
- break;
|
|
- }
|
|
- }
|
|
- }
|
|
- // Paper end
|
|
+ // Tuinity - replace logic
|
|
|
|
@Override
|
|
protected boolean executeNext() {
|
|
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
index 25073eb392bb00daf7e0b68be4767cea416c1816..1658c03b70b5984c87d069276efcc7b8c8878431 100644
|
|
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
@@ -410,6 +410,10 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
|
}
|
|
// Tuinity end
|
|
|
|
+ // Tuinity start - execute chunk tasks mid tick
|
|
+ public long lastMidTickExecuteFailure;
|
|
+ // Tuinity end - execute chunk tasks mid tick
|
|
+
|
|
// Add env and gen to constructor, WorldData -> WorldDataServer
|
|
public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey<World> resourcekey, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<MobSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
|
|
super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env, executor); // Paper pass executor
|
|
@@ -674,7 +678,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
|
}
|
|
timings.scheduledBlocks.stopTiming(); // Paper
|
|
|
|
- this.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
gameprofilerfiller.exitEnter("raid");
|
|
this.timings.raids.startTiming(); // Paper - timings
|
|
this.persistentRaid.a();
|
|
@@ -683,7 +687,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
|
timings.doSounds.startTiming(); // Spigot
|
|
this.ak();
|
|
timings.doSounds.stopTiming(); // Spigot
|
|
- this.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
this.ticking = false;
|
|
gameprofilerfiller.exitEnter("entities");
|
|
boolean flag3 = true || !this.players.isEmpty() || !this.getForceLoadedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
|
|
@@ -760,7 +764,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
|
}
|
|
this.afterEntityTickingTasks.clear();
|
|
// Paper end
|
|
- this.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
|
|
Entity entity2;
|
|
|
|
@@ -770,7 +774,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
|
}
|
|
|
|
timings.tickEntities.stopTiming(); // Spigot
|
|
- this.getMinecraftServer().midTickLoadChunks(); // Paper
|
|
+ // Tuinity - replace logic
|
|
this.tickBlockEntities();
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java
|
|
index 74894282575d12f25ba4968abf873d3a346529b7..89d43183cf6c628c124aba486db69336f1e017df 100644
|
|
--- a/src/main/java/net/minecraft/world/level/World.java
|
|
+++ b/src/main/java/net/minecraft/world/level/World.java
|
|
@@ -960,6 +960,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
|
|
return;
|
|
// Paper end
|
|
}
|
|
+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick
|
|
}
|
|
// Paper start - Prevent armor stands from doing entity lookups
|
|
@Override
|