From ce8a2dd0c03e01f056bdd9f7a933afd08959efff Mon Sep 17 00:00:00 2001 From: Woder <17339354+wode490390@users.noreply.github.com> Date: Sun, 9 Jul 2023 15:53:49 +0800 Subject: [PATCH] Remove Timings --- src/main/java/cn/nukkit/Player.java | 22 +- src/main/java/cn/nukkit/Server.java | 16 - .../cn/nukkit/blockentity/BlockEntity.java | 4 - .../blockentity/BlockEntityBrewingStand.java | 3 - .../blockentity/BlockEntityCampfire.java | 3 - .../blockentity/BlockEntityFurnace.java | 3 - src/main/java/cn/nukkit/command/Command.java | 6 - .../cn/nukkit/command/SimpleCommandMap.java | 3 - .../command/defaults/TimingsCommand.java | 74 ----- .../java/cn/nukkit/console/NukkitConsole.java | 3 - src/main/java/cn/nukkit/entity/Entity.java | 27 -- .../java/cn/nukkit/entity/EntityHanging.java | 3 - .../java/cn/nukkit/entity/EntityLiving.java | 5 - .../nukkit/entity/item/EntityExpBottle.java | 4 - .../entity/item/EntityFallingBlock.java | 3 - .../cn/nukkit/entity/item/EntityFirework.java | 5 - .../cn/nukkit/entity/item/EntityItem.java | 4 - .../nukkit/entity/item/EntityMinecartTNT.java | 5 - .../cn/nukkit/entity/item/EntityPotion.java | 3 - .../nukkit/entity/item/EntityPrimedTNT.java | 4 - .../entity/passive/EntityAbstractHorse.java | 4 - .../nukkit/entity/projectile/EntityArrow.java | 4 - .../entity/projectile/EntityEnderPearl.java | 4 - .../entity/projectile/EntitySnowball.java | 4 - src/main/java/cn/nukkit/level/Level.java | 47 --- .../cn/nukkit/level/format/anvil/Anvil.java | 2 - .../level/format/generic/BaseFullChunk.java | 4 - .../nukkit/level/format/leveldb/LevelDB.java | 6 - .../level/format/mcregion/McRegion.java | 2 - .../nukkit/network/protocol/ProtocolInfo.java | 5 +- .../nukkit/permission/DefaultPermissions.java | 1 - .../cn/nukkit/permission/PermissibleBase.java | 4 - .../java/cn/nukkit/plugin/PluginManager.java | 7 +- .../cn/nukkit/plugin/RegisteredListener.java | 8 +- .../java/cn/nukkit/scheduler/AsyncTask.java | 3 - .../cn/nukkit/scheduler/ServerScheduler.java | 2 - .../java/cn/nukkit/scheduler/TaskHandler.java | 6 - src/main/java/cn/nukkit/timings/JsonUtil.java | 73 ----- .../java/cn/nukkit/timings/LevelTimings.java | 49 ---- .../aikar/timings/FullServerTickTiming.java | 108 ------- src/main/java/co/aikar/timings/Timing.java | 182 ------------ .../java/co/aikar/timings/TimingData.java | 91 ------ .../co/aikar/timings/TimingIdentifier.java | 83 ------ src/main/java/co/aikar/timings/Timings.java | 259 ----------------- .../java/co/aikar/timings/TimingsExport.java | 274 ------------------ .../java/co/aikar/timings/TimingsHistory.java | 221 -------------- .../co/aikar/timings/TimingsHistoryEntry.java | 53 ---- .../java/co/aikar/timings/TimingsManager.java | 138 --------- src/main/resources/texts/en_US.lang | 16 - 49 files changed, 7 insertions(+), 1853 deletions(-) delete mode 100644 src/main/java/cn/nukkit/command/defaults/TimingsCommand.java delete mode 100644 src/main/java/cn/nukkit/timings/JsonUtil.java delete mode 100644 src/main/java/cn/nukkit/timings/LevelTimings.java delete mode 100644 src/main/java/co/aikar/timings/FullServerTickTiming.java delete mode 100644 src/main/java/co/aikar/timings/Timing.java delete mode 100644 src/main/java/co/aikar/timings/TimingData.java delete mode 100644 src/main/java/co/aikar/timings/TimingIdentifier.java delete mode 100644 src/main/java/co/aikar/timings/Timings.java delete mode 100644 src/main/java/co/aikar/timings/TimingsExport.java delete mode 100644 src/main/java/co/aikar/timings/TimingsHistory.java delete mode 100644 src/main/java/co/aikar/timings/TimingsHistoryEntry.java delete mode 100644 src/main/java/co/aikar/timings/TimingsManager.java diff --git a/src/main/java/cn/nukkit/Player.java b/src/main/java/cn/nukkit/Player.java index 086b609be4f..01cb237d008 100644 --- a/src/main/java/cn/nukkit/Player.java +++ b/src/main/java/cn/nukkit/Player.java @@ -79,8 +79,6 @@ import cn.nukkit.resourcepacks.ResourcePack; import cn.nukkit.scheduler.AsyncTask; import cn.nukkit.utils.*; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.primitives.Floats; @@ -953,14 +951,11 @@ protected void sendNextChunk() { return; } - Timings.playerChunkSendTimer.startTiming(); - this.sendQueuedChunk(); if ((this.canDoFirstSpawn() || System.currentTimeMillis() - this.creationTime > 15000) && !this.spawned && this.teleportPosition == null) { this.doFirstSpawn(); } - Timings.playerChunkSendTimer.stopTiming(); } protected boolean canDoFirstSpawn() { @@ -1127,8 +1122,6 @@ protected boolean orderChunks() { return false; } - Timings.playerChunkOrderTimer.startTiming(); - this.nextChunkOrderRun = 200; loadQueue.clear(); @@ -1161,7 +1154,6 @@ protected boolean orderChunks() { this.unloadChunk(Level.getHashX(index), Level.getHashZ(index)); } - Timings.playerChunkOrderTimer.stopTiming(); return true; } @@ -1182,7 +1174,7 @@ public boolean dataPacket(DataPacket packet) { return false; } - try (Timing timing = Timings.getSendDataPacketTiming(packet)) { + { DataPacketSendEvent ev = new DataPacketSendEvent(this, packet); this.server.getPluginManager().callEvent(ev); if (ev.isCancelled()) { @@ -1507,8 +1499,6 @@ public boolean fastMove(double dx, double dy, double dz) { return true; } - Timings.entityMoveTimer.startTiming(); - AxisAlignedBB newBB = this.boundingBox.getOffsetBoundingBox(dx, dy, dz); if (this.isSpectator() || server.getAllowFlight() || !this.level.hasCollision(this, newBB, false)) { @@ -1554,7 +1544,6 @@ public boolean fastMove(double dx, double dy, double dz) { this.motionZ = dz;*/ } - Timings.entityMoveTimer.stopTiming(); return true; } @@ -2020,8 +2009,6 @@ public void checkInteractNearby() { * @return Entity|null either NULL if no entity is found or an instance of the entity */ public EntityInteractable getEntityPlayerLookingAt(int maxDistance) { - timing.startTiming(); - EntityInteractable entity = null; // just a fix because player MAY not be fully initialized @@ -2046,7 +2033,6 @@ public EntityInteractable getEntityPlayerLookingAt(int maxDistance) { } } - timing.stopTiming(); return entity; } @@ -2346,16 +2332,14 @@ public void handleDataPacket(DataPacket packet) { return; } - try (Timing timing = Timings.getReceiveDataPacketTiming(packet)) { + { DataPacketReceiveEvent ev = new DataPacketReceiveEvent(this, packet); this.server.getPluginManager().callEvent(ev); if (ev.isCancelled()) { - timing.stopTiming(); return; } if (packet.pid() == ProtocolInfo.BATCH_PACKET) { - timing.stopTiming(); // this.server.getNetwork().processBatch((BatchPacket) packet, this); // Batch packets are already decoded in Synapse onPacketViolation(PacketViolationReason.NESTED_BATCH); @@ -3110,9 +3094,7 @@ public void onCompletion(Server server) { break; } - Timings.playerCommandTimer.startTiming(); this.server.dispatchCommand(playerCommandPreprocessEvent.getPlayer(), playerCommandPreprocessEvent.getMessage().substring(1)); - Timings.playerCommandTimer.stopTiming(); break; case ProtocolInfo.TEXT_PACKET: if (!this.spawned || !this.isAlive()) { diff --git a/src/main/java/cn/nukkit/Server.java b/src/main/java/cn/nukkit/Server.java index d50435e8c72..f6b97ee05bb 100755 --- a/src/main/java/cn/nukkit/Server.java +++ b/src/main/java/cn/nukkit/Server.java @@ -71,7 +71,6 @@ import cn.nukkit.scheduler.ServerScheduler; import cn.nukkit.utils.*; import cn.nukkit.utils.bugreport.ExceptionHandler; -import co.aikar.timings.Timings; import com.dosse.upnp.UPnP; import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; @@ -659,12 +658,10 @@ public void batchPackets(Player[] players, DataPacket[] packets, boolean forceSy if (players == null || packets == null || players.length == 0 || packets.length == 0) { return; } - Timings.playerNetworkSendTimer.startTiming(); BatchPacketsEvent ev = new BatchPacketsEvent(players, packets, forceSync); getPluginManager().callEvent(ev); if (ev.isCancelled()) { - Timings.playerNetworkSendTimer.stopTiming(); return; } @@ -700,7 +697,6 @@ public void batchPackets(Player[] players, DataPacket[] packets, boolean forceSy throw new RuntimeException(e); } } - Timings.playerNetworkSendTimer.stopTiming(); } public void broadcastPacketsCallback(byte[] data, List targets) { @@ -804,7 +800,6 @@ public void reload() { this.pluginManager.loadPlugins(this.pluginPath); this.enablePlugins(PluginLoadOrder.STARTUP); this.enablePlugins(PluginLoadOrder.POSTWORLD); - Timings.reset(); } public void shutdown() { @@ -861,8 +856,6 @@ public void forceShutdown() { this.network.unregisterInterface(interfaz); } - log.debug("Disabling timings"); - Timings.stopServer(); if (this.watchdog != null) { this.watchdog.kill(); } @@ -1125,7 +1118,6 @@ private void checkTickUpdates(int currentTick, long tickTime) { public void doAutoSave() { if (this.getAutoSave()) { - Timings.levelSaveTimer.startTiming(); for (Player player : new ArrayList<>(this.players.values())) { if (player.isOnline()) { player.save(true); @@ -1137,7 +1129,6 @@ public void doAutoSave() { for (Level level : this.getLevels().values()) { level.save(); } - Timings.levelSaveTimer.stopTiming(); } } @@ -1148,21 +1139,15 @@ private boolean tick() { return false; } - Timings.fullServerTickTimer.startTiming(); - ++this.tickCounter; - Timings.connectionTimer.startTiming(); this.network.processInterfaces(); if (this.rcon != null) { this.rcon.check(); } - Timings.connectionTimer.stopTiming(); - Timings.schedulerTimer.startTiming(); this.scheduler.mainThreadHeartbeat(this.tickCounter); - Timings.schedulerTimer.stopTiming(); this.checkTickUpdates(this.tickCounter, tickTime); @@ -1206,7 +1191,6 @@ private boolean tick() { } } - Timings.fullServerTickTimer.stopTiming(); //long now = System.currentTimeMillis(); long nowNano = System.nanoTime(); //float tick = Math.min(20, 1000 / Math.max(1, now - tickTime)); diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntity.java b/src/main/java/cn/nukkit/blockentity/BlockEntity.java index cfe243ec977..93ba0bdf2ed 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntity.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntity.java @@ -8,8 +8,6 @@ import cn.nukkit.math.Vector3; import cn.nukkit.nbt.tag.CompoundTag; import cn.nukkit.utils.ChunkException; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import lombok.extern.log4j.Log4j2; @@ -36,14 +34,12 @@ public abstract class BlockEntity extends Position implements BlockEntityID { protected int lastUpdate; protected Server server; - protected Timing timing; public BlockEntity(FullChunk chunk, CompoundTag nbt) { if (chunk == null || chunk.getProvider() == null) { throw new ChunkException("Invalid garbage Chunk given to Block Entity"); } - this.timing = Timings.getBlockEntityTiming(this); this.server = chunk.getProvider().getLevel().getServer(); this.chunk = chunk; this.setLevel(chunk.getProvider().getLevel()); diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java b/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java index 1330d98f444..7dcabcb0955 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java @@ -162,7 +162,6 @@ public boolean onUpdate() { return true; } lastUpdate = currentTick; - timing.startTiming(); boolean hasUpdate = false; @@ -208,7 +207,6 @@ public boolean onUpdate() { this.server.getPluginManager().callEvent(e); if (e.isCancelled()) { brewing = false; - timing.stopTiming(); return false; } } @@ -257,7 +255,6 @@ public boolean onUpdate() { } brewing = canBrew; - timing.stopTiming(); return hasUpdate; } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityCampfire.java b/src/main/java/cn/nukkit/blockentity/BlockEntityCampfire.java index a0558ed88ce..94b6a045d61 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityCampfire.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityCampfire.java @@ -87,10 +87,8 @@ public boolean onUpdate() { return true; } lastUpdate = currentTick; - timing.startTiming(); if (!canCooking()) { - timing.stopTiming(); return false; } @@ -140,7 +138,6 @@ public boolean onUpdate() { level.addLevelSoundEvent(add(0.5, 0.2, 0.5), LevelSoundEventPacket.SOUND_BLOCK_CAMPFIRE_CRACKLE); } - timing.stopTiming(); return true; } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java b/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java index 9664d2f61de..2487c20be19 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java @@ -227,7 +227,6 @@ public boolean onUpdate() { return true; } lastUpdate = currentTick; - this.timing.startTiming(); boolean ret = false; Item fuel = this.inventory.getFuel(); @@ -310,8 +309,6 @@ public boolean onUpdate() { } } - this.timing.stopTiming(); - return ret; } diff --git a/src/main/java/cn/nukkit/command/Command.java b/src/main/java/cn/nukkit/command/Command.java index 59fad6c4cef..0781f1bc0e8 100644 --- a/src/main/java/cn/nukkit/command/Command.java +++ b/src/main/java/cn/nukkit/command/Command.java @@ -7,8 +7,6 @@ import cn.nukkit.lang.TranslationContainer; import cn.nukkit.permission.Permissible; import cn.nukkit.utils.TextFormat; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -44,8 +42,6 @@ public abstract class Command { protected Map commandParameters = new Object2ObjectOpenHashMap<>(); - public Timing timing; - public Command(String name) { this(name, "", null, new String[0]); } @@ -72,7 +68,6 @@ public Command(String name, String description, String usageMessage, String... a } this.aliases = aliases; this.activeAliases = aliases; - this.timing = Timings.getCommandTiming(this); this.commandParameters.put("default", new CommandParameter[]{CommandParameter.newType("args", true, CommandParamType.RAWTEXT)}); } @@ -191,7 +186,6 @@ public boolean setLabel(String name) { this.nextLabel = name; if (!this.isRegistered()) { this.label = name; - this.timing = Timings.getCommandTiming(this); return true; } return false; diff --git a/src/main/java/cn/nukkit/command/SimpleCommandMap.java b/src/main/java/cn/nukkit/command/SimpleCommandMap.java index fc8e43821fc..fd591da58c9 100644 --- a/src/main/java/cn/nukkit/command/SimpleCommandMap.java +++ b/src/main/java/cn/nukkit/command/SimpleCommandMap.java @@ -90,7 +90,6 @@ private void setDefaultCommands() { // if ((boolean) this.server.getConfig("debug.commands", false)) { this.register("nukkit", new StatusCommand("status")); this.register("nukkit", new GarbageCollectorCommand("gc")); - this.register("nukkit", new TimingsCommand("timings")); //this.register("nukkit", new DumpMemoryCommand("dumpmemory")); // } @@ -274,7 +273,6 @@ public boolean dispatch(CommandSender sender, String cmdLine) { return false; } - target.timing.startTiming(); try { target.execute(sender, sentCommandLabel, args); } catch (Exception e) { @@ -285,7 +283,6 @@ public boolean dispatch(CommandSender sender, String cmdLine) { logger.logException(e); } } - target.timing.stopTiming(); return true; } diff --git a/src/main/java/cn/nukkit/command/defaults/TimingsCommand.java b/src/main/java/cn/nukkit/command/defaults/TimingsCommand.java deleted file mode 100644 index beb9354e2ba..00000000000 --- a/src/main/java/cn/nukkit/command/defaults/TimingsCommand.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.nukkit.command.defaults; - -import cn.nukkit.command.CommandSender; -import cn.nukkit.command.data.CommandEnum; -import cn.nukkit.command.data.CommandParameter; -import cn.nukkit.lang.TranslationContainer; -import co.aikar.timings.Timings; -import co.aikar.timings.TimingsExport; - -/** - * @author fromgate - * @author Pub4Game - */ -public class TimingsCommand extends VanillaCommand { - - public TimingsCommand(String name) { - super(name, "%nukkit.command.timings.description", "%nukkit.command.timings.usage"); - this.setPermission("nukkit.command.timings"); - this.commandParameters.clear(); - this.commandParameters.put("default", new CommandParameter[]{ - CommandParameter.newEnum("action", new CommandEnum("TimingsAction", "on", "off", "paste", "verbon", "verboff", "reset", "report")) - }); - } - - @Override - public boolean execute(CommandSender sender, String commandLabel, String[] args) { - if (!this.testPermission(sender)) { - return true; - } - - if (args.length != 1) { - sender.sendMessage(new TranslationContainer("commands.generic.usage", usageMessage)); - return true; - } - - String mode = args[0].toLowerCase(); - - if (mode.equals("on")) { - Timings.setTimingsEnabled(true); - Timings.reset(); - sender.sendMessage(new TranslationContainer("nukkit.command.timings.enable")); - return true; - } else if (mode.equals("off")) { - Timings.setTimingsEnabled(false); - sender.sendMessage(new TranslationContainer("nukkit.command.timings.disable")); - return true; - } - - if (!Timings.isTimingsEnabled()) { - sender.sendMessage(new TranslationContainer("nukkit.command.timings.timingsDisabled")); - return true; - } - - switch (mode) { - case "verbon": - sender.sendMessage(new TranslationContainer("nukkit.command.timings.verboseEnable")); - Timings.setVerboseEnabled(true); - break; - case "verboff": - sender.sendMessage(new TranslationContainer("nukkit.command.timings.verboseDisable")); - Timings.setVerboseEnabled(true); - break; - case "reset": - Timings.reset(); - sender.sendMessage(new TranslationContainer("nukkit.command.timings.reset")); - break; - case "report": - case "paste": - TimingsExport.reportTimings(sender); - break; - } - return true; - } -} diff --git a/src/main/java/cn/nukkit/console/NukkitConsole.java b/src/main/java/cn/nukkit/console/NukkitConsole.java index a2cce94ff8d..d8865810b44 100644 --- a/src/main/java/cn/nukkit/console/NukkitConsole.java +++ b/src/main/java/cn/nukkit/console/NukkitConsole.java @@ -4,7 +4,6 @@ import cn.nukkit.command.CommandSender; import cn.nukkit.event.server.ServerCommandEvent; import cn.nukkit.event.server.ServerInterruptEvent; -import co.aikar.timings.Timings; import net.minecrell.terminalconsole.SimpleTerminalConsole; import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; @@ -34,7 +33,6 @@ protected void runCommand(String command) { if (sender == null) { return; } - Timings.serverCommandTimer.startTiming(); ServerCommandEvent event = new ServerCommandEvent(sender, command); if (server.getPluginManager() != null) { server.getPluginManager().callEvent(event); @@ -42,7 +40,6 @@ protected void runCommand(String command) { if (!event.isCancelled()) { Server.getInstance().getScheduler().scheduleTask(() -> server.dispatchCommand(event.getSender(), event.getCommand())); } - Timings.serverCommandTimer.stopTiming(); } else { consoleQueue.add(command); } diff --git a/src/main/java/cn/nukkit/entity/Entity.java b/src/main/java/cn/nukkit/entity/Entity.java index 5390423a2cb..d181697a68f 100644 --- a/src/main/java/cn/nukkit/entity/Entity.java +++ b/src/main/java/cn/nukkit/entity/Entity.java @@ -32,10 +32,6 @@ import cn.nukkit.plugin.Plugin; import cn.nukkit.potion.Effect; import cn.nukkit.utils.ChunkException; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; -import co.aikar.timings.TimingsHistory; -import co.aikar.timings.TimingsManager; import com.google.common.collect.Iterables; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -485,12 +481,8 @@ public abstract class Entity extends Location implements Metadatable { public boolean closed = false; - protected Timing timing; - protected boolean isPlayer = false; - private final Timing fullEntityUpdateTiming; - private volatile boolean initialized; public float getHeight() { @@ -530,7 +522,6 @@ protected float getBaseOffset() { } public Entity(FullChunk chunk, CompoundTag nbt) { - this.fullEntityUpdateTiming = TimingsManager.getTiming("FullEntityUpdate - " + this.getClass().getName()); if (this instanceof Player) { return; } @@ -595,8 +586,6 @@ protected final void init(FullChunk chunk, CompoundTag nbt) { } this.initialized = true; - this.timing = Timings.getEntityTiming(this); - this.isPlayer = this instanceof Player; this.temporalVector = new Vector3(); @@ -1525,8 +1514,6 @@ public boolean entityBaseTick() { } public boolean entityBaseTick(int tickDiff) { - Timings.entityBaseTickTimer.startTiming(); - if (!this.isPlayer) { this.blocksAround = null; this.collisionBlocks = null; @@ -1539,7 +1526,6 @@ public boolean entityBaseTick(int tickDiff) { if (!this.isPlayer) { this.close(); } - Timings.entityBaseTickTimer.stopTiming(); return false; } if (riding != null && !riding.isAlive() && riding instanceof EntityRideable) { @@ -1606,9 +1592,7 @@ public boolean entityBaseTick(int tickDiff) { this.age += tickDiff; this.ticksLived += tickDiff; - TimingsHistory.activatedEntityTicks++; - Timings.entityBaseTickTimer.stopTiming(); return hasUpdate; } @@ -1681,8 +1665,6 @@ public boolean onUpdate(int currentTick) { return false; } - this.fullEntityUpdateTiming.startTiming(); - if (!this.isAlive()) { ++this.deadTicks; if (this.deadTicks >= 10) { @@ -1706,8 +1688,6 @@ public boolean onUpdate(int currentTick) { this.updateMovement(); - this.fullEntityUpdateTiming.stopTiming(); - return hasUpdate; } @@ -2139,8 +2119,6 @@ public boolean fastMove(double dx, double dy, double dz) { return true; } - Timings.entityMoveTimer.startTiming(); - AxisAlignedBB newBB = this.boundingBox.getOffsetBoundingBox(dx, dy, dz); if (server.getAllowFlight() || !this.level.hasCollision(this, newBB, false)) { @@ -2164,7 +2142,6 @@ public boolean fastMove(double dx, double dy, double dz) { /*this.motionX = dx; this.motionY = dy; this.motionZ = dz;*/ - Timings.entityMoveTimer.stopTiming(); return true; } @@ -2179,9 +2156,6 @@ public boolean move(double dx, double dy, double dz) { this.onGround = this.isPlayer; return true; } else { - - Timings.entityMoveTimer.startTiming(); - this.ySize *= 0.4; double movX = dx; @@ -2279,7 +2253,6 @@ public boolean move(double dx, double dy, double dz) { } //TODO: vehicle collision events (first we need to spawn them!) - Timings.entityMoveTimer.stopTiming(); return true; } } diff --git a/src/main/java/cn/nukkit/entity/EntityHanging.java b/src/main/java/cn/nukkit/entity/EntityHanging.java index 16b6028bc46..8eac06fad9d 100644 --- a/src/main/java/cn/nukkit/entity/EntityHanging.java +++ b/src/main/java/cn/nukkit/entity/EntityHanging.java @@ -37,8 +37,6 @@ public boolean onUpdate(int currentTick) { } this.lastUpdate = currentTick; - this.timing.startTiming(); - if (!this.isAlive()) { this.close(); } else if ((this.checkInterval += tickDiff) >= 100) { @@ -50,7 +48,6 @@ public boolean onUpdate(int currentTick) { } } - this.timing.stopTiming(); return true; } diff --git a/src/main/java/cn/nukkit/entity/EntityLiving.java b/src/main/java/cn/nukkit/entity/EntityLiving.java index ef1aa57470d..6590d8895f6 100644 --- a/src/main/java/cn/nukkit/entity/EntityLiving.java +++ b/src/main/java/cn/nukkit/entity/EntityLiving.java @@ -23,7 +23,6 @@ import cn.nukkit.network.protocol.EntityEventPacket; import cn.nukkit.potion.Effect; import cn.nukkit.utils.BlockIterator; -import co.aikar.timings.Timings; import java.util.ArrayList; import java.util.Arrays; @@ -268,8 +267,6 @@ public boolean entityBaseTick() { @Override public boolean entityBaseTick(int tickDiff) { - Timings.livingEntityBaseTickTimer.startTiming(); - boolean hasUpdate = super.entityBaseTick(tickDiff); if (this.isAlive() && this.needLivingBaseTick) { @@ -381,8 +378,6 @@ public boolean entityBaseTick(int tickDiff) { } } - Timings.livingEntityBaseTickTimer.stopTiming(); - return hasUpdate; } diff --git a/src/main/java/cn/nukkit/entity/item/EntityExpBottle.java b/src/main/java/cn/nukkit/entity/item/EntityExpBottle.java index fd9772c4b85..7c25d9a07ff 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityExpBottle.java +++ b/src/main/java/cn/nukkit/entity/item/EntityExpBottle.java @@ -63,8 +63,6 @@ public boolean onUpdate(int currentTick) { return false; } - this.timing.startTiming(); - boolean hasUpdate = super.onUpdate(currentTick); if (this.age > 1200) { @@ -84,8 +82,6 @@ public boolean onUpdate(int currentTick) { this.getLevel().dropExpOrb(this, ThreadLocalRandom.current().nextInt(3, 12)); } - this.timing.stopTiming(); - return hasUpdate; } diff --git a/src/main/java/cn/nukkit/entity/item/EntityFallingBlock.java b/src/main/java/cn/nukkit/entity/item/EntityFallingBlock.java index ee0b17d9d5e..10c40c350dd 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityFallingBlock.java +++ b/src/main/java/cn/nukkit/entity/item/EntityFallingBlock.java @@ -122,7 +122,6 @@ public boolean onUpdate(int currentTick) { return true; } lastUpdate = currentTick; - this.timing.startTiming(); boolean hasUpdate = entityBaseTick(tickDiff); @@ -236,8 +235,6 @@ public boolean onUpdate(int currentTick) { updateMovement(); } - this.timing.stopTiming(); - return hasUpdate || !onGround || Math.abs(motionX) > 0.00001 || Math.abs(motionY) > 0.00001 || Math.abs(motionZ) > 0.00001; } diff --git a/src/main/java/cn/nukkit/entity/item/EntityFirework.java b/src/main/java/cn/nukkit/entity/item/EntityFirework.java index c661696ce48..1effd83b8a3 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityFirework.java +++ b/src/main/java/cn/nukkit/entity/item/EntityFirework.java @@ -76,9 +76,6 @@ public boolean onUpdate(int currentTick) { this.lastUpdate = currentTick; - this.timing.startTiming(); - - boolean hasUpdate = this.entityBaseTick(tickDiff); if (this.isAlive()) { @@ -119,8 +116,6 @@ public boolean onUpdate(int currentTick) { } } - this.timing.stopTiming(); - return hasUpdate || !this.onGround || Math.abs(this.motionX) > 0.00001 || Math.abs(this.motionY) > 0.00001 || Math.abs(this.motionZ) > 0.00001; } diff --git a/src/main/java/cn/nukkit/entity/item/EntityItem.java b/src/main/java/cn/nukkit/entity/item/EntityItem.java index c9ff80bed07..de5ff1822a5 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityItem.java +++ b/src/main/java/cn/nukkit/entity/item/EntityItem.java @@ -180,8 +180,6 @@ public boolean onUpdate(int currentTick) { this.lastUpdate = currentTick; - this.timing.startTiming(); - if (this.age % 60 == 0 && this.onGround && this.pickupDelay <= 0 && this.getItem() != null && this.isAlive()) { if (this.getItem().getCount() < this.getItem().getMaxStackSize()) { for (Entity entity : this.getLevel().getNearbyEntities(getBoundingBox().grow(1, 1, 1), this)) { @@ -273,8 +271,6 @@ public boolean onUpdate(int currentTick) { } } - this.timing.stopTiming(); - return hasUpdate || this.age <= 60 || !this.onGround || Math.abs(this.motionX) > 0.00001 || Math.abs(this.motionY) > 0.00001 || Math.abs(this.motionZ) > 0.00001; } diff --git a/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java b/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java index ac47be04c6a..aee699582eb 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java +++ b/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java @@ -62,12 +62,9 @@ public boolean onUpdate(int currentTick) { return false; } - this.timing.startTiming(); - if (this.isPrimed()) { int tickDiff = currentTick - lastUpdate; if (tickDiff <= 0) { - this.timing.stopTiming(); return false; } @@ -84,12 +81,10 @@ public boolean onUpdate(int currentTick) { this.close(); } - this.timing.stopTiming(); return false; } } - this.timing.stopTiming(); return super.onUpdate(currentTick); } diff --git a/src/main/java/cn/nukkit/entity/item/EntityPotion.java b/src/main/java/cn/nukkit/entity/item/EntityPotion.java index e56ec87e87a..8cdd55c6a00 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityPotion.java +++ b/src/main/java/cn/nukkit/entity/item/EntityPotion.java @@ -201,8 +201,6 @@ public boolean onUpdate(int currentTick) { return false; } - this.timing.startTiming(); - boolean hasUpdate = super.onUpdate(currentTick); if (this.age > 1200) { @@ -213,7 +211,6 @@ public boolean onUpdate(int currentTick) { hasUpdate = true; } - this.timing.stopTiming(); return hasUpdate; } diff --git a/src/main/java/cn/nukkit/entity/item/EntityPrimedTNT.java b/src/main/java/cn/nukkit/entity/item/EntityPrimedTNT.java index 1a3f458819f..c92465e1a5c 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityPrimedTNT.java +++ b/src/main/java/cn/nukkit/entity/item/EntityPrimedTNT.java @@ -115,8 +115,6 @@ public boolean onUpdate(int currentTick) { } lastUpdate = currentTick; - this.timing.startTiming(); - this.setDataProperty(new IntEntityData(DATA_FUSE_LENGTH, fuse)); this.getLevel().addParticle(new SmokeParticle(this.add(0, 1, 0))); this.getLevel().addLevelSoundEvent(this, LevelSoundEventPacket.SOUND_FIZZ); @@ -152,8 +150,6 @@ public boolean onUpdate(int currentTick) { } } - this.timing.stopTiming(); - return hasUpdate || fuse >= 0 || Math.abs(motionX) > 0.00001 || Math.abs(motionY) > 0.00001 || Math.abs(motionZ) > 0.00001; } diff --git a/src/main/java/cn/nukkit/entity/passive/EntityAbstractHorse.java b/src/main/java/cn/nukkit/entity/passive/EntityAbstractHorse.java index f5e00851c36..23cbbe42782 100644 --- a/src/main/java/cn/nukkit/entity/passive/EntityAbstractHorse.java +++ b/src/main/java/cn/nukkit/entity/passive/EntityAbstractHorse.java @@ -146,8 +146,6 @@ public boolean onUpdate(int currentTick) { } this.lastUpdate = currentTick; - this.timing.startTiming(); - boolean hasUpdate = this.entityBaseTick(tickDiff); if (this.isAlive()) { @@ -172,8 +170,6 @@ public boolean onUpdate(int currentTick) { this.updateMovement(); } - this.timing.stopTiming(); - return hasUpdate || !this.onGround || Math.abs(this.motionX) > 0.00001 || Math.abs(this.motionY) > 0.00001 || Math.abs(this.motionZ) > 0.00001; } diff --git a/src/main/java/cn/nukkit/entity/projectile/EntityArrow.java b/src/main/java/cn/nukkit/entity/projectile/EntityArrow.java index 457f083fa1c..2f48cde29cb 100644 --- a/src/main/java/cn/nukkit/entity/projectile/EntityArrow.java +++ b/src/main/java/cn/nukkit/entity/projectile/EntityArrow.java @@ -130,8 +130,6 @@ public boolean onUpdate(int currentTick) { return false; } - this.timing.startTiming(); - boolean hasUpdate = super.onUpdate(currentTick); if (this.onGround || this.hadCollision) { @@ -151,8 +149,6 @@ public boolean onUpdate(int currentTick) { hasUpdate = true; } - this.timing.stopTiming(); - return hasUpdate; } diff --git a/src/main/java/cn/nukkit/entity/projectile/EntityEnderPearl.java b/src/main/java/cn/nukkit/entity/projectile/EntityEnderPearl.java index e8ce85a56ea..5dafb282b2a 100644 --- a/src/main/java/cn/nukkit/entity/projectile/EntityEnderPearl.java +++ b/src/main/java/cn/nukkit/entity/projectile/EntityEnderPearl.java @@ -60,8 +60,6 @@ public boolean onUpdate(int currentTick) { return false; } - this.timing.startTiming(); - boolean hasUpdate = super.onUpdate(currentTick); if (this.isCollided && this.shootingEntity instanceof Player) { @@ -81,8 +79,6 @@ public boolean onUpdate(int currentTick) { hasUpdate = true; } - this.timing.stopTiming(); - return hasUpdate; } diff --git a/src/main/java/cn/nukkit/entity/projectile/EntitySnowball.java b/src/main/java/cn/nukkit/entity/projectile/EntitySnowball.java index 3af3bfea1d2..7d0875e5fd4 100644 --- a/src/main/java/cn/nukkit/entity/projectile/EntitySnowball.java +++ b/src/main/java/cn/nukkit/entity/projectile/EntitySnowball.java @@ -57,8 +57,6 @@ public boolean onUpdate(int currentTick) { return false; } - this.timing.startTiming(); - boolean hasUpdate = super.onUpdate(currentTick); if (this.age > 1200 || this.isCollided) { @@ -66,8 +64,6 @@ public boolean onUpdate(int currentTick) { hasUpdate = true; } - this.timing.stopTiming(); - return hasUpdate; } diff --git a/src/main/java/cn/nukkit/level/Level.java b/src/main/java/cn/nukkit/level/Level.java index 8ca9f359830..b604d480296 100644 --- a/src/main/java/cn/nukkit/level/Level.java +++ b/src/main/java/cn/nukkit/level/Level.java @@ -57,10 +57,7 @@ import cn.nukkit.potion.Effect; import cn.nukkit.scheduler.AsyncTask; import cn.nukkit.scheduler.BlockUpdateScheduler; -import cn.nukkit.timings.LevelTimings; import cn.nukkit.utils.*; -import co.aikar.timings.Timings; -import co.aikar.timings.TimingsHistory; import com.google.common.base.Preconditions; import it.unimi.dsi.fastutil.chars.Char2ObjectMap; import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap; @@ -277,8 +274,6 @@ public int size() { private static final int LCG_CONSTANT = 1013904223; - public LevelTimings timings; - private int tickRate; public int tickRateTime = 0; public int tickRateCounter = 0; @@ -327,7 +322,6 @@ public Level(Server server, String name, String path, LevelProviderHandle provid this.autoSave = server.getAutoSave(); this.autoCompaction = server.isAutoCompactionEnabled(); this.folderName = name; - this.timings = new LevelTimings(this); this.updateQueue = new BlockUpdateScheduler(this, 0); this.randomUpdateQueue = new BlockUpdateScheduler(this, 0); Arrays.fill(lastChunkPos, ChunkPosition.INVALID_CHUNK_POSITION); @@ -1023,8 +1017,6 @@ public GameRules getGameRules() { } public void doTick(int currentTick) { - this.timings.doTick.startTiming(); - updateBlockLight(lightQueue); this.checkTime(); @@ -1078,13 +1070,11 @@ public void doTick(int currentTick) { this.levelCurrentTick++; this.unloadChunks(); - this.timings.doTickPending.startTiming(); this.updateQueue.tick(this.getCurrentTick()); if (gameRules.getInteger(GameRule.RANDOM_TICK_SPEED) > 0) { randomUpdateQueue.tick(getCurrentTick()); } - this.timings.doTickPending.stopTiming(); while (!this.normalUpdateQueue.isEmpty()) { Block block = getBlock(this.normalUpdateQueue.poll()); @@ -1106,9 +1096,6 @@ public void doTick(int currentTick) { } } - TimingsHistory.entityTicks += this.updateEntities.size(); - this.timings.entityTick.startTiming(); - if (!this.updateEntities.isEmpty()) { for (long id : new ObjectArrayList<>(this.updateEntities.keySet())) { Entity entity = this.updateEntities.get(id); @@ -1121,16 +1108,10 @@ public void doTick(int currentTick) { } } } - this.timings.entityTick.stopTiming(); - TimingsHistory.tileEntityTicks += this.updateBlockEntities.size(); - this.timings.blockEntityTick.startTiming(); this.updateBlockEntities.removeIf(blockEntity -> !blockEntity.isValid() || !blockEntity.onUpdate()); - this.timings.blockEntityTick.stopTiming(); - this.timings.tickChunks.startTiming(); this.tickChunks(); - this.timings.tickChunks.stopTiming(); synchronized (changedBlocks) { if (!this.changedBlocks.isEmpty()) { @@ -1191,8 +1172,6 @@ public void doTick(int currentTick) { Server.broadcastPacket(players.values().toArray(new Player[0]), packet); gameRules.refresh(); } - - this.timings.doTick.stopTiming(); } private void performThunder(long index, FullChunk chunk) { @@ -3011,7 +2990,6 @@ public void generateChunkCallback(int x, int z, BaseFullChunk chunk) { } public void generateChunkCallback(int x, int z, BaseFullChunk chunk, boolean isPopulated) { - Timings.generationCallbackTimer.startTiming(); long index = Level.chunkHash(x, z); boolean queuedGen; if (this.chunkPopulationQueue.remove(index)) { @@ -3042,7 +3020,6 @@ public void generateChunkCallback(int x, int z, BaseFullChunk chunk, boolean isP chunk.setProvider(this.provider); this.setChunk(x, z, chunk, false); } - Timings.generationCallbackTimer.stopTiming(); } @Override @@ -3250,7 +3227,6 @@ private void sendChunk(int x, int z, long index, int subChunkCount, ChunkBlobCac } private void processChunkRequest() { - this.timings.syncChunkSendTimer.startTiming(); Iterator it = this.chunkSendQueue.keySet().iterator(); while (it.hasNext()) { long index = it.next(); @@ -3280,14 +3256,11 @@ private void processChunkRequest() { continue; } } - this.timings.syncChunkSendPrepareTimer.startTiming(); AsyncTask task = this.provider.requestChunkTask(x, z); if (task != null) { this.server.getScheduler().scheduleAsyncTask(task); } - this.timings.syncChunkSendPrepareTimer.stopTiming(); } - this.timings.syncChunkSendTimer.stopTiming(); } public boolean isCacheChunks() { @@ -3299,7 +3272,6 @@ public boolean isCacheChunks() { * If this.cacheChunks == false, the ChunkPacketCache can be null; */ public void chunkRequestCallback(long timestamp, int x, int z, int subChunkCount, ChunkBlobCache chunkBlobCache, ChunkPacketCache chunkPacketCache, byte[] payload, byte[] payloadOld, byte[] subModePayload, byte[] subModePayloadNew, Map payloads, Map subChunkPayloads, byte[] heightMapType, byte[][] heightMapData, boolean[] emptySection) { - this.timings.syncChunkSendTimer.startTiming(); long index = Level.chunkHash(x, z); if (this.cacheChunks) { @@ -3368,7 +3340,6 @@ public void chunkRequestCallback(long timestamp, int x, int z, int subChunkCount } } - this.timings.syncChunkSendTimer.stopTiming(); return; } @@ -3406,8 +3377,6 @@ public void chunkRequestCallback(long timestamp, int x, int z, int subChunkCount player.sendSubChunks(this.getDimension().ordinal(), x, z, subChunkCount, chunkBlobCache, subChunkPayloads, heightMapType, heightMapData); } } - - this.timings.syncChunkSendTimer.stopTiming(); } public void removeEntity(Entity entity) { @@ -3503,14 +3472,11 @@ public boolean loadChunk(int x, int z, boolean generate) { } private boolean loadChunkInternal(long index, int x, int z, boolean generate) { - this.timings.syncChunkLoadTimer.startTiming(); - this.cancelUnloadChunkRequest(x, z); BaseFullChunk chunk = this.provider.getChunk(x, z, generate); if (chunk == null) { - this.timings.syncChunkLoadTimer.stopTiming(); if (generate) { throw new IllegalStateException("Could not create new Chunk"); } @@ -3524,7 +3490,6 @@ private boolean loadChunkInternal(long index, int x, int z, boolean generate) { this.server.getPluginManager().callEvent(new ChunkLoadEvent(chunk, !chunk.isGenerated())); } else { this.unloadChunk(x, z, false); - this.timings.syncChunkLoadTimer.stopTiming(); return false; } @@ -3540,7 +3505,6 @@ private boolean loadChunkInternal(long index, int x, int z, boolean generate) { } else { this.unloadChunkRequest(x, z); } - this.timings.syncChunkLoadTimer.stopTiming(); return true; } @@ -3585,8 +3549,6 @@ public boolean unloadChunk(int x, int z, boolean safe, boolean trySave) { return true; } - this.timings.doChunkUnload.startTiming(); - long index = Level.chunkHash(x, z); BaseFullChunk chunk = this.getChunk(x, z); @@ -3595,7 +3557,6 @@ public boolean unloadChunk(int x, int z, boolean safe, boolean trySave) { ChunkUnloadEvent ev = new ChunkUnloadEvent(chunk); this.server.getPluginManager().callEvent(ev); if (ev.isCancelled()) { - this.timings.doChunkUnload.stopTiming(); return false; } } @@ -3637,8 +3598,6 @@ public boolean unloadChunk(int x, int z, boolean safe, boolean trySave) { this.chunks.remove(index); this.chunkTickList.remove(index); - this.timings.doChunkUnload.stopTiming(); - return true; } @@ -3779,7 +3738,6 @@ public boolean populateChunk(int x, int z, boolean force) { BaseFullChunk chunk = this.getChunk(x, z, true); boolean populate; if (!chunk.isPopulated()) { - Timings.populationTimer.startTiming(); populate = true; for (int xx = -1; xx <= 1; ++xx) { for (int zz = -1; zz <= 1; ++zz) { @@ -3802,7 +3760,6 @@ public boolean populateChunk(int x, int z, boolean force) { this.server.getScheduler().scheduleAsyncTask(task); } } - Timings.populationTimer.stopTiming(); return false; } @@ -3820,10 +3777,8 @@ public void generateChunk(int x, int z, boolean force) { long index = Level.chunkHash(x, z); if (!this.chunkGenerationQueue.putIfAbsent(index, true)) { - Timings.generationTimer.startTiming(); GenerationTask task = new GenerationTask(this, this.getChunk(x, z, true)); this.server.getScheduler().scheduleAsyncTask(task); - Timings.generationTimer.stopTiming(); } } @@ -3836,7 +3791,6 @@ public void regenerateChunk(int x, int z) { } public void doChunkGarbageCollection() { - this.timings.doChunkGC.startTiming(); // remove all invaild block entities. List toClose = new ObjectArrayList<>(); for (BlockEntity anBlockEntity : blockEntities.values()) { @@ -3867,7 +3821,6 @@ public void doChunkGarbageCollection() { } this.provider.doGarbageCollection(); - this.timings.doChunkGC.stopTiming(); } public void unloadChunks() { diff --git a/src/main/java/cn/nukkit/level/format/anvil/Anvil.java b/src/main/java/cn/nukkit/level/format/anvil/Anvil.java index 786b3d15c05..eea5c1a1f31 100644 --- a/src/main/java/cn/nukkit/level/format/anvil/Anvil.java +++ b/src/main/java/cn/nukkit/level/format/anvil/Anvil.java @@ -154,7 +154,6 @@ public synchronized BaseFullChunk loadChunk(long index, int chunkX, int chunkZ, int regionX = getRegionIndexX(chunkX); int regionZ = getRegionIndexZ(chunkZ); BaseRegionLoader region = this.loadRegion(regionX, regionZ); - this.level.timings.syncChunkLoadDataTimer.startTiming(); BaseFullChunk chunk; try { chunk = region.readChunk(chunkX - regionX * 32, chunkZ - regionZ * 32); @@ -169,7 +168,6 @@ public synchronized BaseFullChunk loadChunk(long index, int chunkX, int chunkZ, } else { putChunk(index, chunk); } - this.level.timings.syncChunkLoadDataTimer.stopTiming(); return chunk; } diff --git a/src/main/java/cn/nukkit/level/format/generic/BaseFullChunk.java b/src/main/java/cn/nukkit/level/format/generic/BaseFullChunk.java index 54b93cd2a11..f3fadd4c15a 100644 --- a/src/main/java/cn/nukkit/level/format/generic/BaseFullChunk.java +++ b/src/main/java/cn/nukkit/level/format/generic/BaseFullChunk.java @@ -144,7 +144,6 @@ public void initChunk() { if (this.getProvider() != null && !this.isInit) { boolean changed = false; if (this.NBTentities != null) { - this.getProvider().getLevel().timings.syncChunkLoadEntitiesTimer.startTiming(); for (CompoundTag nbt : NBTentities) { if (!nbt.contains("id")) { this.setChanged(); @@ -160,12 +159,10 @@ public void initChunk() { changed = true; } } - this.getProvider().getLevel().timings.syncChunkLoadEntitiesTimer.stopTiming(); this.NBTentities = null; } if (this.NBTtiles != null) { - this.getProvider().getLevel().timings.syncChunkLoadBlockEntitiesTimer.startTiming(); for (CompoundTag nbt : NBTtiles) { if (nbt != null) { if (!nbt.contains("id")) { @@ -182,7 +179,6 @@ public void initChunk() { } } } - this.getProvider().getLevel().timings.syncChunkLoadBlockEntitiesTimer.stopTiming(); this.NBTtiles = null; } diff --git a/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java b/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java index a67e1a6c7e2..61f1cbe7899 100644 --- a/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java +++ b/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java @@ -409,11 +409,9 @@ public boolean loadChunk(int chunkX, int chunkZ, boolean create) { long index = Level.chunkHash(chunkX, chunkZ); synchronized (this.chunks) { - this.level.timings.syncChunkLoadDataTimer.startTiming(); chunk = this.chunks.get(index); if (chunk != null) { this.lastChunk.set(new WeakReference<>(chunk)); - this.level.timings.syncChunkLoadDataTimer.stopTiming(); return true; } @@ -430,10 +428,8 @@ public boolean loadChunk(int chunkX, int chunkZ, boolean create) { if (chunk != null) { this.chunks.put(index, chunk); this.lastChunk.set(new WeakReference<>(chunk)); - this.level.timings.syncChunkLoadDataTimer.stopTiming(); return true; } - this.level.timings.syncChunkLoadDataTimer.stopTiming(); } return false; } @@ -965,7 +961,6 @@ public LevelDbChunk getChunk(int chunkX, int chunkZ, boolean create) { return chunk; } - this.level.timings.syncChunkLoadDataTimer.startTiming(); try { chunk = this.readChunk(chunkX, chunkZ); } catch (Exception e) { @@ -975,7 +970,6 @@ public LevelDbChunk getChunk(int chunkX, int chunkZ, boolean create) { if (chunk == null && create) { chunk = LevelDbChunk.getEmptyChunk(chunkX, chunkZ, this); } - this.level.timings.syncChunkLoadDataTimer.stopTiming(); if (chunk != null) { this.lastChunk.set(new WeakReference<>(chunk)); diff --git a/src/main/java/cn/nukkit/level/format/mcregion/McRegion.java b/src/main/java/cn/nukkit/level/format/mcregion/McRegion.java index d30292b9561..def9cb581d2 100644 --- a/src/main/java/cn/nukkit/level/format/mcregion/McRegion.java +++ b/src/main/java/cn/nukkit/level/format/mcregion/McRegion.java @@ -183,7 +183,6 @@ public BaseFullChunk loadChunk(long index, int chunkX, int chunkZ, boolean creat int regionX = getRegionIndexX(chunkX); int regionZ = getRegionIndexZ(chunkZ); BaseRegionLoader region = this.loadRegion(regionX, regionZ); - this.level.timings.syncChunkLoadDataTimer.startTiming(); BaseFullChunk chunk; try { chunk = region.readChunk(chunkX - regionX * 32, chunkZ - regionZ * 32); @@ -198,7 +197,6 @@ public BaseFullChunk loadChunk(long index, int chunkX, int chunkZ, boolean creat } else { putChunk(index, chunk); } - this.level.timings.syncChunkLoadDataTimer.stopTiming(); return chunk; } diff --git a/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java b/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java index e106b34280e..50c8feb15ba 100644 --- a/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java +++ b/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java @@ -133,7 +133,7 @@ public interface ProtocolInfo { int UPDATE_SOFT_ENUM_PACKET = 0x72; // 114 c int NETWORK_STACK_LATENCY_PACKET = 0x73; // 115 cs int BLOCK_PALETTE_PACKET = 0x74; // 116 c D - int SCRIPT_CUSTOM_EVENT_PACKET = 0x75; // 117 cs + int SCRIPT_CUSTOM_EVENT_PACKET = 0x75; // 117 cs D int SPAWN_PARTICLE_EFFECT_PACKET = 0x76; // 118 c int AVAILABLE_ACTOR_IDENTIFIERS_PACKET = 0x77; // 119 c int LEVEL_SOUND_EVENT_PACKET_V2 = 0x78; // 120 cs D @@ -213,7 +213,7 @@ public interface ProtocolInfo { int GAME_TEST_REQUEST_PACKET = 0xc2; // 194 s int GAME_TEST_RESULTS_PACKET = 0xc3; // 195 c int UPDATE_CLIENT_INPUT_LOCKS_PACKET = 0xc4; // 196 c - int CLIENT_CHEAT_ABILITY_PACKET = 0xc5; // 197 s + int CLIENT_CHEAT_ABILITY_PACKET = 0xc5; // 197 s D int CAMERA_PRESETS_PACKET = 0xc6; // 198 c int UNLOCKED_RECIPES_PACKET = 0xc7; // 199 c @@ -248,6 +248,7 @@ public interface ProtocolInfo { int COMPRESSED_BIOME_DEFINITION_LIST_PACKET = 0x12d; // 301 c int TRIM_DATA_PACKET = 0x12e; // 302 c int OPEN_SIGN_PACKET = 0x12f; // 303 c + int AGENT_ANIMATION_PACKET = 0x130; // 304 c int COUNT = 1024; diff --git a/src/main/java/cn/nukkit/permission/DefaultPermissions.java b/src/main/java/cn/nukkit/permission/DefaultPermissions.java index 7a7b29bbf72..e461bf56dc1 100644 --- a/src/main/java/cn/nukkit/permission/DefaultPermissions.java +++ b/src/main/java/cn/nukkit/permission/DefaultPermissions.java @@ -106,7 +106,6 @@ public static void registerCorePermissions() { registerPermission(new Permission(ROOT + ".command.gc", "Allows the user to fire garbage collection tasks", Permission.DEFAULT_OP), commands); registerPermission(new Permission(ROOT + ".command.dumpmemory", "Allows the user to dump memory contents", Permission.DEFAULT_OP), commands); registerPermission(new Permission(ROOT + ".command.gamerule", "Sets or queries a game rule value", Permission.DEFAULT_OP), commands); - registerPermission(new Permission(ROOT + ".command.timings", "Allows the user to records timings for all plugin events", Permission.DEFAULT_OP), commands); registerPermission(new Permission(ROOT + ".command.title", "Allows the user to send titles to players", Permission.DEFAULT_OP), commands); registerPermission(new Permission(ROOT + ".command.spawnpoint", "Allows the user to change player's spawnpoint", Permission.DEFAULT_OP), commands); registerPermission(new Permission(ROOT + ".command.setworldspawn", "Allows the user to change the world spawn", Permission.DEFAULT_OP), commands); diff --git a/src/main/java/cn/nukkit/permission/PermissibleBase.java b/src/main/java/cn/nukkit/permission/PermissibleBase.java index c82ac7d8c32..e93781fb49c 100644 --- a/src/main/java/cn/nukkit/permission/PermissibleBase.java +++ b/src/main/java/cn/nukkit/permission/PermissibleBase.java @@ -4,7 +4,6 @@ import cn.nukkit.plugin.Plugin; import cn.nukkit.utils.PluginException; import cn.nukkit.utils.ServerException; -import co.aikar.timings.Timings; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -120,8 +119,6 @@ public void removeAttachment(PermissionAttachment attachment) { @Override public void recalculatePermissions() { - Timings.permissibleCalculationTimer.startTiming(); - this.clearPermissions(); Map defaults = Server.getInstance().getPluginManager().getDefaultPermissions(this.isOp()); Server.getInstance().getPluginManager().subscribeToDefaultPerms(this.isOp(), this.parent != null ? this.parent : this); @@ -136,7 +133,6 @@ public void recalculatePermissions() { for (PermissionAttachment attachment : this.attachments) { this.calculateChildPermissions(attachment.getPermissions(), false, attachment); } - Timings.permissibleCalculationTimer.stopTiming(); } public void clearPermissions() { diff --git a/src/main/java/cn/nukkit/plugin/PluginManager.java b/src/main/java/cn/nukkit/plugin/PluginManager.java index 98582d5f5ee..bb292c19521 100644 --- a/src/main/java/cn/nukkit/plugin/PluginManager.java +++ b/src/main/java/cn/nukkit/plugin/PluginManager.java @@ -9,8 +9,6 @@ import cn.nukkit.utils.MainLogger; import cn.nukkit.utils.PluginException; import cn.nukkit.utils.Utils; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -349,7 +347,6 @@ public void recalculatePermissionDefaults(Permission permission) { } private void calculatePermissionDefault(Permission permission) { - Timings.permissionDefaultTimer.startTiming(); if (permission.getDefault().equals(Permission.DEFAULT_OP) || permission.getDefault().equals(Permission.DEFAULT_TRUE)) { this.defaultPermsOp.put(permission.getName(), permission); this.dirtyPermissibles(true); @@ -359,7 +356,6 @@ private void calculatePermissionDefault(Permission permission) { this.defaultPerms.put(permission.getName(), permission); this.dirtyPermissibles(false); } - Timings.permissionDefaultTimer.startTiming(); } private void dirtyPermissibles(boolean op) { @@ -612,8 +608,7 @@ public void registerEvent(Class event, Listener listener, Event } try { - Timing timing = Timings.getPluginEventTiming(event, listener, executor, plugin); - this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled, timing)); + this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); } catch (IllegalAccessException e) { Server.getInstance().getLogger().logException(e); } diff --git a/src/main/java/cn/nukkit/plugin/RegisteredListener.java b/src/main/java/cn/nukkit/plugin/RegisteredListener.java index 0744db1f04c..659e16b7294 100644 --- a/src/main/java/cn/nukkit/plugin/RegisteredListener.java +++ b/src/main/java/cn/nukkit/plugin/RegisteredListener.java @@ -5,7 +5,6 @@ import cn.nukkit.event.EventPriority; import cn.nukkit.event.Listener; import cn.nukkit.utils.EventException; -import co.aikar.timings.Timing; /** * author: MagicDroidX @@ -23,15 +22,12 @@ public class RegisteredListener { private final boolean ignoreCancelled; - private final Timing timing; - - public RegisteredListener(Listener listener, EventExecutor executor, EventPriority priority, Plugin plugin, boolean ignoreCancelled, Timing timing) { + public RegisteredListener(Listener listener, EventExecutor executor, EventPriority priority, Plugin plugin, boolean ignoreCancelled) { this.listener = listener; this.priority = priority; this.plugin = plugin; this.executor = executor; this.ignoreCancelled = ignoreCancelled; - this.timing = timing; } public Listener getListener() { @@ -52,9 +48,7 @@ public void callEvent(Event event) throws EventException { return; } } - this.timing.startTiming(); executor.execute(listener, event); - this.timing.stopTiming(); } public boolean isIgnoringCancelled() { diff --git a/src/main/java/cn/nukkit/scheduler/AsyncTask.java b/src/main/java/cn/nukkit/scheduler/AsyncTask.java index 80ce01d63ee..2a8a0ae6273 100644 --- a/src/main/java/cn/nukkit/scheduler/AsyncTask.java +++ b/src/main/java/cn/nukkit/scheduler/AsyncTask.java @@ -1,7 +1,6 @@ package cn.nukkit.scheduler; import cn.nukkit.Server; -import co.aikar.timings.Timings; import lombok.extern.log4j.Log4j2; import java.util.Queue; @@ -63,7 +62,6 @@ public void cleanObject() { } public static void collectTask() { - Timings.schedulerAsyncTimer.startTiming(); while (!FINISHED_LIST.isEmpty()) { AsyncTask task = FINISHED_LIST.poll(); try { @@ -74,7 +72,6 @@ public static void collectTask() { + " invoking onCompletion", e); } } - Timings.schedulerAsyncTimer.stopTiming(); } } diff --git a/src/main/java/cn/nukkit/scheduler/ServerScheduler.java b/src/main/java/cn/nukkit/scheduler/ServerScheduler.java index 131ccd6f4e9..bb8ac0d97a5 100644 --- a/src/main/java/cn/nukkit/scheduler/ServerScheduler.java +++ b/src/main/java/cn/nukkit/scheduler/ServerScheduler.java @@ -281,14 +281,12 @@ public void mainThreadHeartbeat(int currentTick) { } else if (taskHandler.isAsynchronous()) { asyncPool.execute(taskHandler.getTask()); } else { - taskHandler.timing.startTiming(); try { taskHandler.run(currentTick); } catch (Throwable e) { log.fatal("Could not execute taskHandler " + taskHandler.getTaskId() + ": " + e.getMessage()); Server.getInstance().getLogger().logException(e instanceof Exception ? e : new RuntimeException(e)); } - taskHandler.timing.stopTiming(); } if (taskHandler.isRepeating()) { taskHandler.setNextRunTick(currentTick + taskHandler.getPeriod()); diff --git a/src/main/java/cn/nukkit/scheduler/TaskHandler.java b/src/main/java/cn/nukkit/scheduler/TaskHandler.java index c7a7fa77d4c..d3a7389fe82 100644 --- a/src/main/java/cn/nukkit/scheduler/TaskHandler.java +++ b/src/main/java/cn/nukkit/scheduler/TaskHandler.java @@ -1,9 +1,6 @@ package cn.nukkit.scheduler; -import cn.nukkit.Server; import cn.nukkit.plugin.Plugin; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; import lombok.extern.log4j.Log4j2; /** @@ -25,14 +22,11 @@ public class TaskHandler { private boolean cancelled; - public final Timing timing; - public TaskHandler(Plugin plugin, Runnable task, int taskId, boolean asynchronous) { this.asynchronous = asynchronous; this.plugin = plugin; this.task = task; this.taskId = taskId; - this.timing = Timings.getTaskTiming(this, period); } public boolean isCancelled() { diff --git a/src/main/java/cn/nukkit/timings/JsonUtil.java b/src/main/java/cn/nukkit/timings/JsonUtil.java deleted file mode 100644 index 6dac8e67bb5..00000000000 --- a/src/main/java/cn/nukkit/timings/JsonUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.nukkit.timings; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -import java.util.*; -import java.util.function.Function; - -/** - * @author Tee7even - *

- * Various methods for more compact JSON object constructing - */ -@SuppressWarnings("unchecked") -public class JsonUtil { - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - - public static JsonArray toArray(Object... objects) { - List array = new ArrayList(); - Collections.addAll(array, objects); - return GSON.toJsonTree(array).getAsJsonArray(); - } - - public static JsonObject toObject(Object object) { - return GSON.toJsonTree(object).getAsJsonObject(); - } - - public static JsonObject mapToObject(Iterable collection, Function mapper) { - Map object = new LinkedHashMap(); - for (E e : collection) { - JSONPair pair = mapper.apply(e); - if (pair != null) { - object.put(pair.key, pair.value); - } - } - return GSON.toJsonTree(object).getAsJsonObject(); - } - - public static JsonArray mapToArray(E[] elements, Function mapper) { - ArrayList array = new ArrayList(); - Collections.addAll(array, elements); - return mapToArray(array, mapper); - } - - public static JsonArray mapToArray(Iterable collection, Function mapper) { - List array = new ArrayList(); - for (E e : collection) { - if (e == null) continue; - Object obj = mapper.apply(e); - if (obj != null) { - array.add(obj); - } - } - return GSON.toJsonTree(array).getAsJsonArray(); - } - - public static class JSONPair { - public final String key; - public final Object value; - - public JSONPair(String key, Object value) { - this.key = key; - this.value = value; - } - - public JSONPair(int key, Object value) { - this.key = String.valueOf(key); - this.value = value; - } - } -} diff --git a/src/main/java/cn/nukkit/timings/LevelTimings.java b/src/main/java/cn/nukkit/timings/LevelTimings.java deleted file mode 100644 index e3563501755..00000000000 --- a/src/main/java/cn/nukkit/timings/LevelTimings.java +++ /dev/null @@ -1,49 +0,0 @@ -package cn.nukkit.timings; - -import cn.nukkit.level.Level; -import co.aikar.timings.Timing; -import co.aikar.timings.TimingsManager; - -/** - * @author Pub4Game - * @author Tee7even - */ -public class LevelTimings { - public final Timing doChunkUnload; - public final Timing doTickPending; - public final Timing doChunkGC; - public final Timing doTick; - - public final Timing tickChunks; - public final Timing entityTick; - public final Timing blockEntityTick; - public final Timing blockUpdate; - - public final Timing syncChunkSendTimer; - public final Timing syncChunkSendPrepareTimer; - public final Timing syncChunkLoadTimer; - public final Timing syncChunkLoadDataTimer; - public final Timing syncChunkLoadEntitiesTimer; - public final Timing syncChunkLoadBlockEntitiesTimer; - - public LevelTimings(Level level) { - String name = level.getFolderName() + " - "; - - this.doChunkUnload = TimingsManager.getTiming(name + "doChunkUnload"); - this.doTickPending = TimingsManager.getTiming(name + "doTickPending"); - this.doChunkGC = TimingsManager.getTiming(name + "doChunkGC"); - this.doTick = TimingsManager.getTiming(name + "doTick"); - - this.tickChunks = TimingsManager.getTiming(name + "tickChunks"); - this.entityTick = TimingsManager.getTiming(name + "entityTick"); - this.blockEntityTick = TimingsManager.getTiming(name + "blockEntityTick"); - this.blockUpdate = TimingsManager.getTiming(name + "blockUpdate"); - - this.syncChunkSendTimer = TimingsManager.getTiming(name + "syncChunkSend"); - this.syncChunkSendPrepareTimer = TimingsManager.getTiming(name + "syncChunkSendPrepare"); - this.syncChunkLoadTimer = TimingsManager.getTiming(name + "syncChunkLoad"); - this.syncChunkLoadDataTimer = TimingsManager.getTiming(name + "syncChunkLoad - Data"); - this.syncChunkLoadEntitiesTimer = TimingsManager.getTiming(name + "syncChunkLoad - Entities"); - this.syncChunkLoadBlockEntitiesTimer = TimingsManager.getTiming(name + "syncChunkLoad - BlockEntities"); - } -} diff --git a/src/main/java/co/aikar/timings/FullServerTickTiming.java b/src/main/java/co/aikar/timings/FullServerTickTiming.java deleted file mode 100644 index 66526bf8ec6..00000000000 --- a/src/main/java/co/aikar/timings/FullServerTickTiming.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import static co.aikar.timings.TimingIdentifier.DEFAULT_GROUP; -import static co.aikar.timings.TimingsManager.*; - -public class FullServerTickTiming extends Timing { - private static final TimingIdentifier IDENTIFIER = new TimingIdentifier(DEFAULT_GROUP.name, "Full Server Tick", null); - final TimingData minuteData; - double avgFreeMemory = -1D; - double avgUsedMemory = -1D; - - FullServerTickTiming() { - super(IDENTIFIER); - this.minuteData = new TimingData(this.id); - - TIMING_MAP.put(IDENTIFIER, this); - } - - @Override - public Timing startTiming() { - if (TimingsManager.needsFullReset) { - TimingsManager.resetTimings(); - } else if (TimingsManager.needsRecheckEnabled) { - TimingsManager.recheckEnabled(); - } - super.startTiming(); - return this; - } - - @Override - public void stopTiming() { - super.stopTiming(); - if (!this.enabled) { - return; - } - - if (TimingsHistory.timedTicks % 20 == 0) { - final Runtime runtime = Runtime.getRuntime(); - double usedMemory = runtime.totalMemory() - runtime.freeMemory(); - double freeMemory = runtime.maxMemory() - usedMemory; - - if (this.avgFreeMemory == -1) { - this.avgFreeMemory = freeMemory; - } else { - this.avgFreeMemory = (this.avgFreeMemory * (59 / 60D)) + (freeMemory * (1 / 60D)); - } - - if (this.avgUsedMemory == -1) { - this.avgUsedMemory = usedMemory; - } else { - this.avgUsedMemory = (this.avgUsedMemory * (59 / 60D)) + (usedMemory * (1 / 60D)); - } - } - - long start = System.nanoTime(); - TimingsManager.tick(); - long diff = System.nanoTime() - start; - - CURRENT = Timings.timingsTickTimer; - Timings.timingsTickTimer.addDiff(diff); - //addDiff for timingsTickTimer incremented this, bring it back down to 1 per tick. - this.record.curTickCount--; - this.minuteData.curTickTotal = this.record.curTickTotal; - this.minuteData.curTickCount = 1; - boolean violated = isViolated(); - this.minuteData.tick(violated); - Timings.timingsTickTimer.tick(violated); - tick(violated); - - if (TimingsHistory.timedTicks % 1200 == 0) { - MINUTE_REPORTS.add(new TimingsHistory.MinuteReport()); - TimingsHistory.resetTicks(false); - this.minuteData.reset(); - } - - if (TimingsHistory.timedTicks % Timings.getHistoryInterval() == 0) { - TimingsManager.HISTORY.add(new TimingsHistory()); - TimingsManager.resetTimings(); - } - } - - boolean isViolated() { - return this.record.curTickTotal > 50000000; - } -} diff --git a/src/main/java/co/aikar/timings/Timing.java b/src/main/java/co/aikar/timings/Timing.java deleted file mode 100644 index 906ff5c5463..00000000000 --- a/src/main/java/co/aikar/timings/Timing.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import cn.nukkit.Nukkit; -import cn.nukkit.Server; - -import java.util.HashMap; -import java.util.Map; - -public class Timing implements AutoCloseable { - private static int idPool = 1; - final int id = idPool++; - - final String name; - private final boolean verbose; - - final Map children = new HashMap<>(); - private Timing parent; - - private final Timing groupTiming; - final TimingData record; - - private long start = 0; - private int timingDepth = 0; - private boolean added; - boolean timed; - boolean enabled; - - Timing(TimingIdentifier id) { - if (id.name.startsWith("##")) { - this.verbose = true; - this.name = id.name.substring(3); - } else { - this.name = id.name; - this.verbose = false; - } - - this.record = new TimingData(this.id); - this.groupTiming = id.groupTiming; - - TimingIdentifier.getGroup(id.group).timings.add(this); - this.checkEnabled(); - } - - final void checkEnabled() { - this.enabled = Timings.isTimingsEnabled() && (!this.verbose || Timings.isVerboseEnabled()); - } - - void tick(boolean violated) { - if (this.timingDepth != 0 || this.record.curTickCount == 0) { - this.timingDepth = 0; - this.start = 0; - return; - } - - this.record.tick(violated); - for (TimingData data : this.children.values()) { - data.tick(violated); - } - } - - public Timing startTiming() { - if (!this.enabled) { - return this; - } - - if (Thread.currentThread() != Nukkit.getMainThread()) { - // Server.getInstance().getLogger().warning("Timing started from non-main thread: " + Thread.currentThread().getName(), new Throwable()); - return this; - } - - if (++this.timingDepth == 1) { - this.start = System.nanoTime(); - this.parent = TimingsManager.CURRENT; - TimingsManager.CURRENT = this; - } - - return this; - } - - public void stopTiming() { - if (!this.enabled) { - return; - } - - if (Thread.currentThread() != Nukkit.getMainThread()) { - // Server.getInstance().getLogger().warning("Timing stopped from non-main thread: " + Thread.currentThread().getName(), new Throwable()); - return; - } - - if (--this.timingDepth == 0 && this.start != 0) { - this.addDiff(System.nanoTime() - this.start); - this.start = 0; - } - } - - public void abort() { - if (this.enabled && this.timingDepth > 0) { - this.start = 0; - } - } - - void addDiff(long diff) { - if (TimingsManager.CURRENT == this) { - TimingsManager.CURRENT = this.parent; - if (this.parent != null) { - if (!this.parent.children.containsKey(this.id)) - this.parent.children.put(this.id, new TimingData(this.id)); - this.parent.children.get(this.id).add(diff); - } - } - - this.record.add(diff); - if (!this.added) { - this.added = true; - this.timed = true; - TimingsManager.TIMINGS.add(this); - } - - if (this.groupTiming != null) { - this.groupTiming.addDiff(diff); - - if (!this.groupTiming.children.containsKey(this.id)) - this.groupTiming.children.put(this.id, new TimingData(this.id)); - this.groupTiming.children.get(this.id).add(diff); - } - } - - void reset(boolean full) { - this.record.reset(); - if (full) { - this.timed = false; - } - this.start = 0; - this.timingDepth = 0; - this.added = false; - this.children.clear(); - this.checkEnabled(); - } - - @Override - public boolean equals(Object o) { - return (this == o); - } - - @Override - public int hashCode() { - return this.id; - } - - //For try-with-resources - @Override - public void close() { - this.stopTiming(); - } - - boolean isSpecial() { - return this == Timings.fullServerTickTimer || this == Timings.timingsTickTimer; - } -} diff --git a/src/main/java/co/aikar/timings/TimingData.java b/src/main/java/co/aikar/timings/TimingData.java deleted file mode 100644 index 8757d6990cf..00000000000 --- a/src/main/java/co/aikar/timings/TimingData.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import com.google.gson.JsonArray; - -import cn.nukkit.timings.JsonUtil; - -class TimingData { - private int id; - int count = 0; - private int lagCount = 0; - long totalTime = 0; - private long lagTotalTime = 0; - - int curTickCount = 0; - int curTickTotal = 0; - - TimingData(int id) { - this.id = id; - } - - TimingData(TimingData data) { - this.id = data.id; - this.count = data.count; - this.lagCount = data.lagCount; - this.totalTime = data.totalTime; - this.lagTotalTime = data.lagTotalTime; - } - - void add(long diff) { - ++this.curTickCount; - this.curTickTotal += diff; - } - - void tick(boolean violated) { - this.count += this.curTickCount; - this.totalTime += this.curTickTotal; - - if (violated) { - this.lagCount += this.curTickCount; - this.lagTotalTime += this.curTickTotal; - } - - this.curTickCount = 0; - this.curTickTotal = 0; - } - - void reset() { - this.count = 0; - this.lagCount = 0; - this.totalTime = 0; - this.lagTotalTime = 0; - this.curTickCount = 0; - this.curTickTotal = 0; - } - - protected TimingData clone() { - return new TimingData(this); - } - - JsonArray export() { - JsonArray json = JsonUtil.toArray(this.id, this.count, this.totalTime); - if (this.lagCount > 0) { - json.add(this.lagCount); - json.add(this.lagTotalTime); - } - return json; - } -} diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java deleted file mode 100644 index aafa13fe50c..00000000000 --- a/src/main/java/co/aikar/timings/TimingIdentifier.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; - -import java.util.ArrayDeque; -import java.util.Map; - -class TimingIdentifier { - static final Map GROUP_MAP = new Object2ObjectOpenHashMap<>(64); - static final TimingGroup DEFAULT_GROUP = getGroup("Nukkit"); - - final String group; - final String name; - final Timing groupTiming; - private final int hashCode; - - TimingIdentifier(String group, String name, Timing groupTiming) { - this.group = group != null ? group.intern() : DEFAULT_GROUP.name; - this.name = name.intern(); - this.groupTiming = groupTiming; - this.hashCode = (31 * this.group.hashCode()) + this.name.hashCode(); - } - - static TimingGroup getGroup(String name) { - if (name == null) { - return DEFAULT_GROUP; - } - - return GROUP_MAP.computeIfAbsent(name, k -> new TimingGroup(name)); - } - - @Override - @SuppressWarnings("all") - public boolean equals(Object o) { - if (o == null || !(o instanceof TimingIdentifier)) { - return false; - } - - TimingIdentifier that = (TimingIdentifier) o; - //Using intern() method on strings makes possible faster string comparison with == - return this.group == that.group && this.name == that.name; - } - - @Override - public int hashCode() { - return this.hashCode; - } - - static class TimingGroup { - private static int idPool = 1; - final int id = idPool++; - - final String name; - ArrayDeque timings = new ArrayDeque<>(64); - - TimingGroup(String name) { - this.name = name.intern(); - } - } -} diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java deleted file mode 100644 index 8baed61cf8b..00000000000 --- a/src/main/java/co/aikar/timings/Timings.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import cn.nukkit.Server; -import cn.nukkit.blockentity.BlockEntity; -import cn.nukkit.command.Command; -import cn.nukkit.entity.Entity; -import cn.nukkit.event.Event; -import cn.nukkit.event.Listener; -import cn.nukkit.math.Mth; -import cn.nukkit.network.protocol.DataPacket; -import cn.nukkit.plugin.EventExecutor; -import cn.nukkit.plugin.MethodEventExecutor; -import cn.nukkit.plugin.Plugin; -import cn.nukkit.scheduler.PluginTask; -import cn.nukkit.scheduler.TaskHandler; -import lombok.extern.log4j.Log4j2; - -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; - -import static co.aikar.timings.TimingIdentifier.DEFAULT_GROUP; - -@Log4j2 -public final class Timings { - private static boolean timingsEnabled = false; - private static boolean verboseEnabled = false; - private static boolean privacy = false; - private static Set ignoredConfigSections = new HashSet<>(); - - private static final int MAX_HISTORY_FRAMES = 12; - private static int historyInterval = -1; - private static int historyLength = -1; - - public static final FullServerTickTiming fullServerTickTimer; - public static final Timing timingsTickTimer; - public static final Timing pluginEventTimer; - - public static final Timing connectionTimer; - public static final Timing schedulerTimer; - public static final Timing schedulerAsyncTimer; - public static final Timing schedulerSyncTimer; - public static final Timing commandTimer; - public static final Timing serverCommandTimer; - public static final Timing levelSaveTimer; - - public static final Timing playerNetworkSendTimer; - public static final Timing playerNetworkReceiveTimer; - public static final Timing playerChunkOrderTimer; - public static final Timing playerChunkSendTimer; - public static final Timing playerCommandTimer; - - public static final Timing tickEntityTimer; - public static final Timing tickBlockEntityTimer; - public static final Timing entityMoveTimer; - public static final Timing entityBaseTickTimer; - public static final Timing livingEntityBaseTickTimer; - - public static final Timing generationTimer; - public static final Timing populationTimer; - public static final Timing generationCallbackTimer; - - public static final Timing permissibleCalculationTimer; - public static final Timing permissionDefaultTimer; - - static { - setTimingsEnabled(Server.getInstance().getConfig("timings.enabled", false)); - setVerboseEnabled(Server.getInstance().getConfig("timings.verbose", false)); - setHistoryInterval(Server.getInstance().getConfig("timings.history-interval", 6000)); - setHistoryLength(Server.getInstance().getConfig("timings.history-length", 72000)); - - privacy = Server.getInstance().getConfig("timings.privacy", false); - ignoredConfigSections.addAll(Server.getInstance().getConfig().getStringList("timings.ignore")); - - log.debug("Timings: \n" + - "Enabled - " + isTimingsEnabled() + "\n" + - "Verbose - " + isVerboseEnabled() + "\n" + - "History Interval - " + getHistoryInterval() + "\n" + - "History Length - " + getHistoryLength()); - - fullServerTickTimer = new FullServerTickTiming(); - timingsTickTimer = TimingsManager.getTiming(DEFAULT_GROUP.name, "Timings Tick", fullServerTickTimer); - pluginEventTimer = TimingsManager.getTiming("Plugin Events"); - - connectionTimer = TimingsManager.getTiming("Connection Handler"); - schedulerTimer = TimingsManager.getTiming("Scheduler"); - schedulerAsyncTimer = TimingsManager.getTiming("## Scheduler - Async Tasks"); - schedulerSyncTimer = TimingsManager.getTiming("## Scheduler - Sync Tasks"); - commandTimer = TimingsManager.getTiming("Commands"); - serverCommandTimer = TimingsManager.getTiming("Server Command"); - levelSaveTimer = TimingsManager.getTiming("Level Save"); - - playerNetworkSendTimer = TimingsManager.getTiming("Player Network Send"); - playerNetworkReceiveTimer = TimingsManager.getTiming("Player Network Receive"); - playerChunkOrderTimer = TimingsManager.getTiming("Player Order Chunks"); - playerChunkSendTimer = TimingsManager.getTiming("Player Send Chunks"); - playerCommandTimer = TimingsManager.getTiming("Player Command"); - - tickEntityTimer = TimingsManager.getTiming("## Entity Tick"); - tickBlockEntityTimer = TimingsManager.getTiming("## BlockEntity Tick"); - entityMoveTimer = TimingsManager.getTiming("## Entity Move"); - entityBaseTickTimer = TimingsManager.getTiming("## Entity Base Tick"); - livingEntityBaseTickTimer = TimingsManager.getTiming("## LivingEntity Base Tick"); - - generationTimer = TimingsManager.getTiming("Level Generation"); - populationTimer = TimingsManager.getTiming("Level Population"); - generationCallbackTimer = TimingsManager.getTiming("Level Generation Callback"); - - permissibleCalculationTimer = TimingsManager.getTiming("Permissible Calculation"); - permissionDefaultTimer = TimingsManager.getTiming("Default Permission Calculation"); - } - - public static boolean isTimingsEnabled() { - return timingsEnabled; - } - - public static void setTimingsEnabled(boolean enabled) { - timingsEnabled = enabled; - TimingsManager.reset(); - } - - public static boolean isVerboseEnabled() { - return verboseEnabled; - } - - public static void setVerboseEnabled(boolean enabled) { - verboseEnabled = enabled; - TimingsManager.needsRecheckEnabled = true; - } - - public static boolean isPrivacy() { - return privacy; - } - - public static Set getIgnoredConfigSections() { - return ignoredConfigSections; - } - - public static int getHistoryInterval() { - return historyInterval; - } - - public static void setHistoryInterval(int interval) { - historyInterval = Math.max(20 * 60, interval); - //Recheck the history length with the new Interval - if (historyLength != -1) { - setHistoryLength(historyLength); - } - } - - public static int getHistoryLength() { - return historyLength; - } - - public static void setHistoryLength(int length) { - //Cap at 12 History Frames, 1 hour at 5 minute frames. - int maxLength = historyInterval * MAX_HISTORY_FRAMES; - //For special cases of servers with special permission to bypass the max. - //This max helps keep data file sizes reasonable for processing on Aikar's Timing parser side. - //Setting this will not help you bypass the max unless Aikar has added an exception on the API side. - if (Server.getInstance().getConfig().getBoolean("timings.bypass-max", false)) { - maxLength = Integer.MAX_VALUE; - } - - historyLength = Math.max(Math.min(maxLength, length), historyInterval); - - Queue oldQueue = TimingsManager.HISTORY; - int frames = (getHistoryLength() / getHistoryInterval()); - if (length > maxLength) { - log.warn( - "Timings Length too high. Requested " + length + ", max is " + maxLength - + ". To get longer history, you must increase your interval. Set Interval to " - + Mth.ceil((float) length / MAX_HISTORY_FRAMES) - + " to achieve this length."); - } - - TimingsManager.HISTORY = new TimingsManager.BoundedQueue<>(frames); - TimingsManager.HISTORY.addAll(oldQueue); - } - - public static void reset() { - TimingsManager.reset(); - } - - - public static Timing getCommandTiming(Command command) { - return TimingsManager.getTiming(DEFAULT_GROUP.name, "Command: " + command.getLabel(), commandTimer); - } - - public static Timing getTaskTiming(TaskHandler handler, long period) { - String repeating = " "; - if (period > 0) { - repeating += "(interval:" + period + ")"; - } else { - repeating += "(Single)"; - } - - if (handler.getTask() instanceof PluginTask) { - String owner = ((PluginTask) handler.getTask()).getOwner().getName(); - return TimingsManager.getTiming(owner, "PluginTask: " + handler.getTaskId() + "<" + handler.getTask().getClass().getName() + ">" + repeating, schedulerSyncTimer); - } else if (!handler.isAsynchronous()) { - return TimingsManager.getTiming(DEFAULT_GROUP.name, "Task: " + handler.getTaskId() + "<" + handler.getTask().getClass().getName() + ">" + repeating, schedulerSyncTimer); - } else { - return null; - } - } - - public static Timing getPluginEventTiming(Class event, Listener listener, EventExecutor executor, Plugin plugin) { - Timing group = TimingsManager.getTiming(plugin.getName(), "Combined Total", pluginEventTimer); - - return TimingsManager.getTiming(plugin.getName(), "Event: " + listener.getClass().getName() + "." - + (executor instanceof MethodEventExecutor ? ((MethodEventExecutor) executor).getMethod().getName() : "???") - + " (" + event.getSimpleName() + ")", group); - } - - public static Timing getEntityTiming(Entity entity) { - return TimingsManager.getTiming(DEFAULT_GROUP.name, "## Entity Tick: " + entity.getClass().getSimpleName(), tickEntityTimer); - } - - public static Timing getBlockEntityTiming(BlockEntity blockEntity) { - return TimingsManager.getTiming(DEFAULT_GROUP.name, "## BlockEntity Tick: " + blockEntity.getClass().getSimpleName(), tickBlockEntityTimer); - } - - public static Timing getReceiveDataPacketTiming(DataPacket pk) { - return TimingsManager.getTiming(DEFAULT_GROUP.name, "## Receive Packet: " + pk.getClass().getSimpleName(), playerNetworkReceiveTimer); - } - - public static Timing getSendDataPacketTiming(DataPacket pk) { - return TimingsManager.getTiming(DEFAULT_GROUP.name, "## Send Packet: " + pk.getClass().getSimpleName(), playerNetworkSendTimer); - } - - public static void stopServer() { - setTimingsEnabled(false); - TimingsManager.recheckEnabled(); - } -} diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java deleted file mode 100644 index 81ce28a1dd2..00000000000 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import cn.nukkit.Server; -import cn.nukkit.command.CommandSender; -import cn.nukkit.command.ConsoleCommandSender; -import cn.nukkit.command.RemoteConsoleCommandSender; -import cn.nukkit.lang.TranslationContainer; -import cn.nukkit.nbt.stream.PGZIPOutputStream; -import cn.nukkit.timings.JsonUtil; -import cn.nukkit.utils.TextFormat; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import lombok.extern.log4j.Log4j2; - -import java.io.*; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.zip.Deflater; - -import static co.aikar.timings.TimingsManager.HISTORY; - -@Log4j2 -public class TimingsExport extends Thread { - private final CommandSender sender; - private final JsonObject out; - private final TimingsHistory[] history; - - private TimingsExport(CommandSender sender, JsonObject out, TimingsHistory[] history) { - super("Timings paste thread"); - this.sender = sender; - this.out = out; - this.history = history; - } - - /** - * Builds a JSON timings report and sends it to Aikar's viewer - * - * @param sender Sender that issued the command - */ - public static void reportTimings(CommandSender sender) { - JsonObject out = new JsonObject(); - out.addProperty("version", Server.getInstance().getVersion()); - out.addProperty("maxplayers", Server.getInstance().getMaxPlayers()); - out.addProperty("start", TimingsManager.timingStart / 1000); - out.addProperty("end", System.currentTimeMillis() / 1000); - out.addProperty("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000); - - if (!Timings.isPrivacy()) { - out.addProperty("server", Server.getInstance().getName()); - out.addProperty("motd", Server.getInstance().getMotd()); - out.addProperty("online-mode", false); //In MCPE we have permanent offline mode. - out.addProperty("rot", ""); //"data:image/png;base64," - } - - final Runtime runtime = Runtime.getRuntime(); - RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - - JsonObject system = new JsonObject(); - system.addProperty("timingcost", getCost()); - system.addProperty("name", System.getProperty("os.name")); - system.addProperty("version", System.getProperty("os.version")); - system.addProperty("jvmversion", System.getProperty("java.version")); - system.addProperty("arch", System.getProperty("os.arch")); - system.addProperty("maxmem", runtime.maxMemory()); - system.addProperty("cpu", runtime.availableProcessors()); - system.addProperty("runtime", ManagementFactory.getRuntimeMXBean().getUptime()); - system.addProperty("flags", String.join(" ", runtimeBean.getInputArguments())); - system.add("gc", JsonUtil.mapToObject(ManagementFactory.getGarbageCollectorMXBeans(), (input) -> - new JsonUtil.JSONPair(input.getName(), JsonUtil.toArray(input.getCollectionCount(), input.getCollectionTime())))); - out.add("system", system); - - TimingsHistory[] history = HISTORY.toArray(new TimingsHistory[HISTORY.size() + 1]); - history[HISTORY.size()] = new TimingsHistory(); //Current snapshot - - JsonObject timings = new JsonObject(); - for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { - for (Timing id : group.timings) { - if (!id.timed && !id.isSpecial()) { - continue; - } - - timings.add(String.valueOf(id.id), JsonUtil.toArray(group.id, id.name)); - } - } - - JsonObject idmap = new JsonObject(); - idmap.add("groups", JsonUtil.mapToObject(TimingIdentifier.GROUP_MAP.values(), (group) -> - new JsonUtil.JSONPair(group.id, group.name))); - idmap.add("handlers", timings); - idmap.add("worlds", JsonUtil.mapToObject(TimingsHistory.levelMap.entrySet(), (entry) -> - new JsonUtil.JSONPair(entry.getValue(), entry.getKey()))); - idmap.add("tileentity", JsonUtil.mapToObject(TimingsHistory.blockEntityMap.entrySet(), (entry) -> - new JsonUtil.JSONPair(entry.getKey(), entry.getValue()))); - idmap.add("entity", JsonUtil.mapToObject(TimingsHistory.entityMap.entrySet(), (entry) -> - new JsonUtil.JSONPair(entry.getKey(), entry.getValue()))); - out.add("idmap", idmap); - - //Information about loaded plugins - out.add("plugins", JsonUtil.mapToObject(Server.getInstance().getPluginManager().getPlugins().values(), (plugin) -> { - JsonObject jsonPlugin = new JsonObject(); - jsonPlugin.addProperty("version", plugin.getDescription().getVersion()); - jsonPlugin.addProperty("description", plugin.getDescription().getDescription());// Sounds legit - jsonPlugin.addProperty("website", plugin.getDescription().getWebsite()); - jsonPlugin.addProperty("authors", String.join(", ", plugin.getDescription().getAuthors())); - return new JsonUtil.JSONPair(plugin.getName(), jsonPlugin); - })); - - //Information on the users Config - JsonObject config = new JsonObject(); - if (!Timings.getIgnoredConfigSections().contains("all")) { - JsonObject nukkit = JsonUtil.toObject(Server.getInstance().getConfig().getRootSection()); - Timings.getIgnoredConfigSections().forEach(nukkit::remove); - config.add("nukkit", nukkit); - } else { - config.add("nukkit", null); - } - out.add("config", config); - - new TimingsExport(sender, out, history).start(); - } - - private static long getCost() { - int passes = 200; - Timing SAMPLER1 = TimingsManager.getTiming(null, "Timings sampler 1", null); - Timing SAMPLER2 = TimingsManager.getTiming(null, "Timings sampler 2", null); - Timing SAMPLER3 = TimingsManager.getTiming(null, "Timings sampler 3", null); - Timing SAMPLER4 = TimingsManager.getTiming(null, "Timings sampler 4", null); - Timing SAMPLER5 = TimingsManager.getTiming(null, "Timings sampler 5", null); - Timing SAMPLER6 = TimingsManager.getTiming(null, "Timings sampler 6", null); - - long start = System.nanoTime(); - for (int i = 0; i < passes; i++) { - SAMPLER1.startTiming(); - SAMPLER2.startTiming(); - SAMPLER3.startTiming(); - SAMPLER4.startTiming(); - SAMPLER5.startTiming(); - SAMPLER6.startTiming(); - SAMPLER6.stopTiming(); - SAMPLER5.stopTiming(); - SAMPLER4.stopTiming(); - SAMPLER3.stopTiming(); - SAMPLER2.stopTiming(); - SAMPLER1.stopTiming(); - } - - long timingsCost = (System.nanoTime() - start) / passes / 6; - - SAMPLER1.reset(true); - SAMPLER2.reset(true); - SAMPLER3.reset(true); - SAMPLER4.reset(true); - SAMPLER5.reset(true); - SAMPLER6.reset(true); - - return timingsCost; - } - - @Override - public synchronized void start() { - if (this.sender instanceof RemoteConsoleCommandSender) { - this.sender.sendMessage(new TranslationContainer("nukkit.command.timings.rcon")); - run(); - } else { - super.start(); - } - } - - @Override - public void run() { - this.sender.sendMessage(new TranslationContainer("nukkit.command.timings.uploadStart")); - this.out.add("data", JsonUtil.mapToArray(this.history, TimingsHistory::export)); - - String response = null; - try { - HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection(); - con.setDoOutput(true); - con.setRequestProperty("User-Agent", "Nukkit/" + Server.getInstance().getName() + "/" + InetAddress.getLocalHost().getHostName()); - con.setRequestMethod("POST"); - con.setInstanceFollowRedirects(false); - - PGZIPOutputStream request = new PGZIPOutputStream(con.getOutputStream()); - request.setLevel(Deflater.BEST_COMPRESSION); - - request.write(new Gson().toJson(this.out).getBytes(StandardCharsets.UTF_8)); - request.close(); - - response = getResponse(con); - - if (con.getResponseCode() != 302) { - this.sender.sendMessage(new TranslationContainer("nukkit.command.timings.uploadError", con.getResponseCode(), con.getResponseMessage())); - if (response != null) { - log.error(response); - } - return; - } - - String location = con.getHeaderField("Location"); - this.sender.sendMessage(new TranslationContainer("nukkit.command.timings.timingsLocation", location)); - if (!(this.sender instanceof ConsoleCommandSender)) { - log.info(Server.getInstance().getLanguage().translate("nukkit.command.timings.timingsLocation", location)); - } - - if (response != null && !response.isEmpty()) { - log.info(Server.getInstance().getLanguage().translate("nukkit.command.timings.timingsResponse", response)); - } - - File timingFolder = new File(Server.getInstance().getDataPath() + File.separator + "timings"); - timingFolder.mkdirs(); - String fileName = timingFolder + File.separator + new SimpleDateFormat("'timings-'yyyy-MM-dd-hh-mm'.txt'").format(new Date()); - - FileWriter writer = new FileWriter(fileName); - writer.write(Server.getInstance().getLanguage().translate("nukkit.command.timings.timingsLocation", location) + "\n\n"); - writer.write(new GsonBuilder().setPrettyPrinting().create().toJson(this.out)); - writer.close(); - - log.info(Server.getInstance().getLanguage().translate("nukkit.command.timings.timingsWrite", fileName)); - } catch (IOException exception) { - this.sender.sendMessage(new TranslationContainer(TextFormat.RED + "%nukkit.command.timings.reportError")); - if (response != null) { - log.error(response); - } - Server.getInstance().getLogger().logException(exception); - } - } - - private String getResponse(HttpURLConnection con) throws IOException { - try (InputStream is = con.getInputStream()) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - byte[] b = new byte[1024]; - int bytesRead; - while ((bytesRead = is.read(b)) != -1) { - bos.write(b, 0, bytesRead); - } - return bos.toString(); - - } catch (IOException exception) { - this.sender.sendMessage(new TranslationContainer(TextFormat.RED + "%nukkit.command.timings.reportError")); - log.warn(con.getResponseMessage(), exception); - return null; - } - } -} diff --git a/src/main/java/co/aikar/timings/TimingsHistory.java b/src/main/java/co/aikar/timings/TimingsHistory.java deleted file mode 100644 index e7e25c07cd9..00000000000 --- a/src/main/java/co/aikar/timings/TimingsHistory.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import cn.nukkit.Player; -import cn.nukkit.Server; -import cn.nukkit.blockentity.BlockEntity; -import cn.nukkit.entity.Entity; -import cn.nukkit.level.Level; -import cn.nukkit.level.format.FullChunk; -import cn.nukkit.timings.JsonUtil; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -import java.lang.management.ManagementFactory; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import static co.aikar.timings.Timings.fullServerTickTimer; -import static co.aikar.timings.TimingsManager.MINUTE_REPORTS; - -public class TimingsHistory { - public static long lastMinuteTime; - public static long timedTicks; - public static long playerTicks; - public static long entityTicks; - public static long tileEntityTicks; - public static long activatedEntityTicks; - - private static int levelIdPool = 1; - static Map levelMap = new HashMap<>(); - static Map entityMap = new HashMap<>(); - static Map blockEntityMap = new HashMap<>(); - - private final long endTime; - private final long startTime; - private final long totalTicks; - // Represents all time spent running the server this history - private final long totalTime; - private final MinuteReport[] minuteReports; - - private final TimingsHistoryEntry[] entries; - private final JsonObject levels = new JsonObject(); - - TimingsHistory() { - this.endTime = System.currentTimeMillis() / 1000; - this.startTime = TimingsManager.historyStart / 1000; - - if (timedTicks % 1200 != 0 || MINUTE_REPORTS.isEmpty()) { - this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size() + 1]); - this.minuteReports[this.minuteReports.length - 1] = new MinuteReport(); - } else { - this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[0]); - } - - long ticks = 0; - for (MinuteReport mr : this.minuteReports) { - ticks += mr.ticksRecord.timed; - } - - this.totalTicks = ticks; - this.totalTime = fullServerTickTimer.record.totalTime; - this.entries = new TimingsHistoryEntry[TimingsManager.TIMINGS.size()]; - - int i = 0; - for (Timing timing : TimingsManager.TIMINGS) { - this.entries[i++] = new TimingsHistoryEntry(timing); - } - - final Map entityCounts = new HashMap<>(); - final Map blockEntityCounts = new HashMap<>(); - final Gson GSON = new Gson(); - // Information about all loaded entities/block entities - for (Level level : Server.getInstance().getLevels().values()) { - JsonArray jsonLevel = new JsonArray(); - for (FullChunk chunk : level.getChunks().values()) { - entityCounts.clear(); - blockEntityCounts.clear(); - - //count entities - for (Entity entity : chunk.getEntities().values()) { - if (!entityCounts.containsKey(entity.getNetworkId())) - entityCounts.put(entity.getNetworkId(), new AtomicInteger(0)); - entityCounts.get(entity.getNetworkId()).incrementAndGet(); - entityMap.put(entity.getNetworkId(), entity.getClass().getSimpleName()); - } - - //count block entities - for (BlockEntity blockEntity : chunk.getBlockEntities().values()) { - if (!blockEntityCounts.containsKey(blockEntity.getBlock().getId())) - blockEntityCounts.put(blockEntity.getBlock().getId(), new AtomicInteger(0)); - blockEntityCounts.get(blockEntity.getBlock().getId()).incrementAndGet(); - blockEntityMap.put(blockEntity.getBlock().getId(), blockEntity.getClass().getSimpleName()); - } - - if (blockEntityCounts.isEmpty() && entityCounts.isEmpty()) { - continue; - } - - JsonArray jsonChunk = new JsonArray(); - jsonChunk.add(chunk.getX()); - jsonChunk.add(chunk.getZ()); - jsonChunk.add(GSON.toJsonTree(JsonUtil.mapToObject(entityCounts.entrySet(), (entry) -> new JsonUtil.JSONPair(entry.getKey(), entry.getValue().get()))).getAsJsonObject()); - jsonChunk.add(GSON.toJsonTree(JsonUtil.mapToObject(blockEntityCounts.entrySet(), (entry) -> new JsonUtil.JSONPair(entry.getKey(), entry.getValue().get()))).getAsJsonObject()); - jsonLevel.add(jsonChunk); - } - - if (!levelMap.containsKey(level.getName())) levelMap.put(level.getName(), levelIdPool++); - levels.add(String.valueOf(levelMap.get(level.getName())), jsonLevel); - } - } - - static void resetTicks(boolean fullReset) { - if (fullReset) { - timedTicks = 0; - } - lastMinuteTime = System.nanoTime(); - playerTicks = 0; - tileEntityTicks = 0; - entityTicks = 0; - activatedEntityTicks = 0; - } - - JsonObject export() { - JsonObject json = new JsonObject(); - json.addProperty("s", this.startTime); - json.addProperty("e", this.endTime); - json.addProperty("tk", this.totalTicks); - json.addProperty("tm", this.totalTime); - json.add("w", this.levels); - json.add("h", JsonUtil.mapToArray(this.entries, (entry) -> { - if (entry.data.count == 0) { - return null; - } - return entry.export(); - })); - json.add("mp", JsonUtil.mapToArray(this.minuteReports, MinuteReport::export)); - return json; - } - - static class MinuteReport { - final long time = System.currentTimeMillis() / 1000; - - final TicksRecord ticksRecord = new TicksRecord(); - final PingRecord pingRecord = new PingRecord(); - final TimingData fst = Timings.fullServerTickTimer.minuteData.clone(); - final double tps = 1E9 / (System.nanoTime() - lastMinuteTime) * this.ticksRecord.timed; - final double usedMemory = Timings.fullServerTickTimer.avgUsedMemory; - final double freeMemory = Timings.fullServerTickTimer.avgFreeMemory; - final double loadAvg = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage(); - - JsonArray export() { - return JsonUtil.toArray(this.time, - Math.round(this.tps * 100D) / 100D, - Math.round(this.pingRecord.avg * 100D) / 100D, - this.fst.export(), - JsonUtil.toArray(this.ticksRecord.timed, - this.ticksRecord.player, - this.ticksRecord.entity, - this.ticksRecord.activatedEntity, - this.ticksRecord.tileEntity), - this.usedMemory, - this.freeMemory, - this.loadAvg); - } - } - - private static class TicksRecord { - final long timed; - final long player; - final long entity; - final long activatedEntity; - final long tileEntity; - - TicksRecord() { - this.timed = timedTicks - (TimingsManager.MINUTE_REPORTS.size() * 1200); - this.player = playerTicks; - this.entity = entityTicks; - this.activatedEntity = activatedEntityTicks; - this.tileEntity = tileEntityTicks; - } - } - - private static class PingRecord { - final double avg; - - PingRecord() { - final Collection onlinePlayers = Server.getInstance().getOnlinePlayers().values(); - int totalPing = 0; - for (Player player : onlinePlayers) { - totalPing += player.getPing(); - } - - this.avg = onlinePlayers.isEmpty() ? 0 : (float) totalPing / onlinePlayers.size(); - } - } -} diff --git a/src/main/java/co/aikar/timings/TimingsHistoryEntry.java b/src/main/java/co/aikar/timings/TimingsHistoryEntry.java deleted file mode 100644 index 9ee71d12ad2..00000000000 --- a/src/main/java/co/aikar/timings/TimingsHistoryEntry.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import com.google.gson.JsonArray; - -import cn.nukkit.timings.JsonUtil; - -import java.util.ArrayList; -import java.util.HashMap; - -class TimingsHistoryEntry { - final TimingData data; - final TimingData[] children; - - TimingsHistoryEntry(Timing timing) { - this.data = timing.record.clone(); - HashMap timingChildren = new HashMap<>(timing.children); - this.children = new TimingData[timingChildren.size()]; - - int i = 0; - for (TimingData child : timingChildren.values()) { - this.children[i++] = child.clone(); - } - } - - JsonArray export() { - JsonArray json = this.data.export(); - if (this.children.length > 0) json.add(JsonUtil.mapToArray(this.children, TimingData::export)); - return json; - } -} diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java deleted file mode 100644 index 3622b329cd6..00000000000 --- a/src/main/java/co/aikar/timings/TimingsManager.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is licensed under the MIT License (MIT). - * - * Copyright (c) 2014 Daniel Ennis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package co.aikar.timings; - -import cn.nukkit.Server; - -import java.util.*; - -public class TimingsManager { - static final Map TIMING_MAP = Collections.synchronizedMap(new HashMap<>(256, 0.5f)); - - static final Queue TIMINGS = new ArrayDeque<>(); - static final ArrayDeque MINUTE_REPORTS = new ArrayDeque<>(); - - static Queue HISTORY = new BoundedQueue<>(12); - - static Timing CURRENT; - - static long timingStart = 0; - static long historyStart = 0; - static boolean needsFullReset = false; - static boolean needsRecheckEnabled = false; - - static void reset() { - needsFullReset = true; - } - - /** - * Called every tick to count the number of times a timer caused TPS loss. - */ - static void tick() { - if (Timings.isTimingsEnabled()) { - boolean violated = Timings.fullServerTickTimer.isViolated(); - - synchronized (TIMINGS) { - for (Timing timing : TIMINGS) { - if (timing.isSpecial()) { - // Called manually - continue; - } - - timing.tick(violated); - } - } - - TimingsHistory.playerTicks += Server.getInstance().getOnlinePlayers().size(); - TimingsHistory.timedTicks++; - } - } - - static void recheckEnabled() { - synchronized (TIMING_MAP) { - TIMING_MAP.values().forEach(Timing::checkEnabled); - } - - needsRecheckEnabled = false; - } - - static void resetTimings() { - if (needsFullReset) { - // Full resets need to re-check every handlers enabled state - // Timing map can be modified from async so we must sync on it. - synchronized (TIMING_MAP) { - for (Timing timing : TIMING_MAP.values()) { - timing.reset(true); - } - } - - HISTORY.clear(); - needsFullReset = false; - needsRecheckEnabled = false; - timingStart = System.currentTimeMillis(); - } else { - // Soft resets only need to act on timings that have done something - // Handlers can only be modified on main thread. - for (Timing timing : TIMINGS) { - timing.reset(false); - } - } - - TIMINGS.clear(); - MINUTE_REPORTS.clear(); - - TimingsHistory.resetTicks(true); - historyStart = System.currentTimeMillis(); - } - - public static Timing getTiming(String name) { - return getTiming(null, name, null); - } - - static Timing getTiming(String group, String name, Timing groupTiming) { - TimingIdentifier id = new TimingIdentifier(group, name, groupTiming); - return TIMING_MAP.computeIfAbsent(id, k -> new Timing(id)); - } - - static final class BoundedQueue extends LinkedList { - final int maxSize; - - BoundedQueue(int maxSize) { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize must be greater than zero"); - } - - this.maxSize = maxSize; - } - - @Override - public boolean add(E e) { - if (this.size() == maxSize) { - this.remove(); - } - - return super.add(e); - } - } -} diff --git a/src/main/resources/texts/en_US.lang b/src/main/resources/texts/en_US.lang index 47e1a3682e4..50d9b3299e6 100644 --- a/src/main/resources/texts/en_US.lang +++ b/src/main/resources/texts/en_US.lang @@ -72,22 +72,6 @@ nukkit.command.reload.usage=/reload nukkit.command.reload.reloading=Reloading server... nukkit.command.reload.reloaded=Reload complete. -nukkit.command.timings.description=Records timings to see performance of the server. -nukkit.command.timings.usage=/timings -nukkit.command.timings.enable=Enabled timings and reset -nukkit.command.timings.disable=Disabled timings -nukkit.command.timings.timingsDisabled=Please enable timings by typing /timings on -nukkit.command.timings.verboseEnable=Enabled verbose timings -nukkit.command.timings.verboseDisable=Disabled verbose timings -nukkit.command.timings.reset=Timings reset -nukkit.command.timings.rcon=Warning: Timings report done over RCON will cause lag spikes, you should use /timings report in game or console -nukkit.command.timings.uploadStart=Preparing timings report... -nukkit.command.timings.uploadError=Upload Error: %1$2s: %2$2s, check logs for more information -nukkit.command.timings.reportError=An error happened while pasting the report, check logs for more information -nukkit.command.timings.timingsLocation=View timings report: %1$2s -nukkit.command.timings.timingsResponse=Timings response: %1$2s -nukkit.command.timings.timingsWrite=Timings written to %1$2s - nukkit.command.title.description=Sends a title to the specified player or modifies title settings for that player nukkit.command.title.usage=/title \n/title \n/title nukkit.command.title.clear=Successfully cleared %1$2s's screen