Created
April 5, 2019 04:45
-
-
Save aikar/ec37231bd2ab2ca5ff4d275cc84d110c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java | |
index 98079dc0..64531fcc 100644 | |
--- a/src/main/java/co/aikar/timings/FullServerTickHandler.java | |
+++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java | |
@@ -2,6 +2,8 @@ package co.aikar.timings; | |
import static co.aikar.timings.TimingsManager.*; | |
+import org.jetbrains.annotations.NotNull; | |
+ | |
public class FullServerTickHandler extends TimingHandler { | |
private static final TimingIdentifier IDENTITY = new TimingIdentifier("Minecraft", "Full Server Tick", null); | |
final TimingData minuteData; | |
@@ -14,6 +16,7 @@ public class FullServerTickHandler extends TimingHandler { | |
TIMING_MAP.put(IDENTITY, this); | |
} | |
+ @NotNull | |
@Override | |
public Timing startTiming() { | |
if (TimingsManager.needsFullReset) { | |
@@ -50,8 +53,7 @@ public class FullServerTickHandler extends TimingHandler { | |
long start = System.nanoTime(); | |
TimingsManager.tick(); | |
long diff = System.nanoTime() - start; | |
- CURRENT = TIMINGS_TICK; | |
- TIMINGS_TICK.addDiff(diff); | |
+ TIMINGS_TICK.addDiff(diff, null); | |
// addDiff for TIMINGS_TICK incremented this, bring it back down to 1 per tick. | |
record.setCurTickCount(record.getCurTickCount()-1); | |
diff --git a/src/main/java/co/aikar/timings/NullTimingHandler.java b/src/main/java/co/aikar/timings/NullTimingHandler.java | |
index 8c43e206..9b45ce88 100644 | |
--- a/src/main/java/co/aikar/timings/NullTimingHandler.java | |
+++ b/src/main/java/co/aikar/timings/NullTimingHandler.java | |
@@ -23,7 +23,12 @@ | |
*/ | |
package co.aikar.timings; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
+ | |
public final class NullTimingHandler implements Timing { | |
+ public static final Timing NULL = new NullTimingHandler(); | |
+ @NotNull | |
@Override | |
public Timing startTiming() { | |
return this; | |
@@ -34,6 +39,7 @@ public final class NullTimingHandler implements Timing { | |
} | |
+ @NotNull | |
@Override | |
public Timing startTimingIfSync() { | |
return this; | |
@@ -49,6 +55,7 @@ public final class NullTimingHandler implements Timing { | |
} | |
+ @Nullable | |
@Override | |
public TimingHandler getTimingHandler() { | |
return null; | |
diff --git a/src/main/java/co/aikar/timings/TimedEventExecutor.java b/src/main/java/co/aikar/timings/TimedEventExecutor.java | |
index feddcdbd..933ecf9b 100644 | |
--- a/src/main/java/co/aikar/timings/TimedEventExecutor.java | |
+++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java | |
@@ -31,6 +31,8 @@ import org.bukkit.plugin.EventExecutor; | |
import org.bukkit.plugin.Plugin; | |
import java.lang.reflect.Method; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
public class TimedEventExecutor implements EventExecutor { | |
@@ -45,7 +47,7 @@ public class TimedEventExecutor implements EventExecutor { | |
* @param method EventHandler method | |
* @param eventClass Owning class | |
*/ | |
- public TimedEventExecutor(EventExecutor executor, Plugin plugin, Method method, Class<? extends Event> eventClass) { | |
+ public TimedEventExecutor(@NotNull EventExecutor executor, @NotNull Plugin plugin, @Nullable Method method, @NotNull Class<? extends Event> eventClass) { | |
this.executor = executor; | |
String id; | |
@@ -69,13 +71,13 @@ public class TimedEventExecutor implements EventExecutor { | |
} | |
@Override | |
- public void execute(Listener listener, Event event) throws EventException { | |
+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { | |
if (event.isAsynchronous() || !Timings.timingsEnabled || !Bukkit.isPrimaryThread()) { | |
executor.execute(listener, event); | |
return; | |
} | |
- timings.startTiming(); | |
- executor.execute(listener, event); | |
- timings.stopTiming(); | |
+ try (Timing ignored = timings.startTiming()){ | |
+ executor.execute(listener, event); | |
+ } | |
} | |
} | |
diff --git a/src/main/java/co/aikar/timings/Timing.java b/src/main/java/co/aikar/timings/Timing.java | |
index b2260104..a21e5ead 100644 | |
--- a/src/main/java/co/aikar/timings/Timing.java | |
+++ b/src/main/java/co/aikar/timings/Timing.java | |
@@ -23,6 +23,9 @@ | |
*/ | |
package co.aikar.timings; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
+ | |
/** | |
* Provides an ability to time sections of code within the Minecraft Server | |
*/ | |
@@ -32,6 +35,7 @@ public interface Timing extends AutoCloseable { | |
* | |
* @return Timing | |
*/ | |
+ @NotNull | |
Timing startTiming(); | |
/** | |
@@ -48,6 +52,7 @@ public interface Timing extends AutoCloseable { | |
* | |
* @return Timing | |
*/ | |
+ @NotNull | |
Timing startTimingIfSync(); | |
/** | |
@@ -60,8 +65,9 @@ public interface Timing extends AutoCloseable { | |
void stopTimingIfSync(); | |
/** | |
- * Stops timing and disregards current timing data. | |
+ * @deprecated Doesn't do anything - Removed | |
*/ | |
+ @Deprecated | |
void abort(); | |
/** | |
@@ -69,6 +75,7 @@ public interface Timing extends AutoCloseable { | |
* | |
* @return TimingHandler | |
*/ | |
+ @Nullable | |
TimingHandler getTimingHandler(); | |
@Override | |
diff --git a/src/main/java/co/aikar/timings/TimingData.java b/src/main/java/co/aikar/timings/TimingData.java | |
index f222d6b7..a5d13a1e 100644 | |
--- a/src/main/java/co/aikar/timings/TimingData.java | |
+++ b/src/main/java/co/aikar/timings/TimingData.java | |
@@ -24,6 +24,7 @@ | |
package co.aikar.timings; | |
import java.util.List; | |
+import org.jetbrains.annotations.NotNull; | |
import static co.aikar.util.JSONUtil.toArray; | |
@@ -82,6 +83,7 @@ class TimingData { | |
return new TimingData(this); | |
} | |
+ @NotNull | |
List<Object> export() { | |
List<Object> list = toArray( | |
id, | |
diff --git a/src/main/java/co/aikar/timings/TimingHandler.java b/src/main/java/co/aikar/timings/TimingHandler.java | |
index 521c985e..cc0390c0 100644 | |
--- a/src/main/java/co/aikar/timings/TimingHandler.java | |
+++ b/src/main/java/co/aikar/timings/TimingHandler.java | |
@@ -25,22 +25,30 @@ package co.aikar.timings; | |
import co.aikar.util.LoadingIntMap; | |
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; | |
-import org.bukkit.Bukkit; | |
+import java.util.ArrayDeque; | |
+import java.util.Deque; | |
import java.util.concurrent.atomic.AtomicInteger; | |
import java.util.logging.Level; | |
+import java.util.logging.Logger; | |
+ | |
+import org.bukkit.Bukkit; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
class TimingHandler implements Timing { | |
private static AtomicInteger idPool = new AtomicInteger(1); | |
+ private static Deque<TimingHandler> TIMING_STACK = new ArrayDeque<>(); | |
final int id = idPool.getAndIncrement(); | |
- final String name; | |
+ final TimingIdentifier identifier; | |
private final boolean verbose; | |
private final Int2ObjectOpenHashMap<TimingData> children = new LoadingIntMap<>(TimingData::new); | |
final TimingData record; | |
+ private TimingHandler startParent; | |
private final TimingHandler groupHandler; | |
private long start = 0; | |
@@ -48,17 +56,10 @@ class TimingHandler implements Timing { | |
private boolean added; | |
private boolean timed; | |
private boolean enabled; | |
- private TimingHandler parent; | |
- | |
- TimingHandler(TimingIdentifier id) { | |
- if (id.name.startsWith("##")) { | |
- verbose = true; | |
- this.name = id.name.substring(3); | |
- } else { | |
- this.name = id.name; | |
- verbose = false; | |
- } | |
+ TimingHandler(@NotNull TimingIdentifier id) { | |
+ this.identifier = id; | |
+ this.verbose = id.name.startsWith("##"); | |
this.record = new TimingData(this.id); | |
this.groupHandler = id.groupHandler; | |
@@ -83,6 +84,7 @@ class TimingHandler implements Timing { | |
} | |
} | |
+ @NotNull | |
@Override | |
public Timing startTimingIfSync() { | |
startTiming(); | |
@@ -94,36 +96,62 @@ class TimingHandler implements Timing { | |
stopTiming(); | |
} | |
+ @NotNull | |
public Timing startTiming() { | |
- if (enabled && Bukkit.isPrimaryThread() && ++timingDepth == 1) { | |
+ if (!enabled || !Bukkit.isPrimaryThread()) { | |
+ return this; | |
+ } | |
+ if (++timingDepth == 1) { | |
+ startParent = TIMING_STACK.peekLast(); | |
start = System.nanoTime(); | |
- parent = TimingsManager.CURRENT; | |
- TimingsManager.CURRENT = this; | |
} | |
+ TIMING_STACK.addLast(this); | |
return this; | |
} | |
public void stopTiming() { | |
- if (enabled && timingDepth > 0 && Bukkit.isPrimaryThread() && --timingDepth == 0 && start != 0) { | |
- addDiff(System.nanoTime() - start); | |
- start = 0; | |
+ if (!enabled || timingDepth <= 0 || start == 0 || !Bukkit.isPrimaryThread()) { | |
+ return; | |
} | |
- } | |
- @Override | |
- public void abort() { | |
- if (enabled && timingDepth > 0) { | |
+ popTimingStack(); | |
+ if (--timingDepth == 0) { | |
+ addDiff(System.nanoTime() - start, startParent); | |
+ startParent = null; | |
start = 0; | |
} | |
} | |
- void addDiff(long diff) { | |
- if (TimingsManager.CURRENT == this) { | |
- TimingsManager.CURRENT = parent; | |
- if (parent != null) { | |
- parent.children.get(id).add(diff); | |
+ private void popTimingStack() { | |
+ TimingHandler last; | |
+ while ((last = TIMING_STACK.removeLast()) != this) { | |
+ last.timingDepth = 0; | |
+ String reportTo; | |
+ if ("Minecraft".equalsIgnoreCase(last.identifier.group)) { | |
+ reportTo = "Paper! This is a potential bug in Paper"; | |
+ } else { | |
+ reportTo = "the plugin " + last.identifier.group + "(Look for errors above this in the logs)"; | |
+ } | |
+ Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to " + reportTo + " (" + last.identifier + " did not stopTiming)", new Throwable()); | |
+ boolean found = TIMING_STACK.contains(this); | |
+ if (!found) { | |
+ // We aren't even in the stack... Don't pop everything | |
+ TIMING_STACK.addLast(last); | |
+ break; | |
} | |
} | |
+ } | |
+ | |
+ @Override | |
+ public final void abort() { | |
+ | |
+ } | |
+ | |
+ void addDiff(long diff, @Nullable TimingHandler parent) { | |
+ if (parent != null) { | |
+ parent.children.get(id).add(diff); | |
+ } | |
+ | |
record.add(diff); | |
if (!added) { | |
added = true; | |
@@ -131,15 +159,13 @@ class TimingHandler implements Timing { | |
TimingsManager.HANDLERS.add(this); | |
} | |
if (groupHandler != null) { | |
- groupHandler.addDiff(diff); | |
+ groupHandler.addDiff(diff, parent); | |
groupHandler.children.get(id).add(diff); | |
} | |
} | |
/** | |
* Reset this timer, setting all values to zero. | |
- * | |
- * @param full | |
*/ | |
void reset(boolean full) { | |
record.reset(); | |
@@ -153,6 +179,7 @@ class TimingHandler implements Timing { | |
checkEnabled(); | |
} | |
+ @NotNull | |
@Override | |
public TimingHandler getTimingHandler() { | |
return this; | |
@@ -169,8 +196,7 @@ class TimingHandler implements Timing { | |
} | |
/** | |
- * This is simply for the Closeable interface so it can be used with | |
- * try-with-resources () | |
+ * This is simply for the Closeable interface so it can be used with try-with-resources () | |
*/ | |
@Override | |
public void close() { | |
@@ -189,6 +215,7 @@ class TimingHandler implements Timing { | |
return enabled; | |
} | |
+ @NotNull | |
TimingData[] cloneChildren() { | |
final TimingData[] clonedChildren = new TimingData[children.size()]; | |
int i = 0; | |
diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java | |
index 769facd8..99815866 100644 | |
--- a/src/main/java/co/aikar/timings/TimingHistory.java | |
+++ b/src/main/java/co/aikar/timings/TimingHistory.java | |
@@ -24,9 +24,7 @@ | |
package co.aikar.timings; | |
import co.aikar.timings.TimingHistory.RegionData.RegionId; | |
-import co.aikar.util.JSONUtil; | |
import com.google.common.base.Function; | |
-import com.google.common.collect.Maps; | |
import com.google.common.collect.Sets; | |
import org.bukkit.Bukkit; | |
import org.bukkit.Chunk; | |
@@ -45,6 +43,8 @@ import java.util.EnumMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
import static co.aikar.timings.TimingsManager.FULL_SERVER_TICK; | |
import static co.aikar.timings.TimingsManager.MINUTE_REPORTS; | |
@@ -60,8 +60,9 @@ public class TimingHistory { | |
public static long activatedEntityTicks; | |
private static int worldIdPool = 1; | |
static Map<String, Integer> worldMap = LoadingMap.newHashMap(new Function<String, Integer>() { | |
+ @NotNull | |
@Override | |
- public Integer apply(String input) { | |
+ public Integer apply(@Nullable String input) { | |
return worldIdPool++; | |
} | |
}); | |
@@ -98,10 +99,10 @@ public class TimingHistory { | |
entries[i++] = new TimingHistoryEntry(handler); | |
} | |
- | |
// Information about all loaded chunks/entities | |
//noinspection unchecked | |
this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() { | |
+ @NotNull | |
@Override | |
public JSONPair apply(World world) { | |
Map<RegionId, RegionData> regions = LoadingMap.newHashMap(RegionData.LOADER); | |
@@ -130,6 +131,7 @@ public class TimingHistory { | |
return pair( | |
worldMap.get(world.getName()), | |
toArrayMapper(regions.values(),new Function<RegionData, Object>() { | |
+ @NotNull | |
@Override | |
public Object apply(RegionData input) { | |
return toArray( | |
@@ -137,6 +139,7 @@ public class TimingHistory { | |
input.regionId.z, | |
toObjectMapper(input.entityCounts.entrySet(), | |
new Function<Map.Entry<EntityType, Counter>, JSONPair>() { | |
+ @NotNull | |
@Override | |
public JSONPair apply(Map.Entry<EntityType, Counter> entry) { | |
entityTypeSet.add(entry.getKey()); | |
@@ -149,6 +152,7 @@ public class TimingHistory { | |
), | |
toObjectMapper(input.tileEntityCounts.entrySet(), | |
new Function<Map.Entry<Material, Counter>, JSONPair>() { | |
+ @NotNull | |
@Override | |
public JSONPair apply(Map.Entry<Material, Counter> entry) { | |
tileEntityTypeSet.add(entry.getKey()); | |
@@ -170,12 +174,13 @@ public class TimingHistory { | |
final RegionId regionId; | |
@SuppressWarnings("Guava") | |
static Function<RegionId, RegionData> LOADER = new Function<RegionId, RegionData>() { | |
+ @NotNull | |
@Override | |
- public RegionData apply(RegionId id) { | |
+ public RegionData apply(@NotNull RegionId id) { | |
return new RegionData(id); | |
} | |
}; | |
- RegionData(RegionId id) { | |
+ RegionData(@NotNull RegionId id) { | |
this.regionId = id; | |
} | |
@@ -201,11 +206,11 @@ public class TimingHistory { | |
@SuppressWarnings("unchecked") | |
final Map<EntityType, Counter> entityCounts = MRUMapCache.of(LoadingMap.of( | |
- new EnumMap<EntityType, Counter>(EntityType.class), Counter.LOADER | |
+ new EnumMap<EntityType, Counter>(EntityType.class), k -> new Counter() | |
)); | |
@SuppressWarnings("unchecked") | |
final Map<Material, Counter> tileEntityCounts = MRUMapCache.of(LoadingMap.of( | |
- new EnumMap<Material, Counter>(Material.class), Counter.LOADER | |
+ new EnumMap<Material, Counter>(Material.class), k -> new Counter() | |
)); | |
static class RegionId { | |
@@ -246,6 +251,7 @@ public class TimingHistory { | |
activatedEntityTicks = 0; | |
} | |
+ @NotNull | |
Object export() { | |
return createObject( | |
pair("s", startTime), | |
@@ -254,6 +260,7 @@ public class TimingHistory { | |
pair("tm", totalTime), | |
pair("w", worlds), | |
pair("h", toArrayMapper(entries, new Function<TimingHistoryEntry, Object>() { | |
+ @Nullable | |
@Override | |
public Object apply(TimingHistoryEntry entry) { | |
TimingData record = entry.data; | |
@@ -264,6 +271,7 @@ public class TimingHistory { | |
} | |
})), | |
pair("mp", toArrayMapper(minuteReports, new Function<MinuteReport, Object>() { | |
+ @NotNull | |
@Override | |
public Object apply(MinuteReport input) { | |
return input.export(); | |
@@ -283,6 +291,7 @@ public class TimingHistory { | |
final double freeMemory = TimingsManager.FULL_SERVER_TICK.avgFreeMemory; | |
final double loadAvg = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage(); | |
+ @NotNull | |
List<Object> export() { | |
return toArray( | |
time, | |
@@ -335,13 +344,6 @@ public class TimingHistory { | |
private static class Counter { | |
private int count = 0; | |
- @SuppressWarnings({"rawtypes", "SuppressionAnnotation", "Guava"}) | |
- static Function LOADER = new LoadingMap.Feeder<Counter>() { | |
- @Override | |
- public Counter apply() { | |
- return new Counter(); | |
- } | |
- }; | |
public int increment() { | |
return ++count; | |
} | |
diff --git a/src/main/java/co/aikar/timings/TimingHistoryEntry.java b/src/main/java/co/aikar/timings/TimingHistoryEntry.java | |
index 0e114eb3..86d5ac6b 100644 | |
--- a/src/main/java/co/aikar/timings/TimingHistoryEntry.java | |
+++ b/src/main/java/co/aikar/timings/TimingHistoryEntry.java | |
@@ -26,6 +26,7 @@ package co.aikar.timings; | |
import com.google.common.base.Function; | |
import java.util.List; | |
+import org.jetbrains.annotations.NotNull; | |
import static co.aikar.util.JSONUtil.toArrayMapper; | |
@@ -33,16 +34,18 @@ class TimingHistoryEntry { | |
final TimingData data; | |
private final TimingData[] children; | |
- TimingHistoryEntry(TimingHandler handler) { | |
+ TimingHistoryEntry(@NotNull TimingHandler handler) { | |
this.data = handler.record.clone(); | |
children = handler.cloneChildren(); | |
} | |
+ @NotNull | |
List<Object> export() { | |
List<Object> result = data.export(); | |
if (children.length > 0) { | |
result.add( | |
toArrayMapper(children, new Function<TimingData, Object>() { | |
+ @NotNull | |
@Override | |
public Object apply(TimingData child) { | |
return child.export(); | |
diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java | |
index 63b4f318..df142a89 100644 | |
--- a/src/main/java/co/aikar/timings/TimingIdentifier.java | |
+++ b/src/main/java/co/aikar/timings/TimingIdentifier.java | |
@@ -24,11 +24,16 @@ | |
package co.aikar.timings; | |
import co.aikar.util.LoadingMap; | |
-import co.aikar.util.MRUMapCache; | |
-import java.util.ArrayDeque; | |
+import java.util.ArrayList; | |
+import java.util.Collections; | |
+import java.util.List; | |
import java.util.Map; | |
+import java.util.Objects; | |
+import java.util.concurrent.ConcurrentHashMap; | |
import java.util.concurrent.atomic.AtomicInteger; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
/** | |
* <p>Used as a basis for fast HashMap key comparisons for the Timing Map.</p> | |
@@ -39,32 +44,30 @@ final class TimingIdentifier { | |
/** | |
* Holds all groups. Autoloads on request for a group by name. | |
*/ | |
- static final Map<String, TimingGroup> GROUP_MAP = MRUMapCache.of( | |
- LoadingMap.newIdentityHashMap(TimingGroup::new, 64) | |
- ); | |
+ static final Map<String, TimingGroup> GROUP_MAP = LoadingMap.of(new ConcurrentHashMap<>(64, .5F), TimingGroup::new); | |
private static final TimingGroup DEFAULT_GROUP = getGroup("Minecraft"); | |
final String group; | |
final String name; | |
final TimingHandler groupHandler; | |
private final int hashCode; | |
- TimingIdentifier(String group, String name, Timing groupHandler) { | |
- this.group = group != null ? group.intern() : DEFAULT_GROUP.name; | |
- this.name = name.intern(); | |
+ TimingIdentifier(@Nullable String group, @NotNull String name, @Nullable Timing groupHandler) { | |
+ this.group = group != null ? group: DEFAULT_GROUP.name; | |
+ this.name = name; | |
this.groupHandler = groupHandler != null ? groupHandler.getTimingHandler() : null; | |
this.hashCode = (31 * this.group.hashCode()) + this.name.hashCode(); | |
} | |
- static TimingGroup getGroup(String groupName) { | |
+ @NotNull | |
+ static TimingGroup getGroup(@Nullable String groupName) { | |
if (groupName == null) { | |
+ //noinspection ConstantConditions | |
return DEFAULT_GROUP; | |
} | |
- return GROUP_MAP.get(groupName.intern()); | |
+ return GROUP_MAP.get(groupName); | |
} | |
- // We are using .intern() on the strings so it is guaranteed to be an identity comparison. | |
- @SuppressWarnings("StringEquality") | |
@Override | |
public boolean equals(Object o) { | |
if (o == null) { | |
@@ -72,7 +75,7 @@ final class TimingIdentifier { | |
} | |
TimingIdentifier that = (TimingIdentifier) o; | |
- return group == that.group && name == that.name; | |
+ return Objects.equals(group, that.group) && Objects.equals(name, that.name); | |
} | |
@Override | |
@@ -80,13 +83,18 @@ final class TimingIdentifier { | |
return hashCode; | |
} | |
+ @Override | |
+ public String toString() { | |
+ return "TimingIdentifier{id=" + group + ":" + name +'}'; | |
+ } | |
+ | |
static class TimingGroup { | |
private static AtomicInteger idPool = new AtomicInteger(1); | |
final int id = idPool.getAndIncrement(); | |
final String name; | |
- ArrayDeque<TimingHandler> handlers = new ArrayDeque<TimingHandler>(64); | |
+ final List<TimingHandler> handlers = Collections.synchronizedList(new ArrayList<>(64)); | |
private TimingGroup(String name) { | |
this.name = name; | |
diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java | |
index f907649b..0b34e0d0 100644 | |
--- a/src/main/java/co/aikar/timings/Timings.java | |
+++ b/src/main/java/co/aikar/timings/Timings.java | |
@@ -32,6 +32,8 @@ import org.bukkit.plugin.Plugin; | |
import java.util.Queue; | |
import java.util.logging.Level; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
@SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "SameParameterValue"}) | |
public final class Timings { | |
@@ -52,7 +54,8 @@ public final class Timings { | |
* @param name Name of Timing | |
* @return Handler | |
*/ | |
- public static Timing of(Plugin plugin, String name) { | |
+ @NotNull | |
+ public static Timing of(@NotNull Plugin plugin, @NotNull String name) { | |
Timing pluginHandler = null; | |
if (plugin != null) { | |
pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); | |
@@ -72,7 +75,8 @@ public final class Timings { | |
* @param groupHandler Parent handler to mirror .start/stop calls to | |
* @return Timing Handler | |
*/ | |
- public static Timing of(Plugin plugin, String name, Timing groupHandler) { | |
+ @NotNull | |
+ public static Timing of(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { | |
Preconditions.checkNotNull(plugin, "Plugin can not be null"); | |
return TimingsManager.getHandler(plugin.getName(), name, groupHandler); | |
} | |
@@ -88,7 +92,8 @@ public final class Timings { | |
* @param name Name of Timing | |
* @return Timing Handler | |
*/ | |
- public static Timing ofStart(Plugin plugin, String name) { | |
+ @NotNull | |
+ public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name) { | |
return ofStart(plugin, name, null); | |
} | |
@@ -104,7 +109,8 @@ public final class Timings { | |
* @param groupHandler Parent handler to mirror .start/stop calls to | |
* @return Timing Handler | |
*/ | |
- public static Timing ofStart(Plugin plugin, String name, Timing groupHandler) { | |
+ @NotNull | |
+ public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { | |
Timing timing = of(plugin, name, groupHandler); | |
timing.startTiming(); | |
return timing; | |
@@ -238,7 +244,7 @@ public final class Timings { | |
* If sender is null, ConsoleCommandSender will be used. | |
* @param sender The sender to send to, or null to use the ConsoleCommandSender | |
*/ | |
- public static void generateReport(CommandSender sender) { | |
+ public static void generateReport(@Nullable CommandSender sender) { | |
if (sender == null) { | |
sender = Bukkit.getConsoleSender(); | |
} | |
@@ -250,7 +256,7 @@ public final class Timings { | |
* Use with {@link org.bukkit.command.BufferedCommandSender} to get full response when done! | |
* @param sender The listener to send responses too. | |
*/ | |
- public static void generateReport(TimingsReportListener sender) { | |
+ public static void generateReport(@NotNull TimingsReportListener sender) { | |
Validate.notNull(sender); | |
TimingsExport.requestingReport.add(sender); | |
} | |
@@ -261,12 +267,13 @@ public final class Timings { | |
These do not have isPrimaryThread() checks in the startTiming/stopTiming | |
================= | |
*/ | |
- | |
- static TimingHandler ofSafe(String name) { | |
+ @NotNull | |
+ static TimingHandler ofSafe(@NotNull String name) { | |
return ofSafe(null, name, null); | |
} | |
- static Timing ofSafe(Plugin plugin, String name) { | |
+ @NotNull | |
+ static Timing ofSafe(@Nullable Plugin plugin, @NotNull String name) { | |
Timing pluginHandler = null; | |
if (plugin != null) { | |
pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); | |
@@ -274,11 +281,13 @@ public final class Timings { | |
return ofSafe(plugin != null ? plugin.getName() : "Minecraft - Invalid Plugin", name, pluginHandler); | |
} | |
- static TimingHandler ofSafe(String name, Timing groupHandler) { | |
+ @NotNull | |
+ static TimingHandler ofSafe(@NotNull String name, @Nullable Timing groupHandler) { | |
return ofSafe(null, name, groupHandler); | |
} | |
- static TimingHandler ofSafe(String groupName, String name, Timing groupHandler) { | |
+ @NotNull | |
+ static TimingHandler ofSafe(@Nullable String groupName, @NotNull String name, @Nullable Timing groupHandler) { | |
return TimingsManager.getHandler(groupName, name, groupHandler); | |
} | |
} | |
diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java | |
index 56b10e89..c0d8f201 100644 | |
--- a/src/main/java/co/aikar/timings/TimingsCommand.java | |
+++ b/src/main/java/co/aikar/timings/TimingsCommand.java | |
@@ -32,13 +32,15 @@ import org.bukkit.util.StringUtil; | |
import java.util.ArrayList; | |
import java.util.List; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
public class TimingsCommand extends BukkitCommand { | |
private static final List<String> TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste", "verbon", "verboff"); | |
private long lastResetAttempt = 0; | |
- public TimingsCommand(String name) { | |
+ public TimingsCommand(@NotNull String name) { | |
super(name); | |
this.description = "Manages Spigot Timings data to see performance of the server."; | |
this.usageMessage = "/timings <reset|report|on|off|verbon|verboff>"; | |
@@ -46,7 +48,7 @@ public class TimingsCommand extends BukkitCommand { | |
} | |
@Override | |
- public boolean execute(CommandSender sender, String currentAlias, String[] args) { | |
+ public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) { | |
if (!testPermission(sender)) { | |
return true; | |
} | |
@@ -104,8 +106,9 @@ public class TimingsCommand extends BukkitCommand { | |
return true; | |
} | |
+ @NotNull | |
@Override | |
- public List<String> tabComplete(CommandSender sender, String alias, String[] args) { | |
+ public List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { | |
Validate.notNull(sender, "Sender cannot be null"); | |
Validate.notNull(args, "Arguments cannot be null"); | |
Validate.notNull(alias, "Alias cannot be null"); | |
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java | |
index df7f4259..65d312b0 100644 | |
--- a/src/main/java/co/aikar/timings/TimingsExport.java | |
+++ b/src/main/java/co/aikar/timings/TimingsExport.java | |
@@ -153,21 +153,34 @@ class TimingsExport extends Thread { | |
Map handlers = createObject(); | |
- for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { | |
- for (TimingHandler id : group.handlers) { | |
- if (!id.isTimed() && !id.isSpecial()) { | |
- continue; | |
+ Map groupData; | |
+ synchronized (TimingIdentifier.GROUP_MAP) { | |
+ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { | |
+ synchronized (group.handlers) { | |
+ for (TimingHandler id : group.handlers) { | |
+ | |
+ if (!id.isTimed() && !id.isSpecial()) { | |
+ continue; | |
+ } | |
+ | |
+ String name = id.identifier.name; | |
+ if (name.startsWith("##")) { | |
+ name = name.substring(3); | |
+ } | |
+ handlers.put(id.id, toArray( | |
+ group.id, | |
+ name | |
+ )); | |
+ } | |
} | |
- handlers.put(id.id, toArray( | |
- group.id, | |
- id.name | |
- )); | |
} | |
+ | |
+ groupData = toObjectMapper( | |
+ TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name)); | |
} | |
parent.put("idmap", createObject( | |
- pair("groups", toObjectMapper( | |
- TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name))), | |
+ pair("groups", groupData), | |
pair("handlers", handlers), | |
pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))), | |
pair("tileentity", | |
diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java | |
index 3443f9b7..ef824d70 100644 | |
--- a/src/main/java/co/aikar/timings/TimingsManager.java | |
+++ b/src/main/java/co/aikar/timings/TimingsManager.java | |
@@ -23,40 +23,37 @@ | |
*/ | |
package co.aikar.timings; | |
+import co.aikar.util.LoadingMap; | |
import com.google.common.collect.EvictingQueue; | |
import org.bukkit.Bukkit; | |
import org.bukkit.Server; | |
import org.bukkit.command.Command; | |
import org.bukkit.plugin.Plugin; | |
import org.bukkit.plugin.java.PluginClassLoader; | |
-import co.aikar.util.LoadingMap; | |
-import javax.annotation.Nullable; | |
-import java.util.ArrayDeque; | |
import java.util.ArrayList; | |
-import java.util.Collection; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.Map; | |
+import java.util.concurrent.ConcurrentHashMap; | |
import java.util.logging.Level; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
public final class TimingsManager { | |
- static final Map<TimingIdentifier, TimingHandler> TIMING_MAP = | |
- Collections.synchronizedMap(LoadingMap.newHashMap( | |
- TimingHandler::new, | |
- 4096, .5F | |
- )); | |
+ static final Map<TimingIdentifier, TimingHandler> TIMING_MAP = LoadingMap.of( | |
+ new ConcurrentHashMap<>(4096, .5F), TimingHandler::new | |
+ ); | |
public static final FullServerTickHandler FULL_SERVER_TICK = new FullServerTickHandler(); | |
public static final TimingHandler TIMINGS_TICK = Timings.ofSafe("Timings Tick", FULL_SERVER_TICK); | |
public static final Timing PLUGIN_GROUP_HANDLER = Timings.ofSafe("Plugins"); | |
public static List<String> hiddenConfigs = new ArrayList<String>(); | |
public static boolean privacy = false; | |
- static final Collection<TimingHandler> HANDLERS = new ArrayDeque<TimingHandler>(); | |
- static final ArrayDeque<TimingHistory.MinuteReport> MINUTE_REPORTS = new ArrayDeque<TimingHistory.MinuteReport>(); | |
+ static final List<TimingHandler> HANDLERS = new ArrayList<>(1024); | |
+ static final List<TimingHistory.MinuteReport> MINUTE_REPORTS = new ArrayList<>(64); | |
static EvictingQueue<TimingHistory> HISTORY = EvictingQueue.create(12); | |
- static TimingHandler CURRENT; | |
static long timingStart = 0; | |
static long historyStart = 0; | |
static boolean needsFullReset = false; | |
@@ -133,7 +130,8 @@ public final class TimingsManager { | |
historyStart = System.currentTimeMillis(); | |
} | |
- static TimingHandler getHandler(String group, String name, Timing parent) { | |
+ @NotNull | |
+ static TimingHandler getHandler(@Nullable String group, @NotNull String name, @Nullable Timing parent) { | |
return TIMING_MAP.get(new TimingIdentifier(group, name, parent)); | |
} | |
@@ -147,7 +145,8 @@ public final class TimingsManager { | |
* @param command Command to get timings for | |
* @return TimingHandler | |
*/ | |
- public static Timing getCommandTiming(String pluginName, Command command) { | |
+ @NotNull | |
+ public static Timing getCommandTiming(@Nullable String pluginName, @NotNull Command command) { | |
Plugin plugin = null; | |
final Server server = Bukkit.getServer(); | |
if (!( server == null || pluginName == null || | |
@@ -174,6 +173,7 @@ public final class TimingsManager { | |
* @param clazz Class to check | |
* @return Plugin if created by a plugin | |
*/ | |
+ @Nullable | |
public static Plugin getPluginByClassloader(@Nullable Class<?> clazz) { | |
if (clazz == null) { | |
return null; | |
diff --git a/src/main/java/co/aikar/timings/TimingsReportListener.java b/src/main/java/co/aikar/timings/TimingsReportListener.java | |
index e7c389c0..bf3e059f 100644 | |
--- a/src/main/java/co/aikar/timings/TimingsReportListener.java | |
+++ b/src/main/java/co/aikar/timings/TimingsReportListener.java | |
@@ -9,6 +9,8 @@ import org.bukkit.command.MessageCommandSender; | |
import org.bukkit.command.RemoteConsoleCommandSender; | |
import java.util.List; | |
+import org.jetbrains.annotations.NotNull; | |
+import org.jetbrains.annotations.Nullable; | |
@SuppressWarnings("WeakerAccess") | |
public class TimingsReportListener implements MessageCommandSender { | |
@@ -16,16 +18,16 @@ public class TimingsReportListener implements MessageCommandSender { | |
private final Runnable onDone; | |
private String timingsURL; | |
- public TimingsReportListener(CommandSender senders) { | |
+ public TimingsReportListener(@NotNull CommandSender senders) { | |
this(senders, null); | |
} | |
- public TimingsReportListener(CommandSender sender, Runnable onDone) { | |
+ public TimingsReportListener(@NotNull CommandSender sender, @Nullable Runnable onDone) { | |
this(Lists.newArrayList(sender), onDone); | |
} | |
- public TimingsReportListener(List<CommandSender> senders) { | |
+ public TimingsReportListener(@NotNull List<CommandSender> senders) { | |
this(senders, null); | |
} | |
- public TimingsReportListener(List<CommandSender> senders, Runnable onDone) { | |
+ public TimingsReportListener(@NotNull List<CommandSender> senders, @Nullable Runnable onDone) { | |
Validate.notNull(senders); | |
Validate.notEmpty(senders); | |
@@ -33,6 +35,7 @@ public class TimingsReportListener implements MessageCommandSender { | |
this.onDone = onDone; | |
} | |
+ @Nullable | |
public String getTimingsURL() { | |
return timingsURL; | |
} | |
@@ -41,7 +44,7 @@ public class TimingsReportListener implements MessageCommandSender { | |
done(null); | |
} | |
- public void done(String url) { | |
+ public void done(@Nullable String url) { | |
this.timingsURL = url; | |
if (onDone != null) { | |
onDone.run(); | |
@@ -54,7 +57,7 @@ public class TimingsReportListener implements MessageCommandSender { | |
} | |
@Override | |
- public void sendMessage(String message) { | |
+ public void sendMessage(@NotNull String message) { | |
senders.forEach((sender) -> sender.sendMessage(message)); | |
} | |
diff --git a/src/main/java/co/aikar/timings/UnsafeTimingHandler.java b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java | |
index 5edaba12..632c4961 100644 | |
--- a/src/main/java/co/aikar/timings/UnsafeTimingHandler.java | |
+++ b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java | |
@@ -24,10 +24,11 @@ | |
package co.aikar.timings; | |
import org.bukkit.Bukkit; | |
+import org.jetbrains.annotations.NotNull; | |
class UnsafeTimingHandler extends TimingHandler { | |
- UnsafeTimingHandler(TimingIdentifier id) { | |
+ UnsafeTimingHandler(@NotNull TimingIdentifier id) { | |
super(id); | |
} | |
@@ -37,6 +38,7 @@ class UnsafeTimingHandler extends TimingHandler { | |
} | |
} | |
+ @NotNull | |
@Override | |
public Timing startTiming() { | |
checkThread(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment