diff --git a/sources/src/main/java/co/aikar/timings/MinecraftTimings.java b/sources/src/main/java/co/aikar/timings/MinecraftTimings.java new file mode 100644 index 000000000..baea97382 --- /dev/null +++ b/sources/src/main/java/co/aikar/timings/MinecraftTimings.java @@ -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, 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 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); + } +} diff --git a/sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java b/sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java new file mode 100644 index 000000000..089154f62 --- /dev/null +++ b/sources/src/main/java/co/aikar/timings/TimedChunkGenerator.java @@ -0,0 +1,131 @@ +/* + * This file is licensed under the MIT License (MIT). + * + * Copyright (c) 2014-2016 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 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 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 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); + } +} diff --git a/sources/src/main/java/co/aikar/timings/TimingHandler.java b/sources/src/main/java/co/aikar/timings/TimingHandler.java new file mode 100644 index 000000000..496755472 --- /dev/null +++ b/sources/src/main/java/co/aikar/timings/TimingHandler.java @@ -0,0 +1,228 @@ +/* + * 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 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 TIMING_STACK = new ArrayDeque<>(); + final int id = idPool.getAndIncrement(); + + final TimingIdentifier identifier; + private final boolean verbose; + + private final Int2ObjectOpenHashMap 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; + } +} diff --git a/sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java new file mode 100644 index 000000000..4eebd9fae --- /dev/null +++ b/sources/src/main/java/co/aikar/timings/WorldTimingsHandler.java @@ -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"); + } +} diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java deleted file mode 100644 index 2ac2a059e..000000000 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java +++ /dev/null @@ -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; - } - } -} diff --git a/sources/src/main/resources/mixins.akarin.core.json b/sources/src/main/resources/mixins.akarin.core.json index 9369eba12..a14a50939 100644 --- a/sources/src/main/resources/mixins.akarin.core.json +++ b/sources/src/main/resources/mixins.akarin.core.json @@ -24,7 +24,6 @@ "core.MixinCommandBanIp", "core.MixinChunkSection", "core.MixinAsyncCatcher", - "core.MixinTimingHandler", "core.MixinVersionCommand", "core.MixinMinecraftServer", "core.MixinChunkIOExecutor", @@ -41,4 +40,4 @@ "optimization.MixinPersistentCollection", "optimization.MixinTileEntityEnchantTable" ] -} \ No newline at end of file +}