2020-05-06 11:48:49 +02:00
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
2020-05-04 05:02:52 +02:00
|
|
|
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
|
2020-05-06 11:48:49 +02:00
|
|
|
index 71d2ae2a9c5a05351241b5a313e66ca15b0624ef..232b0023773008c19f19ad4658eb40fcd08c0333 100644
|
2020-05-04 05:02:52 +02:00
|
|
|
--- 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
|
2020-08-25 04:22:08 +02:00
|
|
|
index dd91a57f994f1c23464f5e33ca332529d7d9ea19..450957c41e144ef2b238051c4d5a242ca2b9ae83 100644
|
2020-05-04 05:02:52 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/VoxelShapes.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/VoxelShapes.java
|
2020-04-22 17:11:50 +02:00
|
|
|
@@ -319,9 +319,21 @@ public final class VoxelShapes {
|
2020-05-04 05:02:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@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);
|
2020-04-22 17:11:50 +02:00
|
|
|
@@ -331,7 +343,22 @@ public final class VoxelShapes {
|
2020-05-04 05:02:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- 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 {
|