Search Unity

Low Level API / NetworkTransport.Receive fabulously slow, is this by design?

Discussion in 'Multiplayer' started by doctorpangloss, Jun 28, 2016.

  1. doctorpangloss

    doctorpangloss

    Joined:
    Feb 20, 2013
    Posts:
    270
    I'm trying to power-use the low level API for a clean lockstep networking implementation. The LLAPI methods execute much worse than 60 frames per second, despite Send and Receive calls happening as fast as possible (in an Update with Application.targetFramerate = -1).

    I know ordinarily the framework / user code is to blame, but I carefully wrote tests with fully mocked NetworkTransport, and I'm passing all the tests far faster than real time—I don't think my code is to blame here. I've also written a framework based on websocket-sharp that vastly outperforms the LLAPI—typically around 40 netcalls per second instead of the 10 successful sends/receives per second I'm observing with LLAPI.

    Is this level of performance expected?

    I'm on 5.3.5f1 on Mac OS X.

    Sample project with tests:

    https://github.com/hiddenswitch/PushyBall

    Build server with SERVER defined, build client with no defines. Run Server then Client.

    High level framework with tests:

    https://github.com/hiddenswitch/Adaptive

    How am I calling NetworkTransport.Send and NetworkTransport.Receive?

    The call at https://github.com/hiddenswitch/Adaptive/blob/master/TimeClockHelper.cs#L48 kicks off a .Send in its callstack. The Update at https://github.com/hiddenswitch/Adaptive/blob/master/NetworkTransportReceiveHelper.cs#L35 calls Receive.
     
    Last edited: Jun 28, 2016
  2. doctorpangloss

    doctorpangloss

    Joined:
    Feb 20, 2013
    Posts:
    270
    Although this isn't in the documentation, it became clear that NetworkTransport.Receive pulls one item at a time off a queue. I would suggest the following pattern, which improved the performance significantly:
    Code (CSharp):
    1. void Update ()
    2.         {
    3.             int recHostId;
    4.             int connectionId;
    5.             int channelId;
    6.             int dataSize;
    7.             byte error;
    8.             NetworkEventType recData = NetworkEventType.Nothing;
    9.             do {
    10.                 recData = NetworkTransport.Receive (out recHostId, out connectionId, out channelId, workingBuffer, workingBuffer.Length, out dataSize, out error);
    11.                 if (recData == NetworkEventType.Nothing) {
    12.                     break;
    13.                 }
    14.                 // Don't create buffers
    15.                 byte[] recBuffer = new byte[dataSize];
    16.  
    17.                 if (dataSize > 0) {
    18.                     Buffer.BlockCopy (workingBuffer, 0, recBuffer, 0, dataSize);
    19.                 }
    20.  
    21.                 transportDelegate.Receive (recHostId, connectionId, channelId, recBuffer, dataSize, dataSize, error, recData);
    22.             } while (recData != NetworkEventType.Nothing);
    23.         }