From 83343517877399b88be05608fed35952430b0175 Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 10 Jan 2013 00:18:11 -0500 Subject: [PATCH] Spigot Timings Overhauls the Timings System adding performance tracking all around the Minecraft Server diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index d6a0a52eb..45d3e3db3 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -180,6 +180,8 @@ import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; import org.bukkit.event.server.ServerLoadEvent; // CraftBukkit end +import org.bukkit.craftbukkit.SpigotTimings; // Spigot + public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant implements ICommandListener, AutoCloseable { public static final Logger LOGGER = LogUtils.getLogger(); @@ -1149,6 +1151,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0 && this.tickCount % autosavePeriod == 0) { // CraftBukkit + SpigotTimings.worldSaveTimer.startTiming(); // Spigot MinecraftServer.LOGGER.debug("Autosave started"); this.profiler.push("save"); this.saveEverything(true, false, false); this.profiler.pop(); MinecraftServer.LOGGER.debug("Autosave finished"); + SpigotTimings.worldSaveTimer.stopTiming(); // Spigot } this.profiler.push("tallying"); @@ -1191,21 +1196,30 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag); ChunkProviderServer.b chunkproviderserver_b = this.mainThreadProcessor; Objects.requireNonNull(completablefuture); chunkproviderserver_b.managedBlock(completablefuture::isDone); + level.timings.syncChunkLoadTimer.stopTiming(); // Spigot ichunkaccess = (IChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { return ichunkaccess1; }, (playerchunk_failure) -> { @@ -374,15 +376,19 @@ public class ChunkProviderServer extends IChunkProvider { @Override public void tick(BooleanSupplier booleansupplier, boolean flag) { this.level.getProfiler().push("purge"); + this.level.timings.doChunkMap.startTiming(); // Spigot this.distanceManager.purgeStaleTickets(); this.runDistanceManagerUpdates(); + this.level.timings.doChunkMap.stopTiming(); // Spigot this.level.getProfiler().popPush("chunks"); if (flag) { this.tickChunks(); } + this.level.timings.doChunkUnload.startTiming(); // Spigot this.level.getProfiler().popPush("unload"); this.chunkMap.tick(booleansupplier); + this.level.timings.doChunkUnload.stopTiming(); // Spigot this.level.getProfiler().pop(); this.clearCache(); } @@ -440,7 +446,9 @@ public class ChunkProviderServer extends IChunkProvider { } if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { + this.level.timings.doTickTiles.startTiming(); // Spigot this.level.tickChunk(chunk1, k); + this.level.timings.doTickTiles.stopTiming(); // Spigot } } } @@ -456,7 +464,9 @@ public class ChunkProviderServer extends IChunkProvider { }); gameprofilerfiller.pop(); gameprofilerfiller.pop(); + this.level.timings.tracker.startTiming(); // Spigot this.chunkMap.tick(); + this.level.timings.tracker.stopTiming(); // Spigot } } diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java index 669efebaf..189c82112 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java @@ -161,6 +161,7 @@ import net.minecraft.world.level.storage.WorldDataServer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.WeatherType; +import org.bukkit.craftbukkit.SpigotTimings; // Spigot import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; import org.bukkit.craftbukkit.util.CraftNamespacedKey; @@ -358,6 +359,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { this.updateSkyBrightness(); this.tickTime(); gameprofilerfiller.popPush("tickPending"); + timings.doTickPending.startTiming(); // Spigot if (!this.isDebug()) { j = this.getGameTime(); gameprofilerfiller.push("blockTicks"); @@ -366,13 +368,16 @@ public class WorldServer extends World implements GeneratorAccessSeed { this.fluidTicks.tick(j, 65536, this::tickFluid); gameprofilerfiller.pop(); } + timings.doTickPending.stopTiming(); // Spigot gameprofilerfiller.popPush("raid"); this.raids.tick(); gameprofilerfiller.popPush("chunkSource"); this.getChunkSource().tick(booleansupplier, true); gameprofilerfiller.popPush("blockEvents"); + timings.doSounds.startTiming(); // Spigot this.runBlockEvents(); + timings.doSounds.stopTiming(); // Spigot this.handlingTick = false; gameprofilerfiller.pop(); boolean flag = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players @@ -383,12 +388,14 @@ public class WorldServer extends World implements GeneratorAccessSeed { if (flag || this.emptyTime++ < 300) { gameprofilerfiller.push("entities"); + timings.tickEntities.startTiming(); // Spigot if (this.dragonFight != null) { gameprofilerfiller.push("dragonFight"); this.dragonFight.tick(); gameprofilerfiller.pop(); } + timings.entityTick.startTiming(); // Spigot this.entityTickList.forEach((entity) -> { if (!entity.isRemoved()) { if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed @@ -415,6 +422,8 @@ public class WorldServer extends World implements GeneratorAccessSeed { } } }); + timings.entityTick.stopTiming(); // Spigot + timings.tickEntities.stopTiming(); // Spigot gameprofilerfiller.pop(); this.tickBlockEntities(); } @@ -796,6 +805,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { } public void tickNonPassenger(Entity entity) { + entity.tickTimer.startTiming(); // Spigot entity.setOldPosAndRot(); GameProfilerFiller gameprofilerfiller = this.getProfiler(); @@ -814,6 +824,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { this.tickPassenger(entity, entity1); } + entity.tickTimer.stopTiming(); // Spigot } diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java index 78dc73545..7cc199599 100644 --- a/src/main/java/net/minecraft/server/network/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java @@ -310,6 +310,7 @@ public class PlayerConnection implements ServerPlayerConnection, PacketListenerP // CraftBukkit end public void tick() { + org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot if (this.ackBlockChangesUpTo > -1) { this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); this.ackBlockChangesUpTo = -1; @@ -390,6 +391,7 @@ public class PlayerConnection implements ServerPlayerConnection, PacketListenerP this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 this.disconnect(IChatBaseComponent.translatable("multiplayer.disconnect.idling")); } + org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.stopTiming(); // Spigot this.chatPreviewThrottler.tick(); } @@ -1977,6 +1979,7 @@ public class PlayerConnection implements ServerPlayerConnection, PacketListenerP } private void handleCommand(String s) { + org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.startTiming(); // Spigot this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); CraftPlayer player = this.getCraftPlayer(); @@ -1985,6 +1988,7 @@ public class PlayerConnection implements ServerPlayerConnection, PacketListenerP this.cserver.getPluginManager().callEvent(event); if (event.isCancelled()) { + org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot return; } @@ -1996,6 +2000,8 @@ public class PlayerConnection implements ServerPlayerConnection, PacketListenerP player.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command"); java.util.logging.Logger.getLogger(PlayerConnection.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); return; + } finally { + org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot } } // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 375cac9c3..0cb6f8798 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -134,6 +134,7 @@ import org.bukkit.craftbukkit.event.CraftPortalEvent; import org.bukkit.entity.Hanging; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Vehicle; +import org.spigotmc.CustomTimingsHandler; // Spigot import org.bukkit.event.entity.EntityCombustByEntityEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; @@ -300,6 +301,7 @@ public abstract class Entity implements INamableTileEntity, EntityAccess, IComma public boolean lastDamageCancelled; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled public boolean persistentInvisibility = false; public BlockPosition lastLavaContact; + public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot public float getBukkitYaw() { return this.yRot; @@ -730,6 +732,7 @@ public abstract class Entity implements INamableTileEntity, EntityAccess, IComma } public void move(EnumMoveType enummovetype, Vec3D vec3d) { + org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.startTiming(); // Spigot if (this.noPhysics) { this.setPos(this.getX() + vec3d.x, this.getY() + vec3d.y, this.getZ() + vec3d.z); } else { @@ -893,6 +896,7 @@ public abstract class Entity implements INamableTileEntity, EntityAccess, IComma this.level.getProfiler().pop(); } } + org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot } protected boolean isHorizontalCollisionMinor(Vec3D vec3d) { diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java index 34babd833..55711380d 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java @@ -142,6 +142,8 @@ import org.bukkit.event.entity.EntityTeleportEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; // CraftBukkit end +import org.bukkit.craftbukkit.SpigotTimings; // Spigot + public abstract class EntityLiving extends Entity { private static final Logger LOGGER = LogUtils.getLogger(); @@ -2787,6 +2789,7 @@ public abstract class EntityLiving extends Entity { @Override public void tick() { + SpigotTimings.timerEntityBaseTick.startTiming(); // Spigot super.tick(); this.updatingUsingItem(); this.updateSwimAmount(); @@ -2827,7 +2830,9 @@ public abstract class EntityLiving extends Entity { } } + SpigotTimings.timerEntityBaseTick.stopTiming(); // Spigot this.aiStep(); + SpigotTimings.timerEntityTickRest.startTiming(); // Spigot double d0 = this.getX() - this.xo; double d1 = this.getZ() - this.zo; float f = (float) (d0 * d0 + d1 * d1); @@ -2908,6 +2913,7 @@ public abstract class EntityLiving extends Entity { this.setXRot(0.0F); } + SpigotTimings.timerEntityTickRest.stopTiming(); // Spigot } public void detectEquipmentUpdates() { @@ -3089,6 +3095,7 @@ public abstract class EntityLiving extends Entity { this.setDeltaMovement(d4, d5, d6); this.level.getProfiler().push("ai"); + SpigotTimings.timerEntityAI.startTiming(); // Spigot if (this.isImmobile()) { this.jumping = false; this.xxa = 0.0F; @@ -3098,6 +3105,7 @@ public abstract class EntityLiving extends Entity { this.serverAiStep(); this.level.getProfiler().pop(); } + SpigotTimings.timerEntityAI.stopTiming(); // Spigot this.level.getProfiler().pop(); this.level.getProfiler().push("jump"); @@ -3132,7 +3140,9 @@ public abstract class EntityLiving extends Entity { this.updateFallFlying(); AxisAlignedBB axisalignedbb = this.getBoundingBox(); + SpigotTimings.timerEntityAIMove.startTiming(); // Spigot this.travel(new Vec3D((double) this.xxa, (double) this.yya, (double) this.zza)); + SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot this.level.getProfiler().pop(); this.level.getProfiler().push("freezing"); boolean flag1 = this.getType().is(TagsEntity.FREEZE_HURTS_EXTRA_TYPES); @@ -3161,7 +3171,9 @@ public abstract class EntityLiving extends Entity { this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); } + SpigotTimings.timerEntityAICollision.startTiming(); // Spigot this.pushEntities(); + SpigotTimings.timerEntityAICollision.stopTiming(); // Spigot this.level.getProfiler().pop(); if (!this.level.isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { this.hurt(DamageSource.DROWN, 1.0F); diff --git a/src/main/java/net/minecraft/world/level/SpawnerCreature.java b/src/main/java/net/minecraft/world/level/SpawnerCreature.java index 424d0c589..fd6c35501 100644 --- a/src/main/java/net/minecraft/world/level/SpawnerCreature.java +++ b/src/main/java/net/minecraft/world/level/SpawnerCreature.java @@ -116,6 +116,7 @@ public final class SpawnerCreature { public static void spawnForChunk(WorldServer worldserver, Chunk chunk, SpawnerCreature.d spawnercreature_d, boolean flag, boolean flag1, boolean flag2) { worldserver.getProfiler().push("spawner"); + worldserver.timings.mobSpawn.startTiming(); // Spigot EnumCreatureType[] aenumcreaturetype = SpawnerCreature.SPAWNING_CATEGORIES; int i = aenumcreaturetype.length; @@ -146,6 +147,7 @@ public final class SpawnerCreature { } } + worldserver.timings.mobSpawn.stopTiming(); // Spigot worldserver.getProfiler().pop(); } diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java index a8e8ee431..167902935 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java @@ -83,6 +83,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.SpigotTimings; // Spigot import org.bukkit.craftbukkit.block.CapturedBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.util.CraftSpawnCategory; @@ -149,6 +150,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable { public boolean populating; public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot + public final SpigotTimings.WorldTimingsHandler timings; // Spigot + public CraftWorld getWorld() { return this.world; } @@ -238,6 +241,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { public void onBorderSetDamageSafeZOne(WorldBorder worldborder, double d0) {} }); // CraftBukkit end + timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings } @Override @@ -594,12 +598,15 @@ public abstract class World implements GeneratorAccess, AutoCloseable { GameProfilerFiller gameprofilerfiller = this.getProfiler(); gameprofilerfiller.push("blockEntities"); + timings.tileEntityPending.startTiming(); // Spigot this.tickingBlockEntities = true; if (!this.pendingBlockEntityTickers.isEmpty()) { this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); this.pendingBlockEntityTickers.clear(); } + timings.tileEntityPending.stopTiming(); // Spigot + timings.tileEntityTick.startTiming(); // Spigot Iterator iterator = this.blockEntityTickers.iterator(); while (iterator.hasNext()) { @@ -612,13 +619,16 @@ public abstract class World implements GeneratorAccess, AutoCloseable { } } + timings.tileEntityTick.stopTiming(); // Spigot this.tickingBlockEntities = false; gameprofilerfiller.pop(); } public void guardEntityTick(Consumer consumer, T t0) { try { + SpigotTimings.tickEntityTimer.startTiming(); // Spigot consumer.accept(t0); + SpigotTimings.tickEntityTimer.stopTiming(); // Spigot } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity"); CrashReportSystemDetails crashreportsystemdetails = crashreport.addCategory("Entity being ticked"); diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java index a39b39e2e..1fd16fc43 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java @@ -21,8 +21,11 @@ import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; import org.bukkit.inventory.InventoryHolder; // CraftBukkit end +import org.spigotmc.CustomTimingsHandler; // Spigot + public abstract class TileEntity { + public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot // CraftBukkit start - data containers private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); public CraftPersistentDataContainer persistentDataContainer; diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java index af55eb3b1..99a2ddbc1 100644 --- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java @@ -882,6 +882,7 @@ public class Chunk extends IChunkAccess { GameProfilerFiller gameprofilerfiller = Chunk.this.level.getProfiler(); gameprofilerfiller.push(this::getType); + this.blockEntity.tickTimer.startTiming(); // Spigot IBlockData iblockdata = Chunk.this.getBlockState(blockposition); if (this.blockEntity.getType().isValid(iblockdata)) { @@ -899,6 +900,10 @@ public class Chunk extends IChunkAccess { this.blockEntity.fillCrashReportCategory(crashreportsystemdetails); throw new ReportedException(crashreport); + // Spigot start + } finally { + this.blockEntity.tickTimer.stopTiming(); + // Spigot end } } } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java index 71c12a5b5..26bd661e8 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java @@ -507,10 +507,13 @@ public class ChunkRegionLoader { NBTTagList nbttaglist1 = getListOfCompoundsOrNull(nbttagcompound, "block_entities"); return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> { + worldserver.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot if (nbttaglist != null) { worldserver.addLegacyChunkEntities(EntityTypes.loadEntitiesRecursive(nbttaglist, worldserver)); } + worldserver.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot + worldserver.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot if (nbttaglist1 != null) { for (int i = 0; i < nbttaglist1.size(); ++i) { NBTTagCompound nbttagcompound1 = nbttaglist1.getCompound(i); @@ -528,6 +531,7 @@ public class ChunkRegionLoader { } } } + worldserver.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot }; } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index aab68f031..cb78477a7 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2282,6 +2282,11 @@ public final class CraftServer implements Server { private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot() { + @Override + public YamlConfiguration getConfig() + { + return org.spigotmc.SpigotConfig.config; + } }; public org.bukkit.Server.Spigot spigot() diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java new file mode 100644 index 000000000..aff7b6b43 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java @@ -0,0 +1,160 @@ +package org.bukkit.craftbukkit; + +import java.util.HashMap; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.World; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.storage.WorldDataServer; +import org.bukkit.craftbukkit.scheduler.CraftTask; +import org.bukkit.plugin.java.JavaPluginLoader; +import org.bukkit.scheduler.BukkitTask; +import org.spigotmc.CustomTimingsHandler; + +public class SpigotTimings { + + public static final CustomTimingsHandler serverTickTimer = new CustomTimingsHandler("** Full Server Tick"); + public static final CustomTimingsHandler playerListTimer = new CustomTimingsHandler("Player List"); + public static final CustomTimingsHandler commandFunctionsTimer = new CustomTimingsHandler("Command Functions"); + public static final CustomTimingsHandler connectionTimer = new CustomTimingsHandler("Connection Handler"); + public static final CustomTimingsHandler playerConnectionTimer = new CustomTimingsHandler("** PlayerConnection"); + public static final CustomTimingsHandler tickablesTimer = new CustomTimingsHandler("Tickables"); + public static final CustomTimingsHandler schedulerTimer = new CustomTimingsHandler("Scheduler"); + public static final CustomTimingsHandler timeUpdateTimer = new CustomTimingsHandler("Time Update"); + public static final CustomTimingsHandler serverCommandTimer = new CustomTimingsHandler("Server Command"); + public static final CustomTimingsHandler worldSaveTimer = new CustomTimingsHandler("World Save"); + + public static final CustomTimingsHandler entityMoveTimer = new CustomTimingsHandler("** entityMove"); + public static final CustomTimingsHandler tickEntityTimer = new CustomTimingsHandler("** tickEntity"); + public static final CustomTimingsHandler activatedEntityTimer = new CustomTimingsHandler("** activatedTickEntity"); + public static final CustomTimingsHandler tickTileEntityTimer = new CustomTimingsHandler("** tickTileEntity"); + + public static final CustomTimingsHandler timerEntityBaseTick = new CustomTimingsHandler("** livingEntityBaseTick"); + public static final CustomTimingsHandler timerEntityAI = new CustomTimingsHandler("** livingEntityAI"); + public static final CustomTimingsHandler timerEntityAICollision = new CustomTimingsHandler("** livingEntityAICollision"); + public static final CustomTimingsHandler timerEntityAIMove = new CustomTimingsHandler("** livingEntityAIMove"); + public static final CustomTimingsHandler timerEntityTickRest = new CustomTimingsHandler("** livingEntityTickRest"); + + public static final CustomTimingsHandler processQueueTimer = new CustomTimingsHandler("processQueue"); + public static final CustomTimingsHandler schedulerSyncTimer = new CustomTimingsHandler("** Scheduler - Sync Tasks", JavaPluginLoader.pluginParentTimer); + + public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand"); + + public static final HashMap entityTypeTimingMap = new HashMap(); + public static final HashMap tileEntityTypeTimingMap = new HashMap(); + public static final HashMap pluginTaskTimingMap = new HashMap(); + + /** + * Gets a timer associated with a plugins tasks. + * @param task + * @param period + * @return + */ + public static CustomTimingsHandler getPluginTaskTimings(BukkitTask task, long period) { + if (!task.isSync()) { + return null; + } + String plugin; + final CraftTask ctask = (CraftTask) task; + + if (task.getOwner() != null) { + plugin = task.getOwner().getDescription().getFullName(); + } else { + plugin = "Unknown"; + } + String taskname = ctask.getTaskName(); + + String name = "Task: " + plugin + " Runnable: " + taskname; + if (period > 0) { + name += "(interval:" + period + ")"; + } else { + name += "(Single)"; + } + CustomTimingsHandler result = pluginTaskTimingMap.get(name); + if (result == null) { + result = new CustomTimingsHandler(name, SpigotTimings.schedulerSyncTimer); + pluginTaskTimingMap.put(name, result); + } + return result; + } + + /** + * Get a named timer for the specified entity type to track type specific timings. + * @param entity + * @return + */ + public static CustomTimingsHandler getEntityTimings(Entity entity) { + String entityType = entity.getClass().getName(); + CustomTimingsHandler result = entityTypeTimingMap.get(entityType); + if (result == null) { + result = new CustomTimingsHandler("** tickEntity - " + entity.getClass().getSimpleName(), activatedEntityTimer); + entityTypeTimingMap.put(entityType, result); + } + return result; + } + + /** + * Get a named timer for the specified tile entity type to track type specific timings. + * @param entity + * @return + */ + public static CustomTimingsHandler getTileEntityTimings(TileEntity entity) { + String entityType = entity.getClass().getName(); + CustomTimingsHandler result = tileEntityTypeTimingMap.get(entityType); + if (result == null) { + result = new CustomTimingsHandler("** tickTileEntity - " + entity.getClass().getSimpleName(), tickTileEntityTimer); + tileEntityTypeTimingMap.put(entityType, result); + } + return result; + } + + /** + * Set of timers per world, to track world specific timings. + */ + public static class WorldTimingsHandler { + public final CustomTimingsHandler mobSpawn; + public final CustomTimingsHandler doChunkUnload; + public final CustomTimingsHandler doTickPending; + public final CustomTimingsHandler doTickTiles; + public final CustomTimingsHandler doChunkMap; + public final CustomTimingsHandler doSounds; + public final CustomTimingsHandler entityTick; + public final CustomTimingsHandler tileEntityTick; + public final CustomTimingsHandler tileEntityPending; + public final CustomTimingsHandler tracker; + public final CustomTimingsHandler doTick; + public final CustomTimingsHandler tickEntities; + + public final CustomTimingsHandler syncChunkLoadTimer; + public final CustomTimingsHandler syncChunkLoadStructuresTimer; + public final CustomTimingsHandler syncChunkLoadEntitiesTimer; + public final CustomTimingsHandler syncChunkLoadTileEntitiesTimer; + public final CustomTimingsHandler syncChunkLoadTileTicksTimer; + public final CustomTimingsHandler syncChunkLoadPostTimer; + + public WorldTimingsHandler(World server) { + String name = ((WorldDataServer) server.levelData).getLevelName() + " - "; + + mobSpawn = new CustomTimingsHandler("** " + name + "mobSpawn"); + doChunkUnload = new CustomTimingsHandler("** " + name + "doChunkUnload"); + doTickPending = new CustomTimingsHandler("** " + name + "doTickPending"); + doTickTiles = new CustomTimingsHandler("** " + name + "doTickTiles"); + doChunkMap = new CustomTimingsHandler("** " + name + "doChunkMap"); + doSounds = new CustomTimingsHandler("** " + name + "doSounds"); + entityTick = new CustomTimingsHandler("** " + name + "entityTick"); + tileEntityTick = new CustomTimingsHandler("** " + name + "tileEntityTick"); + tileEntityPending = new CustomTimingsHandler("** " + name + "tileEntityPending"); + + syncChunkLoadTimer = new CustomTimingsHandler("** " + name + "syncChunkLoad"); + syncChunkLoadStructuresTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Structures"); + syncChunkLoadEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Entities"); + syncChunkLoadTileEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileEntities"); + syncChunkLoadTileTicksTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileTicks"); + syncChunkLoadPostTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Post"); + + + tracker = new CustomTimingsHandler(name + "tracker"); + doTick = new CustomTimingsHandler(name + "doTick"); + tickEntities = new CustomTimingsHandler(name + "tickEntities"); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index cd43b4551..4f8a30657 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -411,7 +411,9 @@ public class CraftScheduler implements BukkitScheduler { if (task.isSync()) { currentTask = task; try { + task.timings.startTiming(); // Spigot task.run(); + task.timings.stopTiming(); // Spigot } catch (final Throwable throwable) { task.getOwner().getLogger().log( Level.WARNING, diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java index c885bc744..70794669f 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java @@ -5,7 +5,10 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; -class CraftTask implements BukkitTask, Runnable { +import org.bukkit.craftbukkit.SpigotTimings; // Spigot +import org.spigotmc.CustomTimingsHandler; // Spigot + +public class CraftTask implements BukkitTask, Runnable { // Spigot private volatile CraftTask next = null; public static final int ERROR = 0; @@ -29,6 +32,7 @@ class CraftTask implements BukkitTask, Runnable { private final int id; private final long createdAt = System.nanoTime(); + final CustomTimingsHandler timings; // Spigot CraftTask() { this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); } @@ -54,6 +58,7 @@ class CraftTask implements BukkitTask, Runnable { } this.id = id; this.period = period; + this.timings = this.isSync() ? SpigotTimings.getPluginTaskTimings(this, period) : null; // Spigot } @Override @@ -131,4 +136,10 @@ class CraftTask implements BukkitTask, Runnable { setPeriod(CraftTask.CANCEL); return true; } + + // Spigot start + public String getTaskName() { + return (getTaskClass() == null) ? "Unknown" : getTaskClass().getName(); + } + // Spigot end } -- 2.34.1