Skip to content

Instantly share code, notes, and snippets.

@aikar
Created April 5, 2019 04:33
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/bccbb8666af819fb42e3f2d1c66f966a to your computer and use it in GitHub Desktop.
Save aikar/bccbb8666af819fb42e3f2d1c66f966a 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 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