9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-25 01:49:16 +00:00

Remove parallel world ticking

This commit is contained in:
Dreeam
2023-01-14 07:56:00 -05:00
parent e7a25cec0d
commit d1e7115af3
13 changed files with 1 additions and 327 deletions

View File

@@ -17,8 +17,7 @@
- Allowing players use tripwire dupe.
- Disabling the UseItemOnPacket Too Far check.
- Update all dependencies to the latest.
- Parallel entity ticking(Half of async)(In alpha)
- Parallel world ticking
- Parallel entity ticking(Half of async)(In beta)
- Some Purpur patches.
- ...

View File

@@ -1,223 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 13:04:01 +0800
Subject: [PATCH] Hearse: Parallel world ticking
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
index 443ac5267245c20830692b37802afd6ebdf8813b..c26511c26bd02320a55a01168f342b4b051ffdfd 100644
--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
+++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
@@ -8,14 +8,16 @@ import java.util.concurrent.atomic.AtomicInteger;
public class DefaultWorkerFactory implements WorkerThreadFactory {
private static final AtomicInteger poolId = new AtomicInteger();
private final AtomicInteger threadId = new AtomicInteger();
+ private final String bound;
- public DefaultWorkerFactory(){
+ public DefaultWorkerFactory(String bound){
poolId.getAndIncrement();
+ this.bound = bound;
}
@Override
public WorkerThread getNewThread(Runnable task) {
- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement());
+ final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound);
if (workerThread.isDaemon()){
workerThread.setDaemon(false);
}
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index fd7912df03ae39347206fe8db2efa7a8a0e516c8..9d26ff7d07f1e972f1720f5b2d0e66d4c9c3f1e5 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ServerEntityTickHook {
private static final Logger logger = LogManager.getLogger();
private static volatile boolean firstTick = false;
- private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory();
+ private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory("entity");
private static final AtomicInteger threadId = new AtomicInteger();
private static WorkerThreadPoolExecutor worker;
private static boolean asyncEntityEnabled;
diff --git a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
new file mode 100644
index 0000000000000000000000000000000000000000..5670fdae5d16cbbdf605df048ae253208e49a82c
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
@@ -0,0 +1,70 @@
+package co.earthme.hearse.server;
+
+import co.earthme.hearse.Hearse;
+import co.earthme.hearse.HearseConfig;
+import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
+import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
+import net.minecraft.CrashReport;
+import net.minecraft.ReportedException;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BooleanSupplier;
+
+public class ServerLevelTickHook {
+ private static final DefaultWorkerFactory workerFactory = new DefaultWorkerFactory("world");
+ private static WorkerThreadPoolExecutor worker;
+ private static boolean enabledParaWorld;
+ private static volatile boolean inited = false;
+ private static final AtomicInteger activeTaskCount = new AtomicInteger();
+
+ public static void initWorker(){
+ enabledParaWorld = HearseConfig.getBoolean("optimizations.enableparallelworldtick",true);
+ if (enabledParaWorld){
+ worker = new WorkerThreadPoolExecutor(
+ MinecraftServer.getServer().levels.size(),
+ MinecraftServer.getServer().levels.size(),
+ 0,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(),
+ workerFactory
+ );
+ worker.prestartAllCoreThreads();
+ Hearse.getWorkerManager().addWorker("world",worker);
+ }
+ inited = true;
+ }
+
+ public static boolean isInited(){
+ return inited;
+ }
+
+ public static void callWorldTick(ServerLevel worldserver, BooleanSupplier shouldKeepTicking){
+ activeTaskCount.getAndIncrement();
+ worker.execute(()->{
+ try {
+ try {
+ worldserver.tick(shouldKeepTicking);
+ for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) {
+ regionManager.recalculateRegions();
+ }
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ worldserver.explosionDensityCache.clear();
+ }finally {
+ activeTaskCount.getAndDecrement();
+ }
+ });
+ }
+
+ public static void awaitWorldTicKTasks(){
+ while (activeTaskCount.get() > 0){
+ LockSupport.parkNanos("Await world ticking",1000000);
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index fe47aff8654283aa6a17a36226aa9fc7f18f9886..57bae261ee1d6db734b38dd5f67dbce98c41fc1c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -3,6 +3,7 @@ package net.minecraft.server;
import co.earthme.hearse.Hearse;
import co.earthme.hearse.HearseConfig;
import co.earthme.hearse.server.ServerEntityTickHook;
+import co.earthme.hearse.server.ServerLevelTickHook;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -223,7 +224,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private String localIp;
private int port;
private final LayeredRegistryAccess<RegistryLayer> registries;
- private Map<ResourceKey<Level>, ServerLevel> levels;
+ public Map<ResourceKey<Level>, ServerLevel> levels;
private PlayerList playerList;
private volatile boolean running;
private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
@@ -1121,6 +1122,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
Arrays.fill( recentTps, 20 );
long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
lastTick = start - TICK_TIME; // Paper
+ ServerLevelTickHook.initWorker(); //Hearse
while (this.running) {
// Paper start - rewrite chunk system
// guarantee that nothing can stop the server from halting if it can at least still tick
@@ -1515,11 +1517,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
//MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper // Purpur
this.isIteratingOverLevels = true; // Paper
- Iterator iterator = this.getAllLevels().iterator(); // Paper - move down
- while (iterator.hasNext()) {
- ServerLevel worldserver = (ServerLevel) iterator.next();
- worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
- worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+ for (ServerLevel worldserver : this.getAllLevels()) {
+ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+ worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
/*this.profiler.push(() -> { // Purpur
@@ -1534,35 +1534,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// CraftBukkit end */
//this.profiler.push("tick"); // Purpur
-
- try {
- //worldserver.timings.doTick.startTiming(); // Spigot // Purpur
- worldserver.tick(shouldKeepTicking);
- // Paper start
- for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) {
- regionManager.recalculateRegions();
- }
- // Paper end
- //worldserver.timings.doTick.stopTiming(); // Spigot // Purpur
- } catch (Throwable throwable) {
- // Spigot Start
- CrashReport crashreport;
- try {
- crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
- } catch (Throwable t) {
- if (throwable instanceof ThreadDeath) { throw (ThreadDeath)throwable; } // Paper
- throw new RuntimeException("Error generating crash report", t);
- }
- // Spigot End
-
- worldserver.fillReportDetails(crashreport);
- throw new ReportedException(crashreport);
- }
-
- //this.profiler.pop(); // Purpur
- //this.profiler.pop(); // Purpur
- worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
+ ServerLevelTickHook.callWorldTick(worldserver,shouldKeepTicking);
}
+ ServerLevelTickHook.awaitWorldTicKTasks();
this.isIteratingOverLevels = false; // Paper
//this.profiler.popPush("connection"); // Purpur
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index de78c5bdde53b4adfed9fda4d473560849bdb5aa..4a75c2895f4f5e3229be3c7b177445611a1e70b6 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -7,6 +7,7 @@ import com.destroystokyo.paper.event.server.ServerExceptionEvent;
import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import java.io.IOException;
import java.util.Iterator;
@@ -179,7 +180,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
- public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = Maps.newConcurrentMap(); // Paper - Optimize explosions
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
// Paper start - fix and optimise world upgrading

View File

@@ -1,102 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 13:58:20 +0800
Subject: [PATCH] Hearse: Print world worker thread names when server started
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
index c26511c26bd02320a55a01168f342b4b051ffdfd..03a29509821a17faac2dc8ab810a2693b03bfbc6 100644
--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
+++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
@@ -2,25 +2,38 @@ package co.earthme.hearse.concurrent.threadfactory;
import co.earthme.hearse.concurrent.WorkerThread;
import co.earthme.hearse.concurrent.WorkerThreadFactory;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectLists;
import net.minecraft.server.MinecraftServer;
+
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class DefaultWorkerFactory implements WorkerThreadFactory {
private static final AtomicInteger poolId = new AtomicInteger();
private final AtomicInteger threadId = new AtomicInteger();
private final String bound;
+ private final List<Thread> createdThreads = ObjectLists.synchronize(new ObjectArrayList<>());
public DefaultWorkerFactory(String bound){
poolId.getAndIncrement();
this.bound = bound;
}
+ public List<Thread> getCreatedThreads() {
+ return this.createdThreads;
+ }
+
@Override
public WorkerThread getNewThread(Runnable task) {
- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound);
- if (workerThread.isDaemon()){
- workerThread.setDaemon(false);
- }
+ final WorkerThread workerThread = new WorkerThread(()->{
+ try {
+ task.run();
+ }finally {
+ this.createdThreads.remove(Thread.currentThread());
+ }
+ },"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound);
+ this.createdThreads.add(workerThread);
workerThread.setDaemon(true);
workerThread.setPriority(Thread.NORM_PRIORITY - 2);
workerThread.setContextClassLoader(MinecraftServer.class.getClassLoader());
diff --git a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
index 5670fdae5d16cbbdf605df048ae253208e49a82c..8085eb700d8e5c20ebb5bfeceb78198c6e973019 100644
--- a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
@@ -2,12 +2,15 @@ package co.earthme.hearse.server;
import co.earthme.hearse.Hearse;
import co.earthme.hearse.HearseConfig;
+import co.earthme.hearse.concurrent.WorkerThread;
import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
import net.minecraft.CrashReport;
import net.minecraft.ReportedException;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -21,6 +24,7 @@ public class ServerLevelTickHook {
private static boolean enabledParaWorld;
private static volatile boolean inited = false;
private static final AtomicInteger activeTaskCount = new AtomicInteger();
+ private static final Logger logger = LogManager.getLogger();
public static void initWorker(){
enabledParaWorld = HearseConfig.getBoolean("optimizations.enableparallelworldtick",true);
@@ -28,13 +32,17 @@ public class ServerLevelTickHook {
worker = new WorkerThreadPoolExecutor(
MinecraftServer.getServer().levels.size(),
MinecraftServer.getServer().levels.size(),
- 0,
+ Long.MAX_VALUE,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
workerFactory
);
+ worker.allowCoreThreadTimeOut(true);
worker.prestartAllCoreThreads();
Hearse.getWorkerManager().addWorker("world",worker);
+ for (Thread worker : workerFactory.getCreatedThreads()){
+ logger.warn("World worker name:{}.This can help you to slove the lag problems when you using parallel world ticking",worker.getName());
+ }
}
inited = true;
}