0

I have script in Unity that is exchanging data with another Python app. It has a while loop that listens for UDP messages as a background thread. Also the script is asking for new data every frame via the Update function.

After I receive a message, the script parses it as a string and it needs to split the string by tabs in order to retrieve all the values. Currently, the string contains eyetracker and joystick data that Unity needs as player inputs.

UDPController.cs

private void init()
{

    // define address to send data to
    pythonEndPoint = new IPEndPoint(IPAddress.Parse(IP), pythonPort);
    unityEndPoint = new IPEndPoint (IPAddress.Parse (IP), unityPort);
    pythonSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);


    //define client to receive data at
    client = new UdpClient(unityPort);
    client.Client.ReceiveTimeout = 1;
    client.Client.SendTimeout = 1;

    // start background thread to receive information
    receiveThread = new Thread(new ThreadStart(ReceiveData));
    receiveThread.IsBackground = true;
    receiveThread.Start();

}

void Update(){
    if (Calibration.calibrationFinished && startRequestNewFrame) {
        RequestData();
    }
}
private void RequestData() {
    // Sends this to the UDP server written in Python
    SendString("NEWFRAME");
}

// receive thread which listens for messages from Python UDP Server
private void ReceiveData()
{

    while (true)
    {

        try
        {

            if(client.Available > 0) {

                double unixRecvTimeStamp = DataManager.ConvertToUnixTimestamp(DateTime.Now);
                byte[] data = client.Receive(ref pythonEndPoint);

                string rawtext = Encoding.UTF8.GetString(data);

                string[] msgs = rawtext.Split('\t');

                string msgType = msgs[0];
                double pythonSentTimeStamp = double.Parse(msgs[msgs.Length-1].Split(' ')[1]);

                DataManager.UdpRecvBuffer += '"' + rawtext + '"' + "\t" + pythonSentTimeStamp + "\t" + unixRecvTimeStamp + "\t" + DataManager.ConvertToUnixTimestamp(DateTime.Now) + "\n";

                if (String.Equals(msgType, "FRAMEDATA"))
                {

                    DataManager.gazeAdcsPos = new Vector2(float.Parse(msgs[1].Split(' ')[1]), float.Parse(msgs[2].Split(' ')[1]));
                    float GazeTimeStamp = float.Parse(msgs[3].Split(' ')[1]);
                    DataManager.rawJoy = new Vector2(float.Parse(msgs[4].Split(' ')[1]), 255 - float.Parse(msgs[5].Split(' ')[1]));
                    float joyC = float.Parse(msgs[6].Split(' ')[1]);
                    float ArduinoTimeStamp = float.Parse(msgs[7].Split(' ')[1]);
                }

            }

        }
        catch (Exception err)
        {
            print(err.ToString());
        }
    }
}

So according to the Unity Profiler, it seems like there is a huge amount of time spent in Behaviour Update, especially inside UDPController.Update() and GC.Collect. My initial hypothesis is that perhaps I'm creating too many strings and arrays overtime and the garbage collector kicks in quite often to remove the unused memory space.

Unity Profiler - Showing high CPU Usage and Time in Behaviour Update

So my question is, is my hypothesis right? If so, how I can rewrite this code to increase my performance and reduce the drop in FPS and perceived lag. If not, where is the issue at because currently the game starts to lag right about 10 minutes in.

Moreover, is there a better way or format for data transferring? It seems like I can be using objects like JSON, Google Protocol Buffer or msgpack or would that be an overkill?

Steven Chen
  • 397
  • 1
  • 6
  • 19
  • What if you would skip some update? Do you need it every frame or twice per second could be enough? – Everts Aug 19 '16 at 05:44
  • @Everts Yeah I need it for every frame. Essentially the data contains the eye coordinates and joystick positions for opening doors and moving the player around. – Steven Chen Aug 19 '16 at 05:46

1 Answers1

0
  1. I can see a lot of local variables in your while loop (along with arrays). Local variables cause Garbage collector to run. You should declare all the variables outside of the method.

  2. Moreover, avoid string operations in while/update() as strings are immutable. Thus your code create a new copy to store the result after every concatenation. Use StringBuilder in these situations to avoid GC.

Read More

Community
  • 1
  • 1
Umair M
  • 10,298
  • 6
  • 42
  • 74