aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1002-Optimize-Voxel-Shape-Merging.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/1002-Optimize-Voxel-Shape-Merging.patch')
-rw-r--r--patches/server/1002-Optimize-Voxel-Shape-Merging.patch123
1 files changed, 123 insertions, 0 deletions
diff --git a/patches/server/1002-Optimize-Voxel-Shape-Merging.patch b/patches/server/1002-Optimize-Voxel-Shape-Merging.patch
new file mode 100644
index 0000000000..114ee7cb28
--- /dev/null
+++ b/patches/server/1002-Optimize-Voxel-Shape-Merging.patch
@@ -0,0 +1,123 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+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/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
+index e164c524aef4fa81fe96ac43454eecff1c38b9c1..9cfbbc61fcfc678f0988d6d45c7994d128051744 100644
+--- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
++++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
+@@ -10,12 +10,33 @@ public class IndirectMerger implements IndexMerger {
+ private final int[] firstIndices;
+ private final int[] secondIndices;
+ private final int resultLength;
++ // Paper start
++ private static final int[] INFINITE_B_1 = new int[]{1, 1};
++ private static final int[] INFINITE_B_0 = new int[]{0, 0};
++ private static final int[] INFINITE_C = new int[]{0, 1};
++ // Paper end
+
+ public IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) {
+ double d = Double.NaN;
+ int i = first.size();
+ int j = second.size();
+ int k = i + j;
++ // Paper start - optimize common path of infinity doublelist
++ int size = first.size();
++ double tail = first.getDouble(size - 1);
++ double head = first.getDouble(0);
++ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) {
++ this.result = second.toDoubleArray();
++ this.resultLength = second.size();
++ if (size == 2) {
++ this.firstIndices = INFINITE_B_0;
++ } else {
++ this.firstIndices = INFINITE_B_1;
++ }
++ this.secondIndices = INFINITE_C;
++ return;
++ }
++ // Paper end
+ this.result = new double[k];
+ this.firstIndices = new int[k];
+ this.secondIndices = new int[k];
+diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+index 7ede56f77af1d40e10fde2e660d5794e4b37dc5d..c348171c150bf69d24303d0862e45ab78baddcab 100644
+--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
++++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+@@ -343,9 +343,21 @@ public final class Shapes {
+ }
+
+ @VisibleForTesting
+- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
++ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // 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 (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) {
++ return new IndirectMerger(first, second, includeFirst, includeSecond);
++ }
++ // Split out rest to hopefully inline the above
++ return lessCommonMerge(size, first, second, includeFirst, includeSecond);
++ }
++
++ private static IndexMerger lessCommonMerge(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
+ int i = first.size() - 1;
+ int j = second.size() - 1;
++ // Paper note - Rewrite below as optimized order if instead of nasty ternary
+ if (first instanceof CubePointRange && second instanceof CubePointRange) {
+ long l = lcm(i, j);
+ if ((long)size * l <= 256L) {
+@@ -353,15 +365,22 @@ public final class Shapes {
+ }
+ }
+
+- if (first.getDouble(i) < second.getDouble(0) - 1.0E-7) {
++ // Paper start - Identical happens more often than Disjoint
++ if (i == j && Objects.equals(first, second)) {
++ if (first instanceof IdenticalMerger) {
++ return (IndexMerger) first;
++ } else if (second instanceof IdenticalMerger) {
++ return (IndexMerger) second;
++ }
++ return new IdenticalMerger(first);
++ } else if (first.getDouble(i) < second.getDouble(0) - 1.0E-7) {
+ return new NonOverlappingMerger(first, second, false);
+ } else if (second.getDouble(j) < first.getDouble(0) - 1.0E-7) {
+ return new NonOverlappingMerger(second, first, true);
+ } else {
+- return (IndexMerger)(i == j && Objects.equals(first, second)
+- ? new IdenticalMerger(first)
+- : new IndirectMerger(first, second, includeFirst, includeSecond));
++ return new IndirectMerger(first, second, includeFirst, includeSecond);
+ }
++ // Paper end
+ }
+
+ public interface DoubleLineConsumer {