From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Thu, 26 Mar 2020 21:59:32 -0700 Subject: [PATCH] Detail more information in watchdog dumps - Dump position, world, velocity, and uuid for currently ticking entities - Dump player name, player uuid, position, and world for packet handling Feature patch diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java index d18af548fa6e979267347443b61efc58b271dfcf..e693a003ea8f022eef8b49e4332025b769333b30 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -632,7 +632,13 @@ public class Connection extends SimpleChannelInboundHandler> { if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { + // Paper start - detailed watchdog information + net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener); + try { tickablepacketlistener.tick(); + } finally { + net.minecraft.network.protocol.PacketUtils.packetProcessing.pop(); + } // Paper end - detailed watchdog information } // Paper end - Buffer joins to world } diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java index f7197f1347251a37dd0f6d9ffa2f09bc3a4e1233..1f7f68aad97ee73763c042837f239bdc7167db55 100644 --- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java +++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java @@ -20,6 +20,24 @@ public class PacketUtils { private static final Logger LOGGER = LogUtils.getLogger(); + // Paper start - detailed watchdog information + public static final java.util.concurrent.ConcurrentLinkedDeque packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>(); + static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong(); + + public static long getTotalProcessedPackets() { + return totalMainThreadPacketsProcessed.get(); + } + + public static java.util.List getCurrentPacketProcessors() { + java.util.List ret = new java.util.ArrayList<>(4); + for (PacketListener listener : packetProcessing) { + ret.add(listener); + } + + return ret; + } + // Paper end - detailed watchdog information + public PacketUtils() {} public static void ensureRunningOnSameThread(Packet packet, T listener, ServerLevel world) throws RunningOnDifferentThreadException { @@ -29,6 +47,8 @@ public class PacketUtils { public static void ensureRunningOnSameThread(Packet packet, T listener, BlockableEventLoop engine) throws RunningOnDifferentThreadException { if (!engine.isSameThread()) { engine.executeIfPossible(() -> { + packetProcessing.push(listener); // Paper - detailed watchdog information + try { // Paper - detailed watchdog information if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players if (listener.shouldHandleMessage(packet)) { try { @@ -47,6 +67,12 @@ public class PacketUtils { } else { PacketUtils.LOGGER.debug("Ignoring packet due to disconnection: {}", packet); } + // Paper start - detailed watchdog information + } finally { + totalMainThreadPacketsProcessed.getAndIncrement(); + packetProcessing.pop(); + } + // Paper end - detailed watchdog information }); throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 9928e14a5a42a2f0deba86e9dcb1f6f9f59412ef..d81be1069ef6ce51789df38ce21f125b6d524945 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1253,7 +1253,26 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } + // Paper start - log detailed entity tick information + // TODO replace with varhandle + static final java.util.concurrent.atomic.AtomicReference currentlyTickingEntity = new java.util.concurrent.atomic.AtomicReference<>(); + + public static List getCurrentlyTickingEntities() { + Entity ticking = currentlyTickingEntity.get(); + List ret = java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking }); + + return ret; + } + // Paper end - log detailed entity tick information + public void tickNonPassenger(Entity entity) { + // Paper start - log detailed entity tick information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); + try { + if (currentlyTickingEntity.get() == null) { + currentlyTickingEntity.lazySet(entity); + } + // Paper end - log detailed entity tick information // Spigot start /*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out EAR 2 entity.tickCount++; @@ -1283,6 +1302,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 } + // Paper start - log detailed entity tick information + } finally { + if (currentlyTickingEntity.get() == entity) { + currentlyTickingEntity.lazySet(null); + } + } + // Paper end - log detailed entity tick information } private void tickPassenger(Entity vehicle, Entity passenger, boolean isActive) { // Paper - EAR 2 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index b810f887e536af938f978ca2af068e6ae89b5e60..8c62d1aa5c8a062685474dca7e91bf9f8b004ca5 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -1128,8 +1128,43 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.onGround; } + // Paper start - detailed watchdog information + public final Object posLock = new Object(); // Paper - log detailed entity tick information + + private Vec3 moveVector; + private double moveStartX; + private double moveStartY; + private double moveStartZ; + + public final Vec3 getMoveVector() { + return this.moveVector; + } + + public final double getMoveStartX() { + return this.moveStartX; + } + + public final double getMoveStartY() { + return this.moveStartY; + } + + public final double getMoveStartZ() { + return this.moveStartZ; + } + // Paper end - detailed watchdog information + public void move(MoverType type, Vec3 movement) { final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity + // Paper start - detailed watchdog information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); + synchronized (this.posLock) { + this.moveStartX = this.getX(); + this.moveStartY = this.getY(); + this.moveStartZ = this.getZ(); + this.moveVector = movement; + } + try { + // Paper end - detailed watchdog information if (this.noPhysics) { this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { @@ -1250,6 +1285,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess gameprofilerfiller.pop(); } } + // Paper start - detailed watchdog information + } finally { + synchronized (this.posLock) { // Paper + this.moveVector = null; + } // Paper + } + // Paper end - detailed watchdog information } private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) { @@ -4872,7 +4914,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public void setDeltaMovement(Vec3 velocity) { + synchronized (this.posLock) { // Paper this.deltaMovement = velocity; + } // Paper } public void addDeltaMovement(Vec3 velocity) { @@ -4978,7 +5022,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Paper end - Fix MC-4 if (this.position.x != x || this.position.y != y || this.position.z != z) { + synchronized (this.posLock) { // Paper this.position = new Vec3(x, y, z); + } // Paper int i = Mth.floor(x); int j = Mth.floor(y); int k = Mth.floor(z); diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java index c9e17225bc52fe5e7b2dc0908db225a86c6e94d1..f7a4fee9bb25ff256dc2e5ea26bfbceca6a49167 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java @@ -22,6 +22,78 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre private volatile long lastTick; private volatile boolean stopping; + // Paper start - log detailed tick information + private void dumpEntity(net.minecraft.world.entity.Entity entity) { + Logger log = Bukkit.getServer().getLogger(); + double posX, posY, posZ; + net.minecraft.world.phys.Vec3 mot; + double moveStartX, moveStartY, moveStartZ; + net.minecraft.world.phys.Vec3 moveVec; + synchronized (entity.posLock) { + posX = entity.getX(); + posY = entity.getY(); + posZ = entity.getZ(); + mot = entity.getDeltaMovement(); + moveStartX = entity.getMoveStartX(); + moveStartY = entity.getMoveStartY(); + moveStartZ = entity.getMoveStartZ(); + moveVec = entity.getMoveVector(); + } + + String entityType = net.minecraft.world.entity.EntityType.getKey(entity.getType()).toString(); + java.util.UUID entityUUID = entity.getUUID(); + net.minecraft.world.level.Level world = entity.level(); + + log.log(Level.SEVERE, "Ticking entity: " + entityType + ", entity class: " + entity.getClass().getName()); + log.log(Level.SEVERE, "Entity status: removed: " + entity.isRemoved() + ", valid: " + entity.valid + ", alive: " + entity.isAlive() + ", is passenger: " + entity.isPassenger()); + log.log(Level.SEVERE, "Entity UUID: " + entityUUID); + log.log(Level.SEVERE, "Position: world: '" + (world == null ? "unknown world?" : world.getWorld().getName()) + "' at location (" + posX + ", " + posY + ", " + posZ + ")"); + log.log(Level.SEVERE, "Velocity: " + (mot == null ? "unknown velocity" : mot.toString()) + " (in blocks per tick)"); + log.log(Level.SEVERE, "Entity AABB: " + entity.getBoundingBox()); + if (moveVec != null) { + log.log(Level.SEVERE, "Move call information: "); + log.log(Level.SEVERE, "Start position: (" + moveStartX + ", " + moveStartY + ", " + moveStartZ + ")"); + log.log(Level.SEVERE, "Move vector: " + moveVec.toString()); + } + } + + private void dumpTickingInfo() { + Logger log = Bukkit.getServer().getLogger(); + + // ticking entities + for (net.minecraft.world.entity.Entity entity : net.minecraft.server.level.ServerLevel.getCurrentlyTickingEntities()) { + this.dumpEntity(entity); + net.minecraft.world.entity.Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + log.log(Level.SEVERE, "Detailing vehicle for above entity:"); + this.dumpEntity(vehicle); + } + } + + // packet processors + for (net.minecraft.network.PacketListener packetListener : net.minecraft.network.protocol.PacketUtils.getCurrentPacketProcessors()) { + if (packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl) { + net.minecraft.server.level.ServerPlayer player = ((net.minecraft.server.network.ServerGamePacketListenerImpl)packetListener).player; + long totalPackets = net.minecraft.network.protocol.PacketUtils.getTotalProcessedPackets(); + if (player == null) { + log.log(Level.SEVERE, "Handling packet for player connection or ticking player connection (null player): " + packetListener); + log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets); + } else { + this.dumpEntity(player); + net.minecraft.world.entity.Entity vehicle = player.getVehicle(); + if (vehicle != null) { + log.log(Level.SEVERE, "Detailing vehicle for above entity:"); + this.dumpEntity(vehicle); + } + log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets); + } + } else { + log.log(Level.SEVERE, "Handling packet for connection: " + packetListener); + } + } + } + // Paper end - log detailed tick information + private WatchdogThread(long timeoutTime, boolean restart) { super( "Paper Watchdog Thread" ); @@ -119,6 +191,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre log.log( Level.SEVERE, "------------------------------" ); log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - rewrite chunk system + this.dumpTickingInfo(); // Paper - log detailed tick information WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); log.log( Level.SEVERE, "------------------------------" ); //