This commit is contained in:
Julian Krings 2024-10-31 21:05:07 +01:00
parent c38bb1cd01
commit b0f4b29a2d
5 changed files with 200 additions and 41 deletions

View File

@ -52,7 +52,7 @@ registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugin
// ============================================================== // ==============================================================
def NMS_BINDINGS = Map.of( def NMS_BINDINGS = Map.of(
"v1_21_R1", "1.21-R0.1-SNAPSHOT", "v1_21_R1", "1.21.1-R0.1-SNAPSHOT",
"v1_20_R4", "1.20.6-R0.1-SNAPSHOT", "v1_20_R4", "1.20.6-R0.1-SNAPSHOT",
"v1_20_R3", "1.20.4-R0.1-SNAPSHOT", "v1_20_R3", "1.20.4-R0.1-SNAPSHOT",
"v1_20_R2", "1.20.2-R0.1-SNAPSHOT", "v1_20_R2", "1.20.2-R0.1-SNAPSHOT",

View File

@ -25,7 +25,10 @@ import com.volmit.iris.util.json.JSONException;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -42,6 +45,7 @@ public class IrisSettings {
private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency(); private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency();
private IrisSettingsStudio studio = new IrisSettingsStudio(); private IrisSettingsStudio studio = new IrisSettingsStudio();
private IrisSettingsPerformance performance = new IrisSettingsPerformance(); private IrisSettingsPerformance performance = new IrisSettingsPerformance();
private IrisSettingsUpdater updater = new IrisSettingsUpdater();
public static int getThreadCount(int c) { public static int getThreadCount(int c) {
return switch (c) { return switch (c) {
@ -144,6 +148,30 @@ public class IrisSettings {
public int scriptLoaderCacheSize = 512; public int scriptLoaderCacheSize = 512;
} }
@Data
public static class IrisSettingsUpdater {
public double threadMultiplier = 2;
public double chunkLoadSensitivity = 0.7;
public MsRange emptyMsRange = new MsRange(80, 100);
public MsRange defaultMsRange = new MsRange(20, 40);
public double getThreadMultiplier() {
return Math.min(Math.abs(threadMultiplier), 0.1);
}
public double getChunkLoadSensitivity() {
return Math.min(chunkLoadSensitivity, 0.9);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class MsRange {
public int min = 20;
public int max = 40;
}
@Data @Data
public static class IrisSettingsGeneral { public static class IrisSettingsGeneral {
public boolean DoomsdayAnnihilationSelfDestructMode = false; public boolean DoomsdayAnnihilationSelfDestructMode = false;

View File

@ -1,6 +1,7 @@
package com.volmit.iris.core.pregenerator; package com.volmit.iris.core.pregenerator;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@ -9,9 +10,9 @@ import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.profile.LoadBalancer;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import lombok.Data;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
@ -34,16 +35,17 @@ public class ChunkUpdater {
private final AtomicInteger chunksProcessed = new AtomicInteger(); private final AtomicInteger chunksProcessed = new AtomicInteger();
private final AtomicInteger chunksProcessedLast = new AtomicInteger(); private final AtomicInteger chunksProcessedLast = new AtomicInteger();
private final AtomicInteger chunksUpdated = new AtomicInteger(); private final AtomicInteger chunksUpdated = new AtomicInteger();
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
private final AtomicLong lastCpsTime = new AtomicLong(M.ms()); private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() / getProperty(), 1); private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * getProperty(), 1);
private final Semaphore semaphore = new Semaphore(256); private final Semaphore semaphore = new Semaphore(256);
private final PlayerCounter playerCounter = new PlayerCounter(semaphore, 256); private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, 256, IrisSettings.get().getUpdater().emptyMsRange);
private final AtomicLong startTime = new AtomicLong(); private final AtomicLong startTime = new AtomicLong();
private final Dimensions dimensions; private final Dimensions dimensions;
private final PregenTask task; private final PregenTask task;
private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit); private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit);
private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit); private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit);
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final CountDownLatch latch; private final CountDownLatch latch;
private final Engine engine; private final Engine engine;
private final World world; private final World world;
@ -54,7 +56,6 @@ public class ChunkUpdater {
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region")); this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
this.task = dimensions.task(); this.task = dimensions.task();
this.totalMaxChunks.set(dimensions.count * 1024); this.totalMaxChunks.set(dimensions.count * 1024);
this.scheduler = Executors.newScheduledThreadPool(1);
this.latch = new CountDownLatch(totalMaxChunks.get()); this.latch = new CountDownLatch(totalMaxChunks.get());
} }
@ -107,7 +108,12 @@ public class ChunkUpdater {
} }
}, 0, 3, TimeUnit.SECONDS); }, 0, 3, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS); scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(playerCounter::update, 0, 5, TimeUnit.SECONDS); scheduler.scheduleAtFixedRate(() -> {
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
if (serverEmpty.getAndSet(empty) == empty)
return;
loadBalancer.setRange(empty ? IrisSettings.get().getUpdater().emptyMsRange : IrisSettings.get().getUpdater().defaultMsRange);
}, 0, 10, TimeUnit.SECONDS);
var t = new Thread(() -> { var t = new Thread(() -> {
run(); run();
@ -123,7 +129,7 @@ public class ChunkUpdater {
public void close() { public void close() {
try { try {
playerCounter.close(); loadBalancer.close();
semaphore.acquire(256); semaphore.acquire(256);
executor.shutdown(); executor.shutdown();
@ -334,39 +340,7 @@ public class ChunkUpdater {
private record Dimensions(Position2 min, Position2 max, int count, PregenTask task) { } private record Dimensions(Position2 min, Position2 max, int count, PregenTask task) { }
@Data
private static class PlayerCounter {
private final Semaphore semaphore;
private final int maxPermits;
private int lastCount = 0;
private int permits = 0;
public void update() {
double count = Bukkit.getOnlinePlayers().size();
if (count == lastCount)
return;
double p = count == 0 ? 0 : count / (Bukkit.getMaxPlayers() / 2d);
int targetPermits = (int) (maxPermits * p);
int diff = targetPermits - permits;
permits = targetPermits;
lastCount = (int) count;
try {
if (diff > 0) semaphore.release(diff);
else semaphore.acquire(Math.abs(diff));
} catch (InterruptedException ignored) {}
}
public void close() {
semaphore.release(permits);
}
}
private static double getProperty() { private static double getProperty() {
try { return IrisSettings.get().getUpdater().getThreadMultiplier();
return Double.parseDouble(System.getProperty("iris.updater"));
} catch (Throwable e) {
return 1;
}
} }
} }

View File

@ -0,0 +1,73 @@
package com.volmit.iris.util.profile;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.util.math.M;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.java.Log;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
@Log
@Getter
public class LoadBalancer extends MsptTimings {
private final Semaphore semaphore;
private final int maxPermits;
private final double range;
@Setter
private int minMspt, maxMspt;
private int permits, lastMspt;
private long lastTime = M.ms();
private Future<?> future;
public LoadBalancer(Semaphore semaphore, int maxPermits, IrisSettings.MsRange range) {
this(semaphore, maxPermits, range.getMin(), range.getMax());
}
public LoadBalancer(Semaphore semaphore, int maxPermits, int minMspt, int maxMspt) {
this.semaphore = semaphore;
this.maxPermits = maxPermits;
this.minMspt = minMspt;
this.maxMspt = maxMspt;
this.range = maxMspt - minMspt;
setName("LoadBalancer");
start();
}
@Override
protected void update(int raw) {
lastTime = M.ms();
int mspt = raw;
if (mspt < lastMspt) {
int min = (int) Math.max(lastMspt * IrisSettings.get().getUpdater().getChunkLoadSensitivity(), 1);
mspt = Math.max(mspt, min);
}
lastMspt = mspt;
mspt = Math.max(mspt - minMspt, 0);
double percent = mspt / range;
int target = (int) (maxPermits * percent);
target = Math.min(target, maxPermits - 20);
int diff = target - permits;
permits = target;
if (diff == 0) return;
log.info("Adjusting load to %s (%s) permits (%s mspt, %.2f)".formatted(target, diff, raw, percent));
if (diff > 0) semaphore.acquireUninterruptibly(diff);
else semaphore.release(Math.abs(diff));
}
public void close() {
interrupt();
semaphore.release(permits);
}
public void setRange(IrisSettings.MsRange range) {
minMspt = range.getMin();
maxMspt = range.getMax();
}
}

View File

@ -0,0 +1,84 @@
package com.volmit.iris.util.profile;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import org.bukkit.Bukkit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public abstract class MsptTimings extends Looper {
private final AtomicInteger currentTick = new AtomicInteger(0);
private int lastTick, lastMspt;
private long lastTime;
private int taskId = -1;
public MsptTimings() {
setName("MsptTimings");
setPriority(9);
setDaemon(true);
}
public static MsptTimings of(Consumer<Integer> update) {
return new Simple(update);
}
@Override
protected final long loop() {
if (startTickTask())
return 200;
long now = M.ms();
int tick = currentTick.get();
int deltaTick = tick - lastTick;
if (deltaTick == 0)
return 200;
lastTick = tick;
int deltaTime = (int) (now - lastTime);
lastTime = now;
int mspt = deltaTime / deltaTick;
mspt -= 50;
mspt = Math.max(mspt, 0);
lastMspt = mspt;
update(mspt);
return 200;
}
public final int getMspt() {
return lastMspt;
}
protected abstract void update(int mspt);
private boolean startTickTask() {
if (taskId != -1 && (Bukkit.getScheduler().isQueued(taskId) || Bukkit.getScheduler().isCurrentlyRunning(taskId)))
return false;
taskId = J.sr(() -> {
if (isInterrupted()) {
J.csr(taskId);
return;
}
currentTick.incrementAndGet();
}, 1);
return taskId != -1;
}
private static class Simple extends MsptTimings {
private final Consumer<Integer> update;
private Simple(Consumer<Integer> update) {
this.update = update;
start();
}
@Override
protected void update(int mspt) {
if (update == null)
return;
update.accept(mspt);
}
}
}