Timings Improvements

use a better stack for managing timing tree relationships
remove unnecessary synchronization (i forgot HANDLERS is only touched on main)

this should hopefully resolve any data integrity concerns
This commit is contained in:
Aikar 2019-03-24 17:47:23 -04:00
parent 5fc918bbf1
commit 4c807f929e
No known key found for this signature in database
GPG Key ID: 401ADFC9891FAAFE
3 changed files with 78 additions and 74 deletions

View File

@ -1,4 +1,4 @@
From d207bdace7d156b6b41a793c67dc8c457f397ab7 Mon Sep 17 00:00:00 2001
From 5c0ebe352e7ae47be75b657d8ff45ed1751a9dd0 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 29 Feb 2016 18:48:17 -0600
Subject: [PATCH] Timings v2
@ -6,10 +6,10 @@ Subject: [PATCH] Timings v2
diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java
new file mode 100644
index 000000000..f6d616732
index 000000000..64531fcce
--- /dev/null
+++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java
@@ -0,0 +1,85 @@
@@ -0,0 +1,84 @@
+package co.aikar.timings;
+
+import static co.aikar.timings.TimingsManager.*;
@ -65,8 +65,7 @@ index 000000000..f6d616732
+ 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);
+
@ -259,10 +258,10 @@ index 000000000..68f7866e1
+}
diff --git a/src/main/java/co/aikar/timings/Timing.java b/src/main/java/co/aikar/timings/Timing.java
new file mode 100644
index 000000000..a562796ce
index 000000000..a21e5ead5
--- /dev/null
+++ b/src/main/java/co/aikar/timings/Timing.java
@@ -0,0 +1,82 @@
@@ -0,0 +1,83 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
@ -330,8 +329,9 @@ index 000000000..a562796ce
+ void stopTimingIfSync();
+
+ /**
+ * Stops timing and disregards current timing data.
+ * @deprecated Doesn't do anything - Removed
+ */
+ @Deprecated
+ void abort();
+
+ /**
@ -475,10 +475,10 @@ index 000000000..a5d13a1e4
+}
diff --git a/src/main/java/co/aikar/timings/TimingHandler.java b/src/main/java/co/aikar/timings/TimingHandler.java
new file mode 100644
index 000000000..6bf8cb688
index 000000000..4e6994098
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingHandler.java
@@ -0,0 +1,200 @@
@@ -0,0 +1,201 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
@ -506,16 +506,23 @@ index 000000000..6bf8cb688
+
+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;
+
+class TimingHandler implements Timing {
+
+ private static AtomicInteger idPool = new AtomicInteger(1);
+ 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);
@ -528,17 +535,10 @@ index 000000000..6bf8cb688
+ 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;
+
@ -579,33 +579,34 @@ index 000000000..6bf8cb688
+ public Timing startTiming() {
+ if (enabled && Bukkit.isPrimaryThread() && ++timingDepth == 1) {
+ 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);
+ TimingHandler last = TIMING_STACK.removeLast();
+ if (last != this) {
+ Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to Paper! ( " + this.identifier + ":" + last +")", new Throwable());
+ TIMING_STACK.addLast(last); // Add it back
+ }
+ addDiff(System.nanoTime() - start, TIMING_STACK.peekLast());
+
+ start = 0;
+ }
+ }
+
+ @Override
+ public void abort() {
+ if (enabled && timingDepth > 0) {
+ start = 0;
+ }
+ public final void abort() {
+
+ }
+
+ void addDiff(long diff) {
+ if (TimingsManager.CURRENT == this) {
+ TimingsManager.CURRENT = parent;
+ if (parent != null) {
+ parent.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;
@ -613,7 +614,7 @@ index 000000000..6bf8cb688
+ TimingsManager.HANDLERS.add(this);
+ }
+ if (groupHandler != null) {
+ groupHandler.addDiff(diff);
+ groupHandler.addDiff(diff, parent);
+ groupHandler.children.get(id).add(diff);
+ }
+ }
@ -681,10 +682,10 @@ index 000000000..6bf8cb688
+}
diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java
new file mode 100644
index 000000000..8726bb9a2
index 000000000..043695239
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingHistory.java
@@ -0,0 +1,357 @@
@@ -0,0 +1,354 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
@ -779,16 +780,13 @@ index 000000000..8726bb9a2
+ }
+ 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>() {
@ -1108,10 +1106,10 @@ index 000000000..86d5ac6bd
+}
diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java
new file mode 100644
index 000000000..4d140f344
index 000000000..df142a89b
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingIdentifier.java
@@ -0,0 +1,111 @@
@@ -0,0 +1,116 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
@ -1197,6 +1195,11 @@ index 000000000..4d140f344
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "TimingIdentifier{id=" + group + ":" + name +'}';
+ }
+
+ static class TimingGroup {
+
+ private static AtomicInteger idPool = new AtomicInteger(1);
@ -1652,10 +1655,10 @@ index 000000000..c0d8f2016
+}
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
new file mode 100644
index 000000000..4a69074a8
index 000000000..65d312b02
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -0,0 +1,350 @@
@@ -0,0 +1,355 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
@ -1820,9 +1823,14 @@ index 000000000..4a69074a8
+ 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
+ ));
+ }
+ }
@ -2008,10 +2016,10 @@ index 000000000..4a69074a8
+}
diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java
new file mode 100644
index 000000000..0109065d3
index 000000000..ef824d701
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingsManager.java
@@ -0,0 +1,193 @@
@@ -0,0 +1,188 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
@ -2064,11 +2072,10 @@ index 000000000..0109065d3
+ 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;
@ -2091,14 +2098,12 @@ index 000000000..0109065d3
+ 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();
@ -2135,10 +2140,8 @@ index 000000000..0109065d3
+ } 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);
+ }
+ }
+
@ -2391,7 +2394,7 @@ index 000000000..80155072d
+}
diff --git a/src/main/java/co/aikar/util/JSONUtil.java b/src/main/java/co/aikar/util/JSONUtil.java
new file mode 100644
index 000000000..e43599b47
index 000000000..190bf0598
--- /dev/null
+++ b/src/main/java/co/aikar/util/JSONUtil.java
@@ -0,0 +1,140 @@
@ -2441,7 +2444,7 @@ index 000000000..e43599b47
+ * @return Map
+ */
+ @NotNull
+ public static Map createObject(@NotNull JSONPair... data) {
+ public static Map<String, Object> createObject(@NotNull JSONPair... data) {
+ return appendObjectData(new LinkedHashMap(), data);
+ }
+
@ -2453,7 +2456,7 @@ index 000000000..e43599b47
+ * @return Map
+ */
+ @NotNull
+ public static Map appendObjectData(@NotNull Map parent, @NotNull JSONPair... data) {
+ public static Map<String, Object> appendObjectData(@NotNull Map parent, @NotNull JSONPair... data) {
+ for (JSONPair JSONPair : data) {
+ parent.put(JSONPair.key, JSONPair.val);
+ }
@ -3179,7 +3182,7 @@ index 000000000..f9a00aecc
+ }
+}
diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java
index b354b617f..01ea1ca67 100644
index dafc4ed93..c2c19ed42 100644
--- a/src/main/java/org/bukkit/command/Command.java
+++ b/src/main/java/org/bukkit/command/Command.java
@@ -35,7 +35,8 @@ public abstract class Command {

View File

@ -1,4 +1,4 @@
From 5fda55b242bfa249aed8325120b652cc33f04288 Mon Sep 17 00:00:00 2001
From 70e2fb3da9e5ab207150021fb5f3787c2dd216e8 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Thu, 3 Mar 2016 13:20:33 -0700
Subject: [PATCH] Use ASM for event executors.
@ -29,16 +29,17 @@ index 524231ecc..082f2f0c5 100644
<build>
diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
new file mode 100644
index 000000000..72318d42d
index 000000000..5b28e9b1d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java
@@ -0,0 +1,41 @@
@@ -0,0 +1,42 @@
+package com.destroystokyo.paper.event.executor;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventException;
+import org.bukkit.event.Listener;
@ -70,7 +71,7 @@ index 000000000..72318d42d
+ try {
+ handle.invoke(listener, event);
+ } catch (Throwable t) {
+ throw new EventException(t);
+ SneakyThrow.sneaky(t);
+ }
+ }
+}

View File

@ -1,14 +1,14 @@
From 9b0f9c9ee09a34ffae2c2a19e184e5a4a81ecace Mon Sep 17 00:00:00 2001
From 85faf4182bc480db78d548ee3fc732cfa3262cdb Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 15 Aug 2018 01:19:37 -0400
Subject: [PATCH] Don't use snapshots for Timings Tile Entity reports
diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java
index 8726bb9a2..21b929f94 100644
index 043695239..99815866b 100644
--- a/src/main/java/co/aikar/timings/TimingHistory.java
+++ b/src/main/java/co/aikar/timings/TimingHistory.java
@@ -122,7 +122,7 @@ public class TimingHistory {
@@ -119,7 +119,7 @@ public class TimingHistory {
data.entityCounts.get(entity.getType()).increment();
}