mirror of
https://hub.spigotmc.org/stash/scm/spigot/spigot.git
synced 2025-08-31 21:49:13 +00:00
177 lines
7.4 KiB
Diff
177 lines
7.4 KiB
Diff
From 2e18115cc5205d7501d3cf894bcdb45f1f398f7f Mon Sep 17 00:00:00 2001
|
|
From: Geoff Crossland <gcrossland+bukkit@gmail.com>
|
|
Date: Thu, 26 Jan 2017 20:54:55 +0000
|
|
Subject: [PATCH] Replace chunk loading / unloading rate throttling.
|
|
|
|
Uses a scheme based on estimated tick slack time.
|
|
See https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/pull-requests/71/overview
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index e6219e027..1db3cbbdd 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -185,6 +185,7 @@ import org.bukkit.event.server.ServerLoadEvent;
|
|
// CraftBukkit end
|
|
|
|
import org.bukkit.craftbukkit.SpigotTimings; // Spigot
|
|
+import org.spigotmc.SlackActivityAccountant; // Spigot
|
|
|
|
public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTask> implements IMojangStatistics, ICommandListener, AutoCloseable {
|
|
|
|
@@ -295,6 +296,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
public static final int TICK_TIME = 1000000000 / TPS;
|
|
private static final int SAMPLE_INTERVAL = 100;
|
|
public final double[] recentTps = new double[ 3 ];
|
|
+ public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant();
|
|
// Spigot end
|
|
|
|
public static <S extends MinecraftServer> S a(Function<Thread, S> function) {
|
|
@@ -1208,6 +1210,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
|
|
public void a(BooleanSupplier booleansupplier) {
|
|
SpigotTimings.serverTickTimer.startTiming(); // Spigot
|
|
+ this.slackActivityAccountant.tickStarted(); // Spigot
|
|
long i = SystemUtils.getMonotonicNanos();
|
|
|
|
++this.tickCount;
|
|
@@ -1256,6 +1259,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
this.frameTimer.a(i1 - i);
|
|
this.profiler.exit();
|
|
org.spigotmc.WatchdogThread.tick(); // Spigot
|
|
+ this.slackActivityAccountant.tickEnded(l); // Spigot
|
|
SpigotTimings.serverTickTimer.stopTiming(); // Spigot
|
|
org.spigotmc.CustomTimingsHandler.tick(); // Spigot
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
index d62dfd54f..bf599a89a 100644
|
|
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
@@ -427,6 +427,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.e {
|
|
}
|
|
|
|
}
|
|
+
|
|
+ private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.96; // Spigot
|
|
+
|
|
protected void unloadChunks(BooleanSupplier booleansupplier) {
|
|
GameProfilerFiller gameprofilerfiller = this.level.getMethodProfiler();
|
|
|
|
@@ -442,18 +445,28 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.e {
|
|
|
|
private void b(BooleanSupplier booleansupplier) {
|
|
LongIterator longiterator = this.toDrop.iterator();
|
|
-
|
|
- for (int i = 0; longiterator.hasNext() && (booleansupplier.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) {
|
|
+ // Spigot start
|
|
+ org.spigotmc.SlackActivityAccountant activityAccountant = this.level.getMinecraftServer().slackActivityAccountant;
|
|
+ activityAccountant.startActivity(0.5);
|
|
+ int targetSize = (int) (this.toDrop.size() * UNLOAD_QUEUE_RESIZE_FACTOR);
|
|
+ // Spigot end
|
|
+ while (longiterator.hasNext()) { // Spigot
|
|
long j = longiterator.nextLong();
|
|
+ longiterator.remove(); // Spigot
|
|
PlayerChunk playerchunk = (PlayerChunk) this.updatingChunkMap.remove(j);
|
|
|
|
if (playerchunk != null) {
|
|
this.pendingUnloads.put(j, playerchunk);
|
|
this.modified = true;
|
|
- ++i;
|
|
+ // Spigot start
|
|
+ if (!booleansupplier.getAsBoolean() && this.toDrop.size() <= targetSize && activityAccountant.activityTimeIsExhausted()) {
|
|
+ break;
|
|
+ }
|
|
+ // Spigot end
|
|
this.a(j, playerchunk);
|
|
}
|
|
}
|
|
+ activityAccountant.endActivity(); // Spigot
|
|
|
|
Runnable runnable;
|
|
|
|
diff --git a/src/main/java/org/spigotmc/SlackActivityAccountant.java b/src/main/java/org/spigotmc/SlackActivityAccountant.java
|
|
new file mode 100644
|
|
index 000000000..aabc7ad20
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/spigotmc/SlackActivityAccountant.java
|
|
@@ -0,0 +1,78 @@
|
|
+package org.spigotmc;
|
|
+
|
|
+/**
|
|
+ * Keeps track of the time spent doing main thread activities that can be spread across ticks,
|
|
+ * so that such work doesn't exceed the current tick's estimated available slack time. Each
|
|
+ * activity is allotted a proportion of the expected slack time according to its weight, versus the
|
|
+ * estimated total weight of all activities.
|
|
+ */
|
|
+public class SlackActivityAccountant {
|
|
+ private double prevTickSlackWeightReciprocal = 1 / MIN_SLACK_WEIGHT;
|
|
+ private static final double MIN_SLACK_WEIGHT = 1 / 65536.0;
|
|
+ private double averageTickNonSlackNanos = 0;
|
|
+ private static final double AVERAGING_FACTOR = 0.375;
|
|
+
|
|
+ private long currentActivityStartNanos;
|
|
+ private static final long OFF = -1;
|
|
+ private long currentActivityEndNanos;
|
|
+ private double tickSlackWeight;
|
|
+ private long tickSlackNanos;
|
|
+
|
|
+ private double getSlackFraction(double slackWeight) {
|
|
+ return Math.min(slackWeight * this.prevTickSlackWeightReciprocal, 1);
|
|
+ }
|
|
+
|
|
+ private int getEstimatedSlackNanos() {
|
|
+ return (int) Math.max(net.minecraft.server.MinecraftServer.TICK_TIME - (long) this.averageTickNonSlackNanos, 0);
|
|
+ }
|
|
+
|
|
+ public void tickStarted() {
|
|
+ this.currentActivityStartNanos = OFF;
|
|
+ this.tickSlackWeight = 0;
|
|
+ this.tickSlackNanos = 0;
|
|
+ }
|
|
+
|
|
+ public void startActivity(double slackWeight) {
|
|
+ double slackFraction0 = getSlackFraction(this.tickSlackWeight);
|
|
+ this.tickSlackWeight += slackWeight;
|
|
+ double slackFraction1 = getSlackFraction(this.tickSlackWeight);
|
|
+
|
|
+ long t = System.nanoTime();
|
|
+ this.currentActivityStartNanos = t;
|
|
+ this.currentActivityEndNanos = t + ((int) ((slackFraction1 - slackFraction0) * this.getEstimatedSlackNanos()));
|
|
+ }
|
|
+
|
|
+ private void endActivity(long endNanos) {
|
|
+ this.tickSlackNanos += endNanos - this.currentActivityStartNanos;
|
|
+ this.currentActivityStartNanos = OFF;
|
|
+ }
|
|
+
|
|
+ public boolean activityTimeIsExhausted() {
|
|
+ if (this.currentActivityStartNanos == OFF) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ long t = System.nanoTime();
|
|
+ if (t <= this.currentActivityEndNanos) {
|
|
+ return false;
|
|
+ } else {
|
|
+ this.endActivity(this.currentActivityEndNanos);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void endActivity() {
|
|
+ if (this.currentActivityStartNanos == OFF) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ this.endActivity(Math.min(System.nanoTime(), this.currentActivityEndNanos));
|
|
+ }
|
|
+
|
|
+ public void tickEnded(long tickNanos) {
|
|
+ this.prevTickSlackWeightReciprocal = 1 / Math.max(this.tickSlackWeight, MIN_SLACK_WEIGHT);
|
|
+
|
|
+ long tickNonSlackNanos = tickNanos - this.tickSlackNanos;
|
|
+ this.averageTickNonSlackNanos = this.averageTickNonSlackNanos * (1 - AVERAGING_FACTOR) + tickNonSlackNanos * AVERAGING_FACTOR;
|
|
+ }
|
|
+}
|
|
--
|
|
2.25.1
|
|
|