Created
April 5, 2019 04:33
-
-
Save aikar/bccbb8666af819fb42e3f2d1c66f966a 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 f6d61673..64531fcc 100644 | |
--- a/src/main/java/co/aikar/timings/FullServerTickHandler.java | |
+++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java | |
@@ -53,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 8e0cd40e..9b45ce88 100644 | |
--- a/src/main/java/co/aikar/timings/NullTimingHandler.java | |
+++ b/src/main/java/co/aikar/timings/NullTimingHandler.java | |
@@ -27,6 +27,7 @@ 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() { | |
diff --git a/src/main/java/co/aikar/timings/TimedEventExecutor.java b/src/main/java/co/aikar/timings/TimedEventExecutor.java | |
index 68f7866e..933ecf9b 100644 | |
--- a/src/main/java/co/aikar/timings/TimedEventExecutor.java | |
+++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java | |
@@ -76,8 +76,8 @@ public class TimedEventExecutor implements EventExecutor { | |
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 a562796c..a21e5ead 100644 | |
--- a/src/main/java/co/aikar/timings/Timing.java | |
+++ b/src/main/java/co/aikar/timings/Timing.java | |
@@ -65,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(); | |
/** | |
diff --git a/src/main/java/co/aikar/timings/TimingHandler.java b/src/main/java/co/aikar/timings/TimingHandler.java | |
index 6bf8cb68..cc0390c0 100644 | |
--- a/src/main/java/co/aikar/timings/TimingHandler.java | |
+++ b/src/main/java/co/aikar/timings/TimingHandler.java | |
@@ -25,21 +25,30 @@ package co.aikar.timings; | |
import co.aikar.util.LoadingIntMap; | |
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; | |
+ | |
+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; | |
@@ -47,17 +56,10 @@ class TimingHandler implements Timing { | |
private boolean added; | |
private boolean timed; | |
private boolean enabled; | |
- private TimingHandler parent; | |
TimingHandler(@NotNull TimingIdentifier id) { | |
- if (id.name.startsWith("##")) { | |
- verbose = true; | |
- this.name = id.name.substring(3); | |
- } else { | |
- this.name = id.name; | |
- verbose = false; | |
- } | |
- | |
+ this.identifier = id; | |
+ this.verbose = id.name.startsWith("##"); | |
this.record = new TimingData(this.id); | |
this.groupHandler = id.groupHandler; | |
@@ -96,35 +98,60 @@ class TimingHandler implements Timing { | |
@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; | |
@@ -132,7 +159,7 @@ class TimingHandler implements Timing { | |
TimingsManager.HANDLERS.add(this); | |
} | |
if (groupHandler != null) { | |
- groupHandler.addDiff(diff); | |
+ groupHandler.addDiff(diff, parent); | |
groupHandler.children.get(id).add(diff); | |
} | |
} | |
diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java | |
index 21b929f9..99815866 100644 | |
--- a/src/main/java/co/aikar/timings/TimingHistory.java | |
+++ b/src/main/java/co/aikar/timings/TimingHistory.java | |
@@ -92,16 +92,13 @@ public class TimingHistory { | |
} | |
this.totalTicks = ticks; | |
this.totalTime = FULL_SERVER_TICK.record.getTotalTime(); | |
- synchronized (TimingsManager.HANDLERS) { | |
- this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()]; | |
+ this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()]; | |
- int i = 0; | |
- for (TimingHandler handler : TimingsManager.HANDLERS) { | |
- entries[i++] = new TimingHistoryEntry(handler); | |
- } | |
+ int i = 0; | |
+ for (TimingHandler handler : TimingsManager.HANDLERS) { | |
+ entries[i++] = new TimingHistoryEntry(handler); | |
} | |
- | |
// Information about all loaded chunks/entities | |
//noinspection unchecked | |
this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() { | |
diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java | |
index 4d140f34..df142a89 100644 | |
--- a/src/main/java/co/aikar/timings/TimingIdentifier.java | |
+++ b/src/main/java/co/aikar/timings/TimingIdentifier.java | |
@@ -83,6 +83,11 @@ final class TimingIdentifier { | |
return hashCode; | |
} | |
+ @Override | |
+ public String toString() { | |
+ return "TimingIdentifier{id=" + group + ":" + name +'}'; | |
+ } | |
+ | |
static class TimingGroup { | |
private static AtomicInteger idPool = new AtomicInteger(1); | |
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java | |
index 4a69074a..65d312b0 100644 | |
--- a/src/main/java/co/aikar/timings/TimingsExport.java | |
+++ b/src/main/java/co/aikar/timings/TimingsExport.java | |
@@ -162,9 +162,14 @@ class TimingsExport extends Thread { | |
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, | |
- id.name | |
+ name | |
)); | |
} | |
} | |
diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java | |
index 0109065d..ef824d70 100644 | |
--- a/src/main/java/co/aikar/timings/TimingsManager.java | |
+++ b/src/main/java/co/aikar/timings/TimingsManager.java | |
@@ -50,11 +50,10 @@ public final class TimingsManager { | |
public static List<String> hiddenConfigs = new ArrayList<String>(); | |
public static boolean privacy = false; | |
- static final List<TimingHandler> HANDLERS = Collections.synchronizedList(new ArrayList<>(1024)); | |
+ 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; | |
@@ -77,14 +76,12 @@ public final class TimingsManager { | |
if (Timings.timingsEnabled) { | |
boolean violated = FULL_SERVER_TICK.isViolated(); | |
- synchronized (HANDLERS) { | |
- for (TimingHandler handler : HANDLERS) { | |
- if (handler.isSpecial()) { | |
- // We manually call this | |
- continue; | |
- } | |
- handler.processTick(violated); | |
+ for (TimingHandler handler : HANDLERS) { | |
+ if (handler.isSpecial()) { | |
+ // We manually call this | |
+ continue; | |
} | |
+ handler.processTick(violated); | |
} | |
TimingHistory.playerTicks += Bukkit.getOnlinePlayers().size(); | |
@@ -121,10 +118,8 @@ public final class TimingsManager { | |
} else { | |
// Soft resets only need to act on timings that have done something | |
// Handlers can only be modified on main thread. | |
- synchronized (HANDLERS) { | |
- for (TimingHandler timings : HANDLERS) { | |
- timings.reset(false); | |
- } | |
+ for (TimingHandler timings : HANDLERS) { | |
+ timings.reset(false); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment