Fix timings
This commit is contained in:
128
sources/src/main/java/co/aikar/timings/MinecraftTimings.java
Normal file
128
sources/src/main/java/co/aikar/timings/MinecraftTimings.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package co.aikar.timings;
|
||||||
|
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
|
import net.minecraft.server.*;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import org.bukkit.craftbukkit.scheduler.CraftTask;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class MinecraftTimings {
|
||||||
|
|
||||||
|
public static final Timing playerListTimer = Timings.ofSafe("Player List");
|
||||||
|
public static final Timing commandFunctionsTimer = Timings.ofSafe("Command Functions");
|
||||||
|
public static final Timing connectionTimer = Timings.ofSafe("Connection Handler");
|
||||||
|
public static final Timing tickablesTimer = Timings.ofSafe("Tickables");
|
||||||
|
public static final Timing minecraftSchedulerTimer = Timings.ofSafe("Minecraft Scheduler");
|
||||||
|
public static final Timing bukkitSchedulerTimer = Timings.ofSafe("Bukkit Scheduler");
|
||||||
|
public static final Timing bukkitSchedulerPendingTimer = Timings.ofSafe("Bukkit Scheduler - Pending");
|
||||||
|
public static final Timing bukkitSchedulerFinishTimer = Timings.ofSafe("Bukkit Scheduler - Finishing");
|
||||||
|
public static final Timing chunkIOTickTimer = Timings.ofSafe("ChunkIOTick");
|
||||||
|
public static final Timing timeUpdateTimer = Timings.ofSafe("Time Update");
|
||||||
|
public static final Timing serverCommandTimer = Timings.ofSafe("Server Command");
|
||||||
|
public static final Timing savePlayers = Timings.ofSafe("Save Players");
|
||||||
|
|
||||||
|
public static final Timing tickEntityTimer = Timings.ofSafe("## tickEntity");
|
||||||
|
public static final Timing tickTileEntityTimer = Timings.ofSafe("## tickTileEntity");
|
||||||
|
public static final Timing packetProcessTimer = Timings.ofSafe("## Packet Processing");
|
||||||
|
public static final Timing scheduledBlocksTimer = Timings.ofSafe("## Scheduled Blocks");
|
||||||
|
public static final Timing structureGenerationTimer = Timings.ofSafe("Structure Generation");
|
||||||
|
|
||||||
|
public static final Timing processQueueTimer = Timings.ofSafe("processQueue");
|
||||||
|
|
||||||
|
public static final Timing playerCommandTimer = Timings.ofSafe("playerCommand");
|
||||||
|
|
||||||
|
public static final Timing entityActivationCheckTimer = Timings.ofSafe("entityActivationCheck");
|
||||||
|
|
||||||
|
public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
|
||||||
|
public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
|
||||||
|
|
||||||
|
private static final Map<Class<? extends Runnable>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
|
||||||
|
|
||||||
|
private MinecraftTimings() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a timer associated with a plugins tasks.
|
||||||
|
* @param bukkitTask
|
||||||
|
* @param period
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Timing getPluginTaskTimings(BukkitTask bukkitTask, long period) {
|
||||||
|
if (!bukkitTask.isSync()) {
|
||||||
|
return NullTimingHandler.NULL;
|
||||||
|
}
|
||||||
|
Plugin plugin;
|
||||||
|
|
||||||
|
Runnable task = ((CraftTask) bukkitTask).task;
|
||||||
|
|
||||||
|
final Class<? extends Runnable> taskClass = task.getClass();
|
||||||
|
if (bukkitTask.getOwner() != null) {
|
||||||
|
plugin = bukkitTask.getOwner();
|
||||||
|
} else {
|
||||||
|
plugin = TimingsManager.getPluginByClassloader(taskClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String taskname = taskNameCache.computeIfAbsent(taskClass, clazz ->
|
||||||
|
clazz.isAnonymousClass() || clazz.isLocalClass()
|
||||||
|
? clazz.getName()
|
||||||
|
: clazz.getCanonicalName());
|
||||||
|
|
||||||
|
StringBuilder name = new StringBuilder(64);
|
||||||
|
name.append("Task: ").append(taskname);
|
||||||
|
if (period > 0) {
|
||||||
|
name.append(" (interval:").append(period).append(")");
|
||||||
|
} else {
|
||||||
|
name.append(" (Single)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
return Timings.ofSafe(null, name.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Timings.ofSafe(plugin, name.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a named timer for the specified entity type to track type specific timings.
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Timing getEntityTimings(Entity entity) {
|
||||||
|
String entityType = entity.getClass().getName();
|
||||||
|
return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType, tickEntityTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a named timer for the specified tile entity type to track type specific timings.
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Timing getTileEntityTimings(TileEntity entity) {
|
||||||
|
String entityType = entity.getClass().getName();
|
||||||
|
return Timings.ofSafe("Minecraft", "## tickTileEntity - " + entityType, tickTileEntityTimer);
|
||||||
|
}
|
||||||
|
public static Timing getCancelTasksTimer() {
|
||||||
|
return Timings.ofSafe("Cancel Tasks");
|
||||||
|
}
|
||||||
|
public static Timing getCancelTasksTimer(Plugin plugin) {
|
||||||
|
return Timings.ofSafe(plugin, "Cancel Tasks");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopServer() {
|
||||||
|
TimingsManager.stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Timing getBlockTiming(Block block) {
|
||||||
|
return Timings.ofSafe("## Scheduled Block: " + block.getName(), scheduledBlocksTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Timing getStructureTiming(StructureGenerator structureGenerator) {
|
||||||
|
return Timings.ofSafe("Structure Generator - " + structureGenerator.getName(), structureGenerationTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Timing getPacketTiming(Packet packet) {
|
||||||
|
return Timings.ofSafe("## Packet - " + packet.getClass().getSimpleName(), packetProcessTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
131
sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java
Normal file
131
sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* This file is licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2016 Daniel Ennis <http://aikar.co>
|
||||||
|
*
|
||||||
|
* 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 net.minecraft.server.BiomeBase.BiomeMeta;
|
||||||
|
import net.minecraft.server.BlockPosition;
|
||||||
|
import net.minecraft.server.Chunk;
|
||||||
|
import net.minecraft.server.EnumCreatureType;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
import net.minecraft.server.WorldServer;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.craftbukkit.generator.InternalChunkGenerator;
|
||||||
|
import org.bukkit.generator.BlockPopulator;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class TimedChunkGenerator extends InternalChunkGenerator {
|
||||||
|
private final WorldServer world;
|
||||||
|
private final InternalChunkGenerator timedGenerator;
|
||||||
|
|
||||||
|
public TimedChunkGenerator(WorldServer worldServer, InternalChunkGenerator gen) {
|
||||||
|
world = worldServer;
|
||||||
|
timedGenerator = gen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public byte[] generate(org.bukkit.World world, Random random, int x, int z) {
|
||||||
|
return timedGenerator.generate(world, random, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public short[][] generateExtBlockSections(org.bukkit.World world, Random random, int x, int z,
|
||||||
|
BiomeGrid biomes) {
|
||||||
|
return timedGenerator.generateExtBlockSections(world, random, x, z, biomes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public byte[][] generateBlockSections(org.bukkit.World world, Random random, int x, int z,
|
||||||
|
BiomeGrid biomes) {
|
||||||
|
return timedGenerator.generateBlockSections(world, random, x, z, biomes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkData generateChunkData(org.bukkit.World world, Random random, int x, int z, BiomeGrid biome) {
|
||||||
|
return timedGenerator.generateChunkData(world, random, x, z, biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSpawn(org.bukkit.World world, int x, int z) {
|
||||||
|
return timedGenerator.canSpawn(world, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockPopulator> getDefaultPopulators(org.bukkit.World world) {
|
||||||
|
return timedGenerator.getDefaultPopulators(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getFixedSpawnLocation(org.bukkit.World world, Random random) {
|
||||||
|
return timedGenerator.getFixedSpawnLocation(world, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getOrCreateChunk(int i, int j) {
|
||||||
|
try (Timing ignored = world.timings.chunkGeneration.startTiming()) {
|
||||||
|
return timedGenerator.getOrCreateChunk(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recreateStructures(int i, int j) {
|
||||||
|
try (Timing ignored = world.timings.syncChunkLoadStructuresTimer.startTiming()) {
|
||||||
|
timedGenerator.recreateStructures(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean a(Chunk chunk, int i, int j) {
|
||||||
|
return timedGenerator.a(chunk, i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BiomeMeta> getMobsFor(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
|
||||||
|
return timedGenerator.getMobsFor(enumcreaturetype, blockposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public BlockPosition findNearestMapFeature(World world, String s, BlockPosition blockposition, boolean flag) {
|
||||||
|
return timedGenerator.findNearestMapFeature(world, s, blockposition, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recreateStructures(Chunk chunk, int i, int j) {
|
||||||
|
try (Timing ignored = world.timings.syncChunkLoadStructuresTimer.startTiming()) {
|
||||||
|
timedGenerator.recreateStructures(chunk, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean a(World world, String s, BlockPosition blockPosition) {
|
||||||
|
return timedGenerator.a(world, s, blockPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
228
sources/src/main/java/co/aikar/timings/TimingHandler.java
Normal file
228
sources/src/main/java/co/aikar/timings/TimingHandler.java
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* This file is licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Daniel Ennis <http://aikar.co>
|
||||||
|
*
|
||||||
|
* 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 co.aikar.util.LoadingIntMap;
|
||||||
|
import io.akarin.api.internal.Akari;
|
||||||
|
import io.akarin.api.internal.Akari.AssignableThread;
|
||||||
|
import io.akarin.server.core.AkarinGlobalConfig;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
class TimingHandler implements Timing {
|
||||||
|
String name;
|
||||||
|
private static AtomicInteger idPool = new AtomicInteger(1);
|
||||||
|
static Deque<TimingHandler> TIMING_STACK = new ArrayDeque<>();
|
||||||
|
final int id = idPool.getAndIncrement();
|
||||||
|
|
||||||
|
final TimingIdentifier identifier;
|
||||||
|
private final boolean verbose;
|
||||||
|
|
||||||
|
private final Int2ObjectOpenHashMap<TimingData> children = new LoadingIntMap<>(TimingData::new);
|
||||||
|
|
||||||
|
final TimingData record;
|
||||||
|
private final TimingHandler groupHandler;
|
||||||
|
|
||||||
|
private long start = 0;
|
||||||
|
private int timingDepth = 0;
|
||||||
|
private boolean added;
|
||||||
|
private boolean timed;
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
TimingHandler(TimingIdentifier id) {
|
||||||
|
this.identifier = id;
|
||||||
|
this.verbose = id.name.startsWith("##");
|
||||||
|
this.record = new TimingData(this.id);
|
||||||
|
this.groupHandler = id.groupHandler;
|
||||||
|
|
||||||
|
TimingIdentifier.getGroup(id.group).handlers.add(this);
|
||||||
|
checkEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
final void checkEnabled() {
|
||||||
|
enabled = Timings.timingsEnabled && (!verbose || Timings.verboseEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void processTick(boolean violated) {
|
||||||
|
if (timingDepth != 0 || record.getCurTickCount() == 0) {
|
||||||
|
timingDepth = 0;
|
||||||
|
start = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
record.processTick(violated);
|
||||||
|
for (TimingData handler : children.values()) {
|
||||||
|
handler.processTick(violated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Timing startTimingIfSync() {
|
||||||
|
startTiming();
|
||||||
|
return (Timing) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTimingIfSync() {
|
||||||
|
if (Akari.isPrimaryThread(false)) {
|
||||||
|
stopTiming(true); // Avoid twice thread check
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Timing startTiming() {
|
||||||
|
if (enabled && Bukkit.isPrimaryThread() && ++timingDepth == 1) {
|
||||||
|
start = System.nanoTime();
|
||||||
|
TIMING_STACK.addLast(this);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTiming() {
|
||||||
|
stopTiming(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTiming(long start) {
|
||||||
|
if (enabled) addDiff(System.nanoTime() - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTiming(boolean alreadySync) {
|
||||||
|
if (!enabled) return;
|
||||||
|
if (!alreadySync) {
|
||||||
|
Thread curThread = Thread.currentThread();
|
||||||
|
if (curThread.getClass() == AssignableThread.class) return;
|
||||||
|
if (curThread != MinecraftServer.getServer().primaryThread) {
|
||||||
|
if (AkarinGlobalConfig.silentAsyncTimings) return;
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
|
||||||
|
Thread.dumpStack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main thread ensured
|
||||||
|
if (--timingDepth == 0 && start != 0) {
|
||||||
|
addDiff(System.nanoTime() - start);
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void abort() {
|
||||||
|
|
||||||
|
}
|
||||||
|
void addDiff(long diff) {
|
||||||
|
if (this != null) {
|
||||||
|
this.children.get(id).add(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
record.add(diff);
|
||||||
|
if (!added) {
|
||||||
|
added = true;
|
||||||
|
timed = true;
|
||||||
|
TimingsManager.HANDLERS.add(this);
|
||||||
|
}
|
||||||
|
if (groupHandler != null) {
|
||||||
|
groupHandler.addDiff(diff, this);
|
||||||
|
groupHandler.children.get(id).add(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void addDiff(long diff, TimingHandler parent) {
|
||||||
|
if (parent != null) {
|
||||||
|
parent.children.get(id).add(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
record.add(diff);
|
||||||
|
if (!added) {
|
||||||
|
added = true;
|
||||||
|
timed = true;
|
||||||
|
TimingsManager.HANDLERS.add(this);
|
||||||
|
}
|
||||||
|
if (groupHandler != null) {
|
||||||
|
groupHandler.addDiff(diff, parent);
|
||||||
|
groupHandler.children.get(id).add(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset this timer, setting all values to zero.
|
||||||
|
*/
|
||||||
|
void reset(boolean full) {
|
||||||
|
record.reset();
|
||||||
|
if (full) {
|
||||||
|
timed = false;
|
||||||
|
}
|
||||||
|
start = 0;
|
||||||
|
timingDepth = 0;
|
||||||
|
added = false;
|
||||||
|
children.clear();
|
||||||
|
checkEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimingHandler getTimingHandler() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (this == o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is simply for the Closeable interface so it can be used with try-with-resources ()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
stopTimingIfSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSpecial() {
|
||||||
|
return this == TimingsManager.FULL_SERVER_TICK || this == TimingsManager.TIMINGS_TICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTimed() {
|
||||||
|
return timed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimingData[] cloneChildren() {
|
||||||
|
final TimingData[] clonedChildren = new TimingData[children.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (TimingData child : children.values()) {
|
||||||
|
clonedChildren[i++] = child.clone();
|
||||||
|
}
|
||||||
|
return clonedChildren;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java
Normal file
103
sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package co.aikar.timings;
|
||||||
|
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of timers per world, to track world specific timings.
|
||||||
|
*/
|
||||||
|
public class WorldTimingsHandler {
|
||||||
|
public final Timing mobSpawn;
|
||||||
|
public final Timing doChunkUnload;
|
||||||
|
public final Timing doPortalForcer;
|
||||||
|
public final Timing scheduledBlocks;
|
||||||
|
public final Timing scheduledBlocksCleanup;
|
||||||
|
public final Timing scheduledBlocksTicking;
|
||||||
|
public final Timing chunkTicks;
|
||||||
|
public final Timing lightChunk;
|
||||||
|
public final Timing chunkTicksBlocks;
|
||||||
|
public final Timing doVillages;
|
||||||
|
public final Timing doChunkMap;
|
||||||
|
public final Timing doChunkMapUpdate;
|
||||||
|
public final Timing doChunkMapToUpdate;
|
||||||
|
public final Timing doChunkMapSortMissing;
|
||||||
|
public final Timing doChunkMapSortSendToPlayers;
|
||||||
|
public final Timing doChunkMapPlayersNeedingChunks;
|
||||||
|
public final Timing doChunkMapPendingSendToPlayers;
|
||||||
|
public final Timing doChunkMapUnloadChunks;
|
||||||
|
public final Timing doChunkGC;
|
||||||
|
public final Timing doSounds;
|
||||||
|
public final Timing entityRemoval;
|
||||||
|
public final Timing entityTick;
|
||||||
|
public final Timing tileEntityTick;
|
||||||
|
public final Timing tileEntityPending;
|
||||||
|
public final Timing tracker1;
|
||||||
|
public final Timing tracker2;
|
||||||
|
public final Timing doTick;
|
||||||
|
public final Timing tickEntities;
|
||||||
|
|
||||||
|
public final Timing syncChunkLoadTimer;
|
||||||
|
public final Timing syncChunkLoadDataTimer;
|
||||||
|
public final Timing syncChunkLoadStructuresTimer;
|
||||||
|
public final Timing syncChunkLoadPostTimer;
|
||||||
|
public final Timing syncChunkLoadNBTTimer;
|
||||||
|
public final Timing syncChunkLoadPopulateNeighbors;
|
||||||
|
public final Timing chunkGeneration;
|
||||||
|
public final Timing chunkIOStage1;
|
||||||
|
public final Timing chunkIOStage2;
|
||||||
|
public final Timing worldSave;
|
||||||
|
public final Timing worldSaveChunks;
|
||||||
|
public final Timing worldSaveLevel;
|
||||||
|
public final Timing chunkSaveData;
|
||||||
|
|
||||||
|
public final Timing lightingQueueTimer;
|
||||||
|
|
||||||
|
public WorldTimingsHandler(World server) {
|
||||||
|
String name = server.worldData.getName() +" - ";
|
||||||
|
|
||||||
|
mobSpawn = Timings.ofSafe(name + "mobSpawn");
|
||||||
|
doChunkUnload = Timings.ofSafe(name + "doChunkUnload");
|
||||||
|
scheduledBlocks = Timings.ofSafe(name + "Scheduled Blocks");
|
||||||
|
scheduledBlocksCleanup = Timings.ofSafe(name + "Scheduled Blocks - Cleanup");
|
||||||
|
scheduledBlocksTicking = Timings.ofSafe(name + "Scheduled Blocks - Ticking");
|
||||||
|
chunkTicks = Timings.ofSafe(name + "Chunk Ticks");
|
||||||
|
lightChunk = Timings.ofSafe(name + "Light Chunk");
|
||||||
|
chunkTicksBlocks = Timings.ofSafe(name + "Chunk Ticks - Blocks");
|
||||||
|
doVillages = Timings.ofSafe(name + "doVillages");
|
||||||
|
doChunkMap = Timings.ofSafe(name + "doChunkMap");
|
||||||
|
doChunkMapUpdate = Timings.ofSafe(name + "doChunkMap - Update");
|
||||||
|
doChunkMapToUpdate = Timings.ofSafe(name + "doChunkMap - To Update");
|
||||||
|
doChunkMapSortMissing = Timings.ofSafe(name + "doChunkMap - Sort Missing");
|
||||||
|
doChunkMapSortSendToPlayers = Timings.ofSafe(name + "doChunkMap - Sort Send To Players");
|
||||||
|
doChunkMapPlayersNeedingChunks = Timings.ofSafe(name + "doChunkMap - Players Needing Chunks");
|
||||||
|
doChunkMapPendingSendToPlayers = Timings.ofSafe(name + "doChunkMap - Pending Send To Players");
|
||||||
|
doChunkMapUnloadChunks = Timings.ofSafe(name + "doChunkMap - Unload Chunks");
|
||||||
|
doSounds = Timings.ofSafe(name + "doSounds");
|
||||||
|
doChunkGC = Timings.ofSafe(name + "doChunkGC");
|
||||||
|
doPortalForcer = Timings.ofSafe(name + "doPortalForcer");
|
||||||
|
entityTick = Timings.ofSafe(name + "entityTick");
|
||||||
|
entityRemoval = Timings.ofSafe(name + "entityRemoval");
|
||||||
|
tileEntityTick = Timings.ofSafe(name + "tileEntityTick");
|
||||||
|
tileEntityPending = Timings.ofSafe(name + "tileEntityPending");
|
||||||
|
|
||||||
|
syncChunkLoadTimer = Timings.ofSafe(name + "syncChunkLoad");
|
||||||
|
syncChunkLoadDataTimer = Timings.ofSafe(name + "syncChunkLoad - Data");
|
||||||
|
syncChunkLoadStructuresTimer = Timings.ofSafe(name + "chunkLoad - recreateStructures");
|
||||||
|
syncChunkLoadPostTimer = Timings.ofSafe(name + "chunkLoad - Post");
|
||||||
|
syncChunkLoadNBTTimer = Timings.ofSafe(name + "chunkLoad - NBT");
|
||||||
|
syncChunkLoadPopulateNeighbors = Timings.ofSafe(name + "chunkLoad - Populate Neighbors");
|
||||||
|
chunkGeneration = Timings.ofSafe(name + "chunkGeneration");
|
||||||
|
chunkIOStage1 = Timings.ofSafe(name + "ChunkIO Stage 1 - DiskIO");
|
||||||
|
chunkIOStage2 = Timings.ofSafe(name + "ChunkIO Stage 2 - Post Load");
|
||||||
|
worldSave = Timings.ofSafe(name + "World Save");
|
||||||
|
worldSaveLevel = Timings.ofSafe(name + "World Save - Level");
|
||||||
|
worldSaveChunks = Timings.ofSafe(name + "World Save - Chunks");
|
||||||
|
chunkSaveData = Timings.ofSafe(name + "Chunk Save - Data");
|
||||||
|
|
||||||
|
tracker1 = Timings.ofSafe(name + "tracker stage 1");
|
||||||
|
tracker2 = Timings.ofSafe(name + "tracker stage 2");
|
||||||
|
doTick = Timings.ofSafe(name + "doTick");
|
||||||
|
tickEntities = Timings.ofSafe(name + "tickEntities");
|
||||||
|
|
||||||
|
lightingQueueTimer = Timings.ofSafe(name + "Lighting Queue");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package io.akarin.server.mixin.core;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import co.aikar.timings.Timing;
|
|
||||||
import io.akarin.api.internal.Akari;
|
|
||||||
import io.akarin.api.internal.Akari.AssignableThread;
|
|
||||||
import io.akarin.server.core.AkarinGlobalConfig;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
|
|
||||||
@Mixin(targets = "co.aikar.timings.TimingHandler", remap = false)
|
|
||||||
public abstract class MixinTimingHandler {
|
|
||||||
@Shadow @Final String name;
|
|
||||||
@Shadow private boolean enabled;
|
|
||||||
@Shadow private long start;
|
|
||||||
@Shadow private int timingDepth;
|
|
||||||
|
|
||||||
@Shadow abstract void addDiff(long diff);
|
|
||||||
@Shadow public abstract Timing startTiming();
|
|
||||||
|
|
||||||
@Overwrite // Overwrite to avoid twice thread check
|
|
||||||
public Timing startTimingIfSync() {
|
|
||||||
startTiming();
|
|
||||||
return (Timing) this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
@Inject(method = "startTiming", at = @At("HEAD"), cancellable = true)
|
|
||||||
public void onStartTiming(CallbackInfoReturnable ci) {
|
|
||||||
if (!Akari.isPrimaryThread(false)) ci.setReturnValue(this); // Avoid modify any field
|
|
||||||
}
|
|
||||||
|
|
||||||
@Overwrite
|
|
||||||
public void stopTimingIfSync() {
|
|
||||||
if (Akari.isPrimaryThread(false)) {
|
|
||||||
stopTiming(true); // Avoid twice thread check
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Overwrite
|
|
||||||
public void stopTiming() {
|
|
||||||
stopTiming(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopTiming(long start) {
|
|
||||||
if (enabled) addDiff(System.nanoTime() - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopTiming(boolean alreadySync) {
|
|
||||||
if (!enabled) return;
|
|
||||||
if (!alreadySync) {
|
|
||||||
Thread curThread = Thread.currentThread();
|
|
||||||
if (curThread.getClass() == AssignableThread.class) return;
|
|
||||||
if (curThread != MinecraftServer.getServer().primaryThread) {
|
|
||||||
if (AkarinGlobalConfig.silentAsyncTimings) return;
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
|
|
||||||
Thread.dumpStack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main thread ensured
|
|
||||||
if (--timingDepth == 0 && start != 0) {
|
|
||||||
addDiff(System.nanoTime() - start);
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
"core.MixinCommandBanIp",
|
"core.MixinCommandBanIp",
|
||||||
"core.MixinChunkSection",
|
"core.MixinChunkSection",
|
||||||
"core.MixinAsyncCatcher",
|
"core.MixinAsyncCatcher",
|
||||||
"core.MixinTimingHandler",
|
|
||||||
"core.MixinVersionCommand",
|
"core.MixinVersionCommand",
|
||||||
"core.MixinMinecraftServer",
|
"core.MixinMinecraftServer",
|
||||||
"core.MixinChunkIOExecutor",
|
"core.MixinChunkIOExecutor",
|
||||||
|
|||||||
Reference in New Issue
Block a user