Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTcpSocket write() causing GUI stuttering/delay
Qt 6.11 is out! See what's new in the release blog

QTcpSocket write() causing GUI stuttering/delay

Scheduled Pinned Locked Moved Solved General and Desktop
4 Posts 2 Posters 488 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    jars121
    wrote on last edited by
    #1

    Hi all,

    I have one application which receives TCP data, performs some processing, then sends it to another application via TCP. This end-to-end process works, but I'm experiencing some strange issues when transmitting the processed TCP data to the external application.

    When transmission to the remote application is disabled (i.e. commented out as shown below), the GUI operates as expected. However, when the TCP transmission is enabled, the GUI exhibits severe stuttering/delay. It's important to note that the classes involved in the processing and transmission of the data via TCP are in separate threads to the GUI/main thread, so I'm not sure why this stuttering is occuring.

    The below is an excerpt from the processing class:

    //The processed data is packaged into a QJsonObject for transmission
    m_jsonData["SomeValue"] = "Some text string";
    
    //I create a QByteArray and QDataStream for reading and transmitting the size of the packet
    QByteArray packetSize;
    QDataStream dataStreamPacketSize(&packetSize, QIODevice::ReadWrite);
    
    //Set the QDataStream version
    dataStreamPacketSize.setVersion(QDataStream::Qt_5_14);
    
    //Instantiate a QJsonDocument for converting the QJsonObject into a binary data QByteArray
    QJsonDocument jsonDocument(m_jsonData);
    QByteArray byteArrayPacket = jsonDocument.toBinaryData();
    
    //Read the size of the packet into the packetSize QByteArray
    dataStreamPacketSize << byteArrayPacket.size();
    
    //Transmit the packet size header via the tcpConnection class
    tcpConnectionInstance->tcpClient->write(packetSize);
    
    //Transmit the packet
    tcpConnectionInstance->tcpClient->write(byteArrayPacket);
    
    //Flush the socket interface
    tcpConnectionInstance->tcpClient->flush();
    

    In the above code, the tcpConnection class is instantiated within the processing class, and moved into its thread (this has been verified by checking each class' QThread::currentThreadId()). The processing class defines tcpConnectionInstance as a tcpConnection pointer in its header file.

    void processingClass::initialiseClass()
    {
        tcpConnectionInstance = new tcpConnection();
        tcpConnectionInstance->moveToThread(this->thread());
    
        //Set up signals/slots etc.
    }
    

    As mentioned above, if I disable the TCP component of the above code, the application runs flawlessly. I.e.:

    //Transmit the packet size header via the tcpConnection class
    //tcpConnectionInstance->tcpClient->write(packetSize);
    
    //Transmit the packet
    //tcpConnectionInstance->tcpClient->write(byteArrayPacket);
    
    //Flush the socket interface
    //tcpConnectionInstance->tcpClient->flush();
    

    This suggests that the packaging of the data into the QJsonObject and converting it into a binary data QByteArray is not an issue.

    In terms of data rate, the QJsonObject contains 216 key/value pairs, which results in a byteArrayPacket size of around 8,600 bytes. The rate at which these packets are processing and transmitted is locked to 50Hz.

    I will note that if I instead use a dummy QJsonObject as the source of the transmission, with only a handful (<10) of key/value pairs, the GUI remains responsive. This suggests that it's the size of the data being sent that is the issue, but I still don't understand how that would cause stuttering/performance degradation in the main thread, when the processing and TCP transmission is decoupled from the GUI/main thread?

    Any input would be greatly appreciated!

    J.HilkJ 1 Reply Last reply
    0
    • J Offline
      J Offline
      jars121
      wrote on last edited by
      #2

      I think I've found the underlying issue. As somewhat expected, the GUI stuttering isn't directly related to the above code, but the issue is being caused by TCP traffic (from what I can tell).

      The processingClass class receives data from an external application via TCP (via another class on a separate thread). As shown above, the processed data is then transmitted via TCP. I've just done some profiling, where I've measured the elapsed time between incoming TCP packets. I.e. how long it takes (in milliseconds) for each TCP packet to be emitted (via signal/slot) from the receiving class to the processingClass class.

      I've plotted the results below:

      0ab5f050-2091-46d2-a077-697644102a99-image.png

      During the profiling, I toggled the TCP transmissions on/off (i.e. the processed data TCP transmission as shown above). As previously stated, the incoming TCP data frequency is locked at 50Hz, which can be seen in the (relatively) stable areas, where the elapsed time is hovering at around 20ms as expected. As soon as I turn on the outbound TCP transmission, the incoming TCP frequency goes haywire. As soon as I turn the outbound TCP transmission offer, the inbound TCP frequency is again relatively stable at 20ms.

      These spikes in inbound TCP data reception are definitely the cause of the observed GUI stuttering, as the GUI is only updated once the various functions in the processingClass class have finished.

      In the process of writing the above, I've just done some further testing and have actually resolved this issue! The device in question was connected to the network and internet via WiFi, and it looks like the 2.4GHz channel it was connected to had really poor bandwidth, so it looks like it was taking excessive time for the inbound and outbound packets to be received and sent. I've just switched to the 5GHz channel and the issue goes away completely.

      1 Reply Last reply
      2
      • J jars121

        Hi all,

        I have one application which receives TCP data, performs some processing, then sends it to another application via TCP. This end-to-end process works, but I'm experiencing some strange issues when transmitting the processed TCP data to the external application.

        When transmission to the remote application is disabled (i.e. commented out as shown below), the GUI operates as expected. However, when the TCP transmission is enabled, the GUI exhibits severe stuttering/delay. It's important to note that the classes involved in the processing and transmission of the data via TCP are in separate threads to the GUI/main thread, so I'm not sure why this stuttering is occuring.

        The below is an excerpt from the processing class:

        //The processed data is packaged into a QJsonObject for transmission
        m_jsonData["SomeValue"] = "Some text string";
        
        //I create a QByteArray and QDataStream for reading and transmitting the size of the packet
        QByteArray packetSize;
        QDataStream dataStreamPacketSize(&packetSize, QIODevice::ReadWrite);
        
        //Set the QDataStream version
        dataStreamPacketSize.setVersion(QDataStream::Qt_5_14);
        
        //Instantiate a QJsonDocument for converting the QJsonObject into a binary data QByteArray
        QJsonDocument jsonDocument(m_jsonData);
        QByteArray byteArrayPacket = jsonDocument.toBinaryData();
        
        //Read the size of the packet into the packetSize QByteArray
        dataStreamPacketSize << byteArrayPacket.size();
        
        //Transmit the packet size header via the tcpConnection class
        tcpConnectionInstance->tcpClient->write(packetSize);
        
        //Transmit the packet
        tcpConnectionInstance->tcpClient->write(byteArrayPacket);
        
        //Flush the socket interface
        tcpConnectionInstance->tcpClient->flush();
        

        In the above code, the tcpConnection class is instantiated within the processing class, and moved into its thread (this has been verified by checking each class' QThread::currentThreadId()). The processing class defines tcpConnectionInstance as a tcpConnection pointer in its header file.

        void processingClass::initialiseClass()
        {
            tcpConnectionInstance = new tcpConnection();
            tcpConnectionInstance->moveToThread(this->thread());
        
            //Set up signals/slots etc.
        }
        

        As mentioned above, if I disable the TCP component of the above code, the application runs flawlessly. I.e.:

        //Transmit the packet size header via the tcpConnection class
        //tcpConnectionInstance->tcpClient->write(packetSize);
        
        //Transmit the packet
        //tcpConnectionInstance->tcpClient->write(byteArrayPacket);
        
        //Flush the socket interface
        //tcpConnectionInstance->tcpClient->flush();
        

        This suggests that the packaging of the data into the QJsonObject and converting it into a binary data QByteArray is not an issue.

        In terms of data rate, the QJsonObject contains 216 key/value pairs, which results in a byteArrayPacket size of around 8,600 bytes. The rate at which these packets are processing and transmitted is locked to 50Hz.

        I will note that if I instead use a dummy QJsonObject as the source of the transmission, with only a handful (<10) of key/value pairs, the GUI remains responsive. This suggests that it's the size of the data being sent that is the issue, but I still don't understand how that would cause stuttering/performance degradation in the main thread, when the processing and TCP transmission is decoupled from the GUI/main thread?

        Any input would be greatly appreciated!

        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #3

        @jars121

        just as an FYI, this:

        void processingClass::initialiseClass()
        {
        tcpConnectionInstance = new tcpConnection();
        tcpConnectionInstance->moveToThread(this->thread());

        //Set up signals/slots etc.
        

        }

        doesn't do any parallelisation.
        You're moving the tcpConnection to the thread it was already living in, (presumably) the main gui thread.


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply
        2
        • J Offline
          J Offline
          jars121
          wrote on last edited by
          #4

          Thanks for that @J-Hilk much appreciated.

          You're right; I must have misremembered how I actually had that piece of code setup. The processingClass class is instantiated in the GUI thread, but is moved to its own thread before the initialiseClass() function is called. As such, when the tcpConnection class is instantiated, it's already living within processingClass' thread.

          I thought I had solved this issue, but I'm still experiencing significant jitter (if you can even call it that) in the inbound TCP packets, which is causing havoc for the GUI and output packet transmission:

          7241f5ac-e9bb-44d5-8ee1-19d7194b5179-image.png

          I don't currently have the means to run iperf3 or similar on the device to check what the actual WiFi signal bandwidth is, so it may just be a really poor connection?!

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved