From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Tue, 22 Sep 2020 01:49:19 -0700 Subject: [PATCH] Optimise non-flush packet sending Places like entity tracking make heavy use of packet sending, and internally netty will use some very expensive thread wakeup calls when scheduling. Thanks to various hacks in ProtocolLib as well as other plugins, we cannot simply use a queue of packets to group send on execute. We have to call execute for each packet. Tux's suggestion here is exactly what was needed - tag the Runnable indicating it should not make a wakeup call. Big thanks to Tux for making this possible as I had given up on this optimisation before he came along. Locally this patch drops the entity tracker tick by a full 1.5x. diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java index 80cc3b62af324512f695e971cce2b01f6eadbdbf..549c82b2bd91db70bc83b4e33131774a0d2d17ac 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -46,6 +46,8 @@ import org.slf4j.Logger; import org.slf4j.Marker; import org.slf4j.MarkerFactory; + +import io.netty.util.concurrent.AbstractEventExecutor; // Paper public class Connection extends SimpleChannelInboundHandler> { private static final float AVERAGE_PACKETS_SMOOTHING = 0.75F; @@ -396,9 +398,19 @@ public class Connection extends SimpleChannelInboundHandler> { if (this.channel.eventLoop().inEventLoop()) { this.doSendPacket(packet, packetsendlistener, enumprotocol, enumprotocol1, flush); // Paper - add flush parameter } else { + // Paper start - optimise packets that are not flushed + // note: since the type is not dynamic here, we need to actually copy the old executor code + // into two branches. On conflict, just re-copy - no changes were made inside the executor code. + if (!flush) { + AbstractEventExecutor.LazyRunnable run = () -> { + this.doSendPacket(packet, packetsendlistener, enumprotocol, enumprotocol1, flush); // Paper - add flush parameter + }; + this.channel.eventLoop().execute(run); + } else { // Paper end - optimise packets that are not flushed this.channel.eventLoop().execute(() -> { - this.doSendPacket(packet, packetsendlistener, enumprotocol, enumprotocol1, flush); // Paper - add flush parameter + this.doSendPacket(packet, packetsendlistener, enumprotocol, enumprotocol1, flush); // Paper - add flush parameter // Paper - diff on change }); + } // Paper } }