9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-29 11:59:24 +00:00

reduce unparking on AsyncGoalThread

This commit is contained in:
Taiyou06
2025-05-02 02:00:44 +02:00
parent c20485292d
commit 35d7a185f3
2 changed files with 32 additions and 4 deletions

View File

@@ -18,6 +18,7 @@ public class AsyncGoalExecutor {
private final ServerLevel serverLevel;
private boolean dirty = false;
private long tickCount = 0L;
private static final int SPIN_LIMIT = 100;
public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel serverLevel) {
this.serverLevel = serverLevel;
@@ -38,8 +39,14 @@ public class AsyncGoalExecutor {
public final void submit(int entityId) {
if (!this.queue.send(entityId)) {
LockSupport.unpark(thread);
int spinCount = 0;
while (!this.queue.send(entityId)) {
spinCount++;
// Unpark thread after some spinning to help clear the queue
if (spinCount > SPIN_LIMIT) {
unpark();
spinCount = 0;
}
Thread.onSpinWait();
}
}
@@ -52,15 +59,18 @@ public class AsyncGoalExecutor {
}
public final void midTick() {
boolean didWork = false;
while (true) {
int id = this.wake.recv();
if (id == Integer.MAX_VALUE) {
break;
}
didWork = true;
Entity entity = this.serverLevel.getEntities().get(id);
if (entity == null || !entity.isAlive() || !(entity instanceof Mob mob)) {
continue;
}
mob.tickingTarget = true;
boolean a = mob.targetSelector.poll();
mob.tickingTarget = false;
@@ -69,8 +79,7 @@ public class AsyncGoalExecutor {
submit(id);
}
}
if ((tickCount & 3L) == 0L) unpark();
if (didWork || (tickCount & 15L) == 0L) unpark();
tickCount += 1;
}
}

View File

@@ -7,6 +7,8 @@ import net.minecraft.server.level.ServerLevel;
import java.util.concurrent.locks.LockSupport;
public class AsyncGoalThread extends Thread {
private static final int SPIN_TRIES = 1000;
public AsyncGoalThread(final MinecraftServer server) {
super(() -> run(server), "Leaf Async Goal Thread");
this.setDaemon(true);
@@ -16,21 +18,38 @@ public class AsyncGoalThread extends Thread {
}
private static void run(MinecraftServer server) {
int emptySpins = 0;
while (server.isRunning()) {
LockSupport.park();
boolean didWork = false;
for (ServerLevel level : server.getAllLevels()) {
var exec = level.asyncGoalExecutor;
boolean levelWork = false;
while (true) {
int id = exec.queue.recv();
if (id == Integer.MAX_VALUE) {
break;
}
levelWork = true;
if (exec.wake(id)) {
while (!exec.wake.send(id)) {
Thread.onSpinWait();
}
}
}
didWork |= levelWork;
}
// Adaptive parking
if (didWork) {
emptySpins = 0; // Reset counter when work was done
} else {
emptySpins++;
if (emptySpins > SPIN_TRIES) {
LockSupport.park(); // Only park after several empty spins
emptySpins = 0;
} else {
Thread.onSpinWait(); // Yield to other threads but don't park
}
}
}
}