Skip to content

Commit 8764652

Browse files
author
vis2k
committed
fix: perf: uncork max message size from 144 KB to as much as we want based on receive window size.
#22 skywind3000/kcp#291
1 parent 957d13c commit 8764652

File tree

3 files changed

+27
-19
lines changed

3 files changed

+27
-19
lines changed

kcp2k/Assets/Tests/Editor/ClientServerTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public void ClientToServerReliableMaxSizedMessage()
299299
server.Start(Port);
300300
ConnectClientBlocking();
301301

302-
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize];
302+
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize)];
303303
for (int i = 0; i < message.Length; ++i)
304304
message[i] = (byte)(i & 0xFF);
305305
Log.Info($"Sending {message.Length} bytes = {message.Length / 1024} KB message");
@@ -356,10 +356,10 @@ public void ClientToServerTooLargeReliableMessage()
356356
server.Start(Port);
357357
ConnectClientBlocking();
358358

359-
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize + 1];
359+
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize) + 1];
360360

361361
#if UNITY_2018_3_OR_NEWER
362-
UnityEngine.TestTools.LogAssert.Expect(UnityEngine.LogType.Error, $"Failed to send reliable message of size {message.Length} because it's larger than ReliableMaxMessageSize={KcpConnection.ReliableMaxMessageSize}");
362+
UnityEngine.TestTools.LogAssert.Expect(UnityEngine.LogType.Error, $"Failed to send reliable message of size {message.Length} because it's larger than ReliableMaxMessageSize={KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize)}");
363363
#endif
364364
SendClientToServerBlocking(new ArraySegment<byte>(message), KcpChannel.Reliable);
365365
Assert.That(serverReceived.Count, Is.EqualTo(0));
@@ -437,7 +437,7 @@ public void ClientToServerMultipleReliableMaxSizedMessagesAtOnce()
437437
for (int i = 0; i < 10; ++i)
438438
{
439439
// create message, fill with unique data (j+i & 0xff)
440-
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize];
440+
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize)];
441441
for (int j = 0; j < message.Length; ++j)
442442
message[j] = (byte)((j + i) & 0xFF);
443443
messages.Add(message);
@@ -555,7 +555,7 @@ public void ServerToClientReliableMaxSizedMessage()
555555
ConnectClientBlocking();
556556
int connectionId = ServerFirstConnectionId();
557557

558-
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize];
558+
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize)];
559559
for (int i = 0; i < message.Length; ++i)
560560
message[i] = (byte)(i & 0xFF);
561561

@@ -615,9 +615,9 @@ public void ServerToClientTooLargeReliableMessage()
615615
ConnectClientBlocking();
616616
int connectionId = ServerFirstConnectionId();
617617

618-
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize + 1];
618+
byte[] message = new byte[KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize) + 1];
619619
#if UNITY_2018_3_OR_NEWER
620-
UnityEngine.TestTools.LogAssert.Expect(UnityEngine.LogType.Error, $"Failed to send reliable message of size {message.Length} because it's larger than ReliableMaxMessageSize={KcpConnection.ReliableMaxMessageSize}");
620+
UnityEngine.TestTools.LogAssert.Expect(UnityEngine.LogType.Error, $"Failed to send reliable message of size {message.Length} because it's larger than ReliableMaxMessageSize={KcpConnection.ReliableMaxMessageSize(ReceiveWindowSize)}");
621621
#endif
622622
SendServerToClientBlocking(connectionId, new ArraySegment<byte>(message), KcpChannel.Reliable);
623623
Assert.That(clientReceived.Count, Is.EqualTo(0));

kcp2k/Assets/kcp2k/highlevel/KcpConnection.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,35 +49,36 @@ public abstract class KcpConnection
4949
// kcp does fragmentation, so max message is way larger than MTU.
5050
//
5151
// -> runtime MTU changes are disabled: mss is always MTU_DEF-OVERHEAD
52-
// -> Send() checks if fragment count < WND_RCV, so we use WND_RCV - 1.
53-
// note that Send() checks WND_RCV instead of wnd_rcv which may or
54-
// may not be a bug in original kcp. but since it uses the define, we
55-
// can use that here too.
52+
// -> Send() checks if fragment count < rcv_wnd, so we use rcv_wnd - 1.
53+
// NOTE that original kcp has a bug where WND_RCV default is used
54+
// instead of configured rcv_wnd, limiting max message size to 144 KB
55+
// https://github.com/skywind3000/kcp/pull/291
56+
// we fixed this in kcp2k.
5657
// -> we add 1 byte KcpHeader enum to each message, so -1
5758
//
58-
// IMPORTANT: max message is MTU * WND_RCV, in other words it completely
59+
// IMPORTANT: max message is MTU * rcv_wnd, in other words it completely
5960
// fills the receive window! due to head of line blocking,
6061
// all other messages have to wait while a maxed size message
6162
// is being delivered.
6263
// => in other words, DO NOT use max size all the time like
6364
// for batching.
6465
// => sending UNRELIABLE max message size most of the time is
6566
// best for performance (use that one for batching!)
66-
public const int ReliableMaxMessageSize = (Kcp.MTU_DEF - Kcp.OVERHEAD - CHANNEL_HEADER_SIZE) * (Kcp.WND_RCV - 1) - 1;
67+
public static int ReliableMaxMessageSize(uint rcv_wnd) => (Kcp.MTU_DEF - Kcp.OVERHEAD - CHANNEL_HEADER_SIZE) * ((int)rcv_wnd - 1) - 1;
6768

6869
// unreliable max message size is simply MTU - channel header size
6970
public const int UnreliableMaxMessageSize = Kcp.MTU_DEF - CHANNEL_HEADER_SIZE;
7071

7172
// buffer to receive kcp's processed messages (avoids allocations).
7273
// IMPORTANT: this is for KCP messages. so it needs to be of size:
7374
// 1 byte header + MaxMessageSize content
74-
byte[] kcpMessageBuffer = new byte[1 + ReliableMaxMessageSize];
75+
byte[] kcpMessageBuffer;// = new byte[1 + ReliableMaxMessageSize];
7576

7677
// send buffer for handing user messages to kcp for processing.
7778
// (avoids allocations).
7879
// IMPORTANT: needs to be of size:
7980
// 1 byte header + MaxMessageSize content
80-
byte[] kcpSendBuffer = new byte[1 + ReliableMaxMessageSize];
81+
byte[] kcpSendBuffer;// = new byte[1 + ReliableMaxMessageSize];
8182

8283
// raw send buffer is exactly MTU.
8384
byte[] rawSendBuffer = new byte[Kcp.MTU_DEF];
@@ -143,6 +144,11 @@ protected void SetupKcp(bool noDelay, uint interval = Kcp.INTERVAL, int fastRese
143144
// message afterwards.
144145
kcp.SetMtu(Kcp.MTU_DEF - CHANNEL_HEADER_SIZE);
145146

147+
// create message buffers AFTER window size is set
148+
// see comments on buffer definition for the "+1" part
149+
kcpMessageBuffer = new byte[1 + ReliableMaxMessageSize(receiveWindowSize)];
150+
kcpSendBuffer = new byte[1 + ReliableMaxMessageSize(receiveWindowSize)];
151+
146152
this.timeout = timeout;
147153
state = KcpState.Connected;
148154

@@ -551,7 +557,7 @@ void SendReliable(KcpHeader header, ArraySegment<byte> content)
551557
}
552558
}
553559
// otherwise content is larger than MaxMessageSize. let user know!
554-
else Log.Error($"Failed to send reliable message of size {content.Count} because it's larger than ReliableMaxMessageSize={ReliableMaxMessageSize}");
560+
else Log.Error($"Failed to send reliable message of size {content.Count} because it's larger than ReliableMaxMessageSize={ReliableMaxMessageSize(kcp.rcv_wnd)}");
555561
}
556562

557563
void SendUnreliable(ArraySegment<byte> message)

kcp2k/Assets/kcp2k/kcp/Kcp.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,11 @@ public int Send(byte[] buffer, int offset, int len)
264264

265265
// original kcp uses WND_RCV const instead of rcv_wnd runtime:
266266
// https://github.com/skywind3000/kcp/pull/291/files
267-
// which always limits max message size to 144 KB.
268-
// this might be a bug.
269-
if (count >= WND_RCV) return -2;
267+
// which always limits max message size to 144 KB:
268+
//if (count >= WND_RCV) return -2;
269+
// using configured rcv_wnd uncorks max message size to 'any':
270+
UnityEngine.Debug.Log($"Send len=" + buffer.Length + " frag count=" + count + " WND_RCV=" + WND_RCV + " rcv_wnd=" + rcv_wnd);
271+
if (count >= rcv_wnd) return -2;
270272

271273
if (count == 0) count = 1;
272274

0 commit comments

Comments
 (0)