From 38f0f0b71a79fd35147cfa8d28007928e866b4a7 Mon Sep 17 00:00:00 2001 From: Aikar Date: Tue, 2 Oct 2018 22:29:31 -0400 Subject: [PATCH] Disable use of Locks on main thread for DataPaletteBlock This should greatly improve performance by using a No Op lock while on the main thread. Vanilla always had a write lock on write operations, but we added a Read Lock during Async Chunks to make concurrent writes non fatal for Async Chunks. This means we added on a bunch of over head to all chunk read operations. This corrects that, as well as disabling the write lock while on main thread. It is a general rule that you do not touch a chunk async once it is loaded into the world, as we never had locks on the chunk before 1.13 even. So once we are on main, we don't expect concurrent access to begin with, so we don't need the write locks either. --- ...7-Async-Chunk-Loading-and-Generation.patch | 89 +++++++++++++++---- .../0380-Optimize-Light-Recalculations.patch | 8 +- ...t-recheck-type-after-setting-a-block.patch | 6 +- .../0383-Fix-Sending-Chunks-to-Client.patch | 10 +-- 4 files changed, 86 insertions(+), 27 deletions(-) diff --git a/Spigot-Server-Patches/0377-Async-Chunk-Loading-and-Generation.patch b/Spigot-Server-Patches/0377-Async-Chunk-Loading-and-Generation.patch index 9db05ed2b2..6aba229aa8 100644 --- a/Spigot-Server-Patches/0377-Async-Chunk-Loading-and-Generation.patch +++ b/Spigot-Server-Patches/0377-Async-Chunk-Loading-and-Generation.patch @@ -1,4 +1,4 @@ -From 446a8037bfb38116cc712bf89d52dde7cd5aff68 Mon Sep 17 00:00:00 2001 +From 523a76f0b9a204e83620100df735b2228c22306e Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 21 Jul 2018 16:55:04 -0400 Subject: [PATCH] Async Chunk Loading and Generation @@ -345,6 +345,18 @@ index 0000000000..0a9fd5d662 + }; + +} +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index 9162151e2a..15a327923f 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -184,6 +184,7 @@ public class Chunk implements IChunkAccess { + + for (k = 0; k < this.sections.length; ++k) { + this.sections[k] = protochunk.getSections()[k]; ++ if (this.sections[k] != null) this.sections[k].disableLocks(); // Paper - Async Chunks - disable locks used during world gen + } + + Iterator iterator = protochunk.s().iterator(); diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java index 5b57ea93c8..5d5834ba7f 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -503,6 +515,28 @@ index c233b7e903..edd0742527 100644 completion = new Supplier() { public NBTTagCompound get() { +diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java +index bdfc7d81ff..a5c4564d60 100644 +--- a/src/main/java/net/minecraft/server/ChunkSection.java ++++ b/src/main/java/net/minecraft/server/ChunkSection.java +@@ -24,7 +24,17 @@ public class ChunkSection { + this.skyLight = new NibbleArray(); + } + ++ // Paper start - Async Chunks - Lock during world gen ++ if (chunk instanceof ProtoChunk) { ++ this.blockIds.enableLocks(); ++ } else { ++ this.blockIds.disableLocks(); ++ } ++ } ++ void disableLocks() { ++ this.blockIds.disableLocks(); + } ++ // Paper end + + public IBlockData getType(int i, int j, int k) { + return this.blockIds.a(i, j, k); diff --git a/src/main/java/net/minecraft/server/ChunkTaskScheduler.java b/src/main/java/net/minecraft/server/ChunkTaskScheduler.java index 34019bd1b3..4ca977645f 100644 --- a/src/main/java/net/minecraft/server/ChunkTaskScheduler.java @@ -526,7 +560,7 @@ index 34019bd1b3..4ca977645f 100644 ProtoChunk protochunk; diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main/java/net/minecraft/server/DataPaletteBlock.java -index 71a3636be6..b0170db9ca 100644 +index 71a3636be6..ff0fe25417 100644 --- a/src/main/java/net/minecraft/server/DataPaletteBlock.java +++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java @@ -3,7 +3,7 @@ package net.minecraft.server; @@ -538,15 +572,29 @@ index 71a3636be6..b0170db9ca 100644 import java.util.function.Function; import java.util.stream.Collectors; -@@ -20,25 +20,16 @@ public class DataPaletteBlock implements DataPaletteExpandable { +@@ -20,25 +20,42 @@ public class DataPaletteBlock implements DataPaletteExpandable { protected DataBits a; protected DataBits getDataBits() { return this.a; } // Paper - OBFHELPER private DataPalette h; private DataPalette getDataPalette() { return this.h; } // Paper - OBFHELPER private int i; private int getBitsPerObject() { return this.i; } // Paper - OBFHELPER - private final ReentrantLock j = new ReentrantLock(); -+ // Paper start - use read write locks -+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); ++ // Paper start - use read write locks only during generation, disable once back on main thread ++ private static final NoopLock NOOP_LOCK = new NoopLock(); ++ private java.util.concurrent.locks.Lock readLock = NOOP_LOCK; ++ private java.util.concurrent.locks.Lock writeLock = NOOP_LOCK; ++ ++ private static class NoopLock extends ReentrantReadWriteLock.WriteLock { ++ private NoopLock() { ++ super(new ReentrantReadWriteLock()); ++ } ++ ++ @Override ++ public final void lock() { ++ } ++ ++ @Override ++ public final void unlock() { - private void b() { +- private void b() { - if (this.j.isLocked() && !this.j.isHeldByCurrentThread()) { - String s = (String)Thread.getAllStackTraces().keySet().stream().filter(Objects::nonNull).map((thread) -> { - return thread.getName() + ": \n\tat " + (String)Arrays.stream(thread.getStackTrace()).map(Object::toString).collect(Collectors.joining("\n\tat ")); @@ -557,31 +605,42 @@ index 71a3636be6..b0170db9ca 100644 - throw new ReportedException(crashreport); - } else { - this.j.lock(); -- } -+ lock.writeLock().lock(); + } } -- + ++ synchronized void enableLocks() { ++ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); ++ readLock = lock.readLock(); ++ writeLock = lock.writeLock(); ++ } ++ synchronized void disableLocks() { ++ readLock = NOOP_LOCK; ++ writeLock = NOOP_LOCK; ++ } ++ private void b() { ++ writeLock.lock(); ++ } private void c() { - this.j.unlock(); -+ lock.writeLock().unlock(); ++ writeLock.unlock(); } + // Paper end public DataPaletteBlock(DataPalette datapalette, RegistryBlockID registryblockid, Function function, Function function1, T object) { // Paper start - Anti-Xray - Support default constructor -@@ -147,8 +138,13 @@ public class DataPaletteBlock implements DataPaletteExpandable { +@@ -147,8 +164,13 @@ public class DataPaletteBlock implements DataPaletteExpandable { } protected T a(int ix) { - T object = this.h.a(this.a.a(ix)); // Paper - decompile fix - return (T)(object == null ? this.g : object); -+ try { // Paper -+ lock.readLock().lock(); ++ try { // Paper start - read lock ++ readLock.lock(); + T object = this.h.a(this.a.a(ix)); // Paper - decompile fix + return (T)(object == null ? this.g : object); + } finally { -+ lock.readLock().unlock(); -+ } // Paper ++ readLock.unlock(); ++ } // Paper end } // Paper start - Anti-Xray - Support default methods diff --git a/Spigot-Server-Patches/0380-Optimize-Light-Recalculations.patch b/Spigot-Server-Patches/0380-Optimize-Light-Recalculations.patch index b2dd69b925..753fc3bcfb 100644 --- a/Spigot-Server-Patches/0380-Optimize-Light-Recalculations.patch +++ b/Spigot-Server-Patches/0380-Optimize-Light-Recalculations.patch @@ -1,4 +1,4 @@ -From f8d45609bd1247f999df8ac62ca914e8b18e0b28 Mon Sep 17 00:00:00 2001 +From 1b776a800b336105e8b519498c9ad387a58035b0 Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 28 Sep 2018 20:46:29 -0400 Subject: [PATCH] Optimize Light Recalculations @@ -14,10 +14,10 @@ Also optimizes to not repeatedly look up the same chunk for light lookups. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 9162151e2a..651bb23be9 100644 +index 15a327923f..0b2d9a05f4 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -347,7 +347,7 @@ public class Chunk implements IChunkAccess { +@@ -348,7 +348,7 @@ public class Chunk implements IChunkAccess { private void a(int i, int j, int k, int l) { if (l > k && this.areNeighborsLoaded(1)) { // Paper for (int i1 = k; i1 < l; ++i1) { @@ -26,7 +26,7 @@ index 9162151e2a..651bb23be9 100644 } this.x = true; -@@ -578,7 +578,7 @@ public class Chunk implements IChunkAccess { +@@ -579,7 +579,7 @@ public class Chunk implements IChunkAccess { } else { if (flag1) { this.initLighting(); diff --git a/Spigot-Server-Patches/0382-Don-t-recheck-type-after-setting-a-block.patch b/Spigot-Server-Patches/0382-Don-t-recheck-type-after-setting-a-block.patch index 9c15809a81..68b81e786c 100644 --- a/Spigot-Server-Patches/0382-Don-t-recheck-type-after-setting-a-block.patch +++ b/Spigot-Server-Patches/0382-Don-t-recheck-type-after-setting-a-block.patch @@ -1,4 +1,4 @@ -From 588da1da60dac3624336295f970c26987135e8f6 Mon Sep 17 00:00:00 2001 +From ab7e26676e388e98f45d9edb6bc48c3fc2d2de7d Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 28 Sep 2018 22:27:33 -0400 Subject: [PATCH] Don't recheck type after setting a block @@ -16,10 +16,10 @@ be having data corruption issues anyways. This provides a small boost to all setType calls. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index e4bda70bb9..895eb60854 100644 +index 0b2d9a05f4..8da88e1c3a 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -573,7 +573,7 @@ public class Chunk implements IChunkAccess { +@@ -574,7 +574,7 @@ public class Chunk implements IChunkAccess { this.world.n(blockposition); } diff --git a/Spigot-Server-Patches/0383-Fix-Sending-Chunks-to-Client.patch b/Spigot-Server-Patches/0383-Fix-Sending-Chunks-to-Client.patch index 4eb683e178..480d6efdd3 100644 --- a/Spigot-Server-Patches/0383-Fix-Sending-Chunks-to-Client.patch +++ b/Spigot-Server-Patches/0383-Fix-Sending-Chunks-to-Client.patch @@ -1,4 +1,4 @@ -From 5ae13b5d368068c630d57a8d6c4801b673b31ffa Mon Sep 17 00:00:00 2001 +From 0270355d40dd0fcd9b6d326f6d0084d07d689e49 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 29 Sep 2018 01:18:16 -0400 Subject: [PATCH] Fix Sending Chunks to Client @@ -14,10 +14,10 @@ This fix always sends chunks to the client, and simply updates the client anytime post processing is triggered with the new chunk data. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 83df52f30..0b0a5424e 100644 +index 8da88e1c3a..64cec6d692 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -1212,7 +1212,7 @@ public class Chunk implements IChunkAccess { +@@ -1213,7 +1213,7 @@ public class Chunk implements IChunkAccess { } public boolean isReady() { @@ -26,7 +26,7 @@ index 83df52f30..0b0a5424e 100644 } public boolean v() { -@@ -1478,6 +1478,13 @@ public class Chunk implements IChunkAccess { +@@ -1479,6 +1479,13 @@ public class Chunk implements IChunkAccess { this.h.clear(); this.a(ChunkStatus.POSTPROCESSED); this.m.a(this); @@ -41,7 +41,7 @@ index 83df52f30..0b0a5424e 100644 } diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index 04ad94e17..748d5f28e 100644 +index 04ad94e171..748d5f28e5 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -23,7 +23,7 @@ public class PlayerChunk {