Skip to content

Instantly share code, notes, and snippets.

@aikar
Created April 5, 2019 04:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aikar/ec37231bd2ab2ca5ff4d275cc84d110c to your computer and use it in GitHub Desktop.
Save aikar/ec37231bd2ab2ca5ff4d275cc84d110c to your computer and use it in GitHub Desktop.
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