Archiviert
13
0
Dieses Repository wurde am 2024-12-25 archiviert. Du kannst Dateien ansehen und es klonen, aber nicht pushen oder Issues/Pull-Requests öffnen.
Paper-Old/Spigot-Server-Patches/0499-Optimize-Voxel-Shape-Merging.patch
Aikar f37381ea8a
Optimize Network Manager to not need synchronization
Removes synchronization from sending packets
Makes normal packet sends no longer need to be wrapped and queued like it use to work.
Adds more packet queue immunities on top of keep alive to let the following scenarios go out
without delay:
  - Keep Alive
  - Chat
  - Kick
  - All of the packets during the Player Joined World event

Hoping that latter one helps join timeout issues more too for slow connections.

Removes processing packet queue off of main thread
  - for the few cases where it is allowed, order is not necessary nor
    should it even be happening concurrently in first place (handshaking/login/status)

Ensures packets sent asynchronously are dispatched on main thread

This helps ensure safety for ProtocolLib as packet listeners
are commonly accessing world state. This will allow you to schedule
a packet to be sent async, but itll be dispatched sync for packet
listeners to process.

This should solve some deadlock risks

This may provide a decent performance improvement because thread synchronization incurs a cache reset
so by avoiding ever entering a synchronized block, we get to avoid that, and packet sending is a really
hot activity.
2020-05-06 05:28:47 -04:00

131 Zeilen
6.5 KiB
Diff

From c9336ba6dcc9a9573528c62c22be1ddd7f6e1d07 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 May 2020 22:35:09 -0400
Subject: [PATCH] Optimize Voxel Shape Merging
This method shows up as super hot in profiler, and also a high "self" time.
Upon analyzing, it appears most usages of this method fall down to the final
else statement of the nasty ternary.
Upon even further analyzation, it appears then the majority of those have a
consistent list 1.... One with Infinity head and Tails.
First optimization is to detect these infinite states and immediately return that
VoxelShapeMergerList so we can avoid testing the rest for most cases.
Break the method into 2 to help the JVM promote inlining of this fast path.
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
with a high self time...
Well, knowing that in most cases our list 1 is actualy the same value, it allows
us to know that with an infinite list1, the result on the merger is essentially
list2 as the final values.
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
and compute a deterministic result for the MergerList values.
Additionally, this lets us avoid even allocating new objects for this too, further
reducing memory usage.
diff --git a/src/main/java/net/minecraft/server/VoxelShapeMergerList.java b/src/main/java/net/minecraft/server/VoxelShapeMergerList.java
index 71d2ae2a9c5..232b0023773 100644
--- a/src/main/java/net/minecraft/server/VoxelShapeMergerList.java
+++ b/src/main/java/net/minecraft/server/VoxelShapeMergerList.java
@@ -6,10 +6,16 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
public final class VoxelShapeMergerList implements VoxelShapeMerger {
- private final DoubleArrayList a;
+ private final DoubleList a; // Paper
private final IntArrayList b;
private final IntArrayList c;
+ // Paper start
+ private static final IntArrayList INFINITE_B_1 = new IntArrayList(new int[]{1, 1});
+ private static final IntArrayList INFINITE_B_0 = new IntArrayList(new int[]{0, 0});
+ private static final IntArrayList INFINITE_C = new IntArrayList(new int[]{0, 1});
+ // Paper end
+
protected VoxelShapeMergerList(DoubleList doublelist, DoubleList doublelist1, boolean flag, boolean flag1) {
int i = 0;
int j = 0;
@@ -18,6 +24,22 @@ public final class VoxelShapeMergerList implements VoxelShapeMerger {
int l = doublelist1.size();
int i1 = k + l;
+ // Paper start - optimize common path of infinity doublelist
+ int size = doublelist.size();
+ double tail = doublelist.getDouble(size - 1);
+ double head = doublelist.getDouble(0);
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !flag && !flag1 && (size == 2 || size == 4)) {
+ this.a = doublelist1;
+ if (size == 2) {
+ this.b = INFINITE_B_0;
+ } else {
+ this.b = INFINITE_B_1;
+ }
+ this.c = INFINITE_C;
+ return;
+ }
+ // Paper end
+
this.a = new DoubleArrayList(i1);
this.b = new IntArrayList(i1);
this.c = new IntArrayList(i1);
diff --git a/src/main/java/net/minecraft/server/VoxelShapes.java b/src/main/java/net/minecraft/server/VoxelShapes.java
index 08c83c62dfe..bb3a1a97df9 100644
--- a/src/main/java/net/minecraft/server/VoxelShapes.java
+++ b/src/main/java/net/minecraft/server/VoxelShapes.java
@@ -316,9 +316,21 @@ public final class VoxelShapes {
}
@VisibleForTesting
- protected static VoxelShapeMerger a(int i, DoubleList doublelist, DoubleList doublelist1, boolean flag, boolean flag1) {
+ private static VoxelShapeMerger a(int i, DoubleList doublelist, DoubleList doublelist1, boolean flag, boolean flag1) { // Paper - private
+ // Paper start - fast track the most common scenario
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
+ // This is actually the most common path, so jump to it straight away
+ if (doublelist.getDouble(0) == Double.NEGATIVE_INFINITY && doublelist.getDouble(doublelist.size() - 1) == Double.POSITIVE_INFINITY) {
+ return new VoxelShapeMergerList(doublelist, doublelist1, flag, flag1);
+ }
+ // Split out rest to hopefully inline the above
+ return lessCommonMerge(i, doublelist, doublelist1, flag, flag1);
+ }
+
+ private static VoxelShapeMerger lessCommonMerge(int i, DoubleList doublelist, DoubleList doublelist1, boolean flag, boolean flag1) {
int j = doublelist.size() - 1;
int k = doublelist1.size() - 1;
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
if (doublelist instanceof VoxelShapeCubePoint && doublelist1 instanceof VoxelShapeCubePoint) {
long l = a(j, k);
@@ -328,7 +340,22 @@ public final class VoxelShapes {
}
}
- return (VoxelShapeMerger) (doublelist.getDouble(j) < doublelist1.getDouble(0) - 1.0E-7D ? new VoxelShapeMergerDisjoint(doublelist, doublelist1, false) : (doublelist1.getDouble(k) < doublelist.getDouble(0) - 1.0E-7D ? new VoxelShapeMergerDisjoint(doublelist1, doublelist, true) : (j == k && Objects.equals(doublelist, doublelist1) ? (doublelist instanceof VoxelShapeMergerIdentical ? (VoxelShapeMerger) doublelist : (doublelist1 instanceof VoxelShapeMergerIdentical ? (VoxelShapeMerger) doublelist1 : new VoxelShapeMergerIdentical(doublelist))) : new VoxelShapeMergerList(doublelist, doublelist1, flag, flag1))));
+ // Identical happens more often than Disjoint
+ if (j == k && Objects.equals(doublelist, doublelist1)) {
+ if (doublelist instanceof VoxelShapeMergerIdentical) {
+ return (VoxelShapeMerger) doublelist;
+ } else if (doublelist1 instanceof VoxelShapeMergerIdentical) {
+ return (VoxelShapeMerger) doublelist1;
+ }
+ return new VoxelShapeMergerIdentical(doublelist);
+ } else if (doublelist.getDouble(j) < doublelist1.getDouble(0) - 1.0E-07) {
+ return new VoxelShapeMergerDisjoint(doublelist, doublelist1, false);
+ } else if (doublelist1.getDouble(k) < doublelist.getDouble(0) - 1.0E-07) {
+ return new VoxelShapeMergerDisjoint(doublelist1, doublelist, true);
+ } else {
+ return new VoxelShapeMergerList(doublelist, doublelist1, flag, flag1);
+ }
+ // Paper end
}
public interface a {
--
2.26.2