fix(perf): avoid periodic attribution stalls
This commit is contained in:
1 parent
d886b1370b
commit
937c7f2edb
5 files changed
+54
-20
No files matched your search
@@ -0,0 +1,15 @@
|
||||
package com.moepus.serverwarashi.common.core.owner;
|
||||
|
||||
record ChunkKey(String dimension, long chunkPos) {
|
||||
private static final long MURMUR_C1 = 0xff51afd7ed558ccdL;
|
||||
private static final long MURMUR_C2 = 0xc4ceb9fe1a85ec53L;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long mixed = chunkPos;
|
||||
mixed = (mixed ^ mixed >>> 33) * MURMUR_C1;
|
||||
mixed = (mixed ^ mixed >>> 33) * MURMUR_C2;
|
||||
mixed ^= mixed >>> 33;
|
||||
return 31 * dimension.hashCode() + Long.hashCode(mixed);
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -11,6 +11,7 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.Ticket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -41,8 +42,8 @@ public final class PerfAttributionSnapshot {
|
||||
Map<ChunkKey, List<Bucket>> loaderByChunk,
|
||||
Map<BlockLoaderRef, List<LoaderTicketTarget>> loaderTargets,
|
||||
Map<BlockLoaderRef, LoaderControl> loaderControls) {
|
||||
this.byChunk = Map.copyOf(byChunk);
|
||||
this.loaderByChunk = Map.copyOf(loaderByChunk);
|
||||
this.byChunk = Collections.unmodifiableMap(byChunk);
|
||||
this.loaderByChunk = Collections.unmodifiableMap(loaderByChunk);
|
||||
this.loaderTargets = copyTargets(loaderTargets);
|
||||
this.loaderControls = new ConcurrentHashMap<>(loaderControls);
|
||||
Map<SourceIdentity, Bucket> unique = new HashMap<>();
|
||||
@@ -52,7 +53,11 @@ public final class PerfAttributionSnapshot {
|
||||
}
|
||||
|
||||
public static PerfAttributionSnapshot capture(MinecraftServer server) {
|
||||
return captureWithFingerprint(server).snapshot();
|
||||
CaptureMaps maps = new CaptureMaps();
|
||||
for (ServerLevel level : server.getAllLevels()) {
|
||||
captureLevel(level, maps, null, true);
|
||||
}
|
||||
return fromCapture(maps);
|
||||
}
|
||||
|
||||
public static Capture captureWithFingerprint(MinecraftServer server) {
|
||||
@@ -124,9 +129,9 @@ public final class PerfAttributionSnapshot {
|
||||
for (Bucket bucket : entry.getValue()) {
|
||||
if (isLoaderSource(bucket)) {
|
||||
var key = new LoaderRegionPlanner.SourceKey(
|
||||
entry.getKey().dimension, bucket.source.id,
|
||||
entry.getKey().dimension(), bucket.source.id,
|
||||
bucket.source.name, bucket.source.position, bucket.source.loaderRef);
|
||||
grouped.computeIfAbsent(key, ignored -> new HashSet<>()).add(entry.getKey().chunkPos);
|
||||
grouped.computeIfAbsent(key, ignored -> new HashSet<>()).add(entry.getKey().chunkPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,9 +381,6 @@ public final class PerfAttributionSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
private record ChunkKey(String dimension, long chunkPos) {
|
||||
}
|
||||
|
||||
private record OwnerIdentity(PerfReportData.AttributionKind kind, String id) {
|
||||
static OwnerIdentity from(Bucket bucket) {
|
||||
return new OwnerIdentity(bucket.owner.kind, bucket.owner.id);
|
||||
|
||||
+3
-8
@@ -27,7 +27,7 @@ final class TicketTopologyFingerprint {
|
||||
void addTickets(long chunkPos, Iterable<? extends Ticket<?>> tickets) {
|
||||
boolean chunkAdded = false;
|
||||
for (Ticket<?> ticket : tickets) {
|
||||
if (!isPotentialLoaderTicket(ticket)) {
|
||||
if (!isAttributableTicketType(ticket.getType())) {
|
||||
continue;
|
||||
}
|
||||
if (!chunkAdded) {
|
||||
@@ -48,12 +48,7 @@ final class TicketTopologyFingerprint {
|
||||
value *= FNV_PRIME;
|
||||
}
|
||||
|
||||
private static boolean isPotentialLoaderTicket(Ticket<?> ticket) {
|
||||
return ticket.getType() != TicketType.PLAYER
|
||||
&& ticket.getType() != TicketType.START
|
||||
&& ticket.getType() != TicketType.PORTAL
|
||||
&& ticket.getType() != TicketType.POST_TELEPORT
|
||||
&& ticket.getType() != TicketType.DRAGON
|
||||
&& ticket.getType() != TicketType.UNKNOWN;
|
||||
static boolean isAttributableTicketType(TicketType<?> type) {
|
||||
return type != TicketType.UNKNOWN;
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -13,7 +13,6 @@ import java.util.function.IntSupplier;
|
||||
final class PerfSessionController {
|
||||
private static final long NANOS_PER_SECOND = 1_000_000_000L;
|
||||
private static final int TOPOLOGY_CHECK_TICKS = 5;
|
||||
private static final int ATTRIBUTION_REFRESH_TICKS = 20;
|
||||
|
||||
private final IntSupplier sampleIntervalMicros;
|
||||
private ActiveSession active;
|
||||
@@ -189,8 +188,7 @@ final class PerfSessionController {
|
||||
&& session.completedTicks % TOPOLOGY_CHECK_TICKS == 0) {
|
||||
long topologyFingerprint = PerfAttributionSnapshot.ticketFingerprint(server);
|
||||
boolean topologyChanged = topologyFingerprint != session.ticketFingerprint;
|
||||
boolean periodicRefresh = session.completedTicks % ATTRIBUTION_REFRESH_TICKS == 0;
|
||||
if (!topologyChanged && !periodicRefresh && session.attribution != null) {
|
||||
if (!topologyChanged && session.attribution != null) {
|
||||
return;
|
||||
}
|
||||
PerfAttributionSnapshot next = PerfAttributionSnapshot.capture(server);
|
||||
|
||||
+25
-1
@@ -6,8 +6,9 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -21,6 +22,29 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PerfAttributionSnapshotTest {
|
||||
@Test
|
||||
void distributesPackedChunkCoordinatesAcrossHashSpace() {
|
||||
Set<Integer> hashes = new HashSet<>();
|
||||
int positions = 0;
|
||||
for (int z = -32; z <= 32; z++) {
|
||||
for (int x = -32; x <= 32; x++) {
|
||||
hashes.add(new ChunkKey("test:level", ChunkPos.asLong(x, z)).hashCode());
|
||||
positions++;
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(hashes.size() >= positions * 99 / 100,
|
||||
"Expected well-distributed hashes, got " + hashes.size() + " for " + positions + " keys");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fingerprintsEveryTicketTypeThatProducesAttribution() {
|
||||
assertTrue(TicketTopologyFingerprint.isAttributableTicketType(TicketType.PLAYER));
|
||||
assertTrue(TicketTopologyFingerprint.isAttributableTicketType(TicketType.START));
|
||||
assertTrue(TicketTopologyFingerprint.isAttributableTicketType(TicketType.FORCED));
|
||||
assertFalse(TicketTopologyFingerprint.isAttributableTicketType(TicketType.UNKNOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void expandsLevel31TargetsByOneBlockTickingChunk() {
|
||||
assertEquals(1, LoaderTicketInfluence.blockTickingRadius(31));
|
||||
|
||||
Reference in new issue
Block a user