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. QtConcurrent run with a never ending while loop leads to high CPU usage

QtConcurrent run with a never ending while loop leads to high CPU usage

Scheduled Pinned Locked Moved Unsolved General and Desktop
qtconcurrentqueuedconnectiogui signals
17 Posts 7 Posters 2.2k 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.
  • M Offline
    M Offline
    MarKS
    wrote on 19 Mar 2021, 13:54 last edited by MarKS
    #1

    Building on this issue of updating GUI from another thread has led to high CPU usage issue.

    To re-iterate, I have a .mp4 file with 12000 frames. I loop through each frame and update the GUI. It looks something like this:

    DataBuffer Controller::read()
    {
         cv::Mat frameBgr;
         m_videoCapture.read(frameBgr);
        
         cv::Mat frameRgb;
         cv::cvtColor(frameBgr, frameRgb, cv::COLOR_BGR2RGB);
    
         m_dataBuffer.width = frameRgb.cols;
         m_dataBuffer.height = frameRgb.rows;
         m_dataBuffer.size = frameRgb.cols * frameRgb.rows;
         m_dataBuffer.data.assign(reinterpret_cast<const uchar*>(frameRgb.datastart),
                                     reinterpret_cast<const uchar*>(frameRgb.dataend));
            
         return m_dataBuffer;        
    }
    
    void Controller::play()
    {
        while(m_isPlaying)
        {
             // get frames from file
             // update GUI with frame
             emit showFrameOnWidget(read());        // QueuedConnection to renderFrame() slot
             
             // update timestamp label
             emit updateTimestamp(m_timestamp);  // QueuedConnection to updateTimestamp() slot
        } 
    }
    
    void MainController::renderFrame(Databuffer frame)
    {
           // process frame and extract all channels
          // lots of computation
    
           // emit render signals to be displayed on QLabel
           emit renderRGB(channel);
           emit renderConfidence(channel);
           emit renderDepth(channel);      
    }
    

    The function play() runs in a different thread created using QtConcurrent::run. When I start playing, my CPU usage hovers around ~70%.

    I have tried using QThread::msleep(sleepTime) inside the loop, but I do not feel this is the right approach. CPU usage with sleep time comes down to ~40%. I ran the same file on VLC mediaplayer (another Qt product) and the CPU consumption was almost 0%. How do they achieve this?

    Is using QtConcurrent::run()in this case wrong? Any other approach to deal with this?

    J 1 Reply Last reply 19 Mar 2021, 14:02
    0
    • M MarKS
      19 Mar 2021, 13:54

      Building on this issue of updating GUI from another thread has led to high CPU usage issue.

      To re-iterate, I have a .mp4 file with 12000 frames. I loop through each frame and update the GUI. It looks something like this:

      DataBuffer Controller::read()
      {
           cv::Mat frameBgr;
           m_videoCapture.read(frameBgr);
          
           cv::Mat frameRgb;
           cv::cvtColor(frameBgr, frameRgb, cv::COLOR_BGR2RGB);
      
           m_dataBuffer.width = frameRgb.cols;
           m_dataBuffer.height = frameRgb.rows;
           m_dataBuffer.size = frameRgb.cols * frameRgb.rows;
           m_dataBuffer.data.assign(reinterpret_cast<const uchar*>(frameRgb.datastart),
                                       reinterpret_cast<const uchar*>(frameRgb.dataend));
              
           return m_dataBuffer;        
      }
      
      void Controller::play()
      {
          while(m_isPlaying)
          {
               // get frames from file
               // update GUI with frame
               emit showFrameOnWidget(read());        // QueuedConnection to renderFrame() slot
               
               // update timestamp label
               emit updateTimestamp(m_timestamp);  // QueuedConnection to updateTimestamp() slot
          } 
      }
      
      void MainController::renderFrame(Databuffer frame)
      {
             // process frame and extract all channels
            // lots of computation
      
             // emit render signals to be displayed on QLabel
             emit renderRGB(channel);
             emit renderConfidence(channel);
             emit renderDepth(channel);      
      }
      

      The function play() runs in a different thread created using QtConcurrent::run. When I start playing, my CPU usage hovers around ~70%.

      I have tried using QThread::msleep(sleepTime) inside the loop, but I do not feel this is the right approach. CPU usage with sleep time comes down to ~40%. I ran the same file on VLC mediaplayer (another Qt product) and the CPU consumption was almost 0%. How do they achieve this?

      Is using QtConcurrent::run()in this case wrong? Any other approach to deal with this?

      J Offline
      J Offline
      jsulm
      Lifetime Qt Champion
      wrote on 19 Mar 2021, 14:02 last edited by
      #2

      @MarKS You will need to show more code to get meaningful answer, especially readFramesFromFile(). Also, you emit showFrameOnWidget on each iteration in the loop - I guess even if there is no new frame yet?

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      M 1 Reply Last reply 19 Mar 2021, 16:08
      0
      • J jsulm
        19 Mar 2021, 14:02

        @MarKS You will need to show more code to get meaningful answer, especially readFramesFromFile(). Also, you emit showFrameOnWidget on each iteration in the loop - I guess even if there is no new frame yet?

        M Offline
        M Offline
        MarKS
        wrote on 19 Mar 2021, 16:08 last edited by MarKS
        #3

        @jsulm I have updated the question to reflect more of the actual code I have.

        1 Reply Last reply
        0
        • J Offline
          J Offline
          jeremy_k
          wrote on 19 Mar 2021, 18:28 last edited by
          #4

          What's the size of the data being emitted by the showFrameOnWidget signal? This is going to be copied to the event queue for the receiving thread.

          Rather than emitting the frame itself, presuming it isn't a trivial size, I would put it into a shared buffer and then emit something representing an index or pointer into the buffer. QSharedData and the associated pointer classes are an option. A ring buffer that avoids dynamic memory in the critical path is another.

          If introducing some latency is acceptable, batching several frames per signal emission could also help smooth the interface.

          Asking a question about code? http://eel.is/iso-c++/testcase/

          M 1 Reply Last reply 19 Mar 2021, 20:56
          0
          • J jeremy_k
            19 Mar 2021, 18:28

            What's the size of the data being emitted by the showFrameOnWidget signal? This is going to be copied to the event queue for the receiving thread.

            Rather than emitting the frame itself, presuming it isn't a trivial size, I would put it into a shared buffer and then emit something representing an index or pointer into the buffer. QSharedData and the associated pointer classes are an option. A ring buffer that avoids dynamic memory in the critical path is another.

            If introducing some latency is acceptable, batching several frames per signal emission could also help smooth the interface.

            M Offline
            M Offline
            MarKS
            wrote on 19 Mar 2021, 20:56 last edited by
            #5

            @jeremy_k as you suggested I moved on to using a pointer to the buffer instead of the whole buffer. It is of course a better alternative to my existing code. But didn't improve the high CPU usage issue.

            When I introduce QThread::msleep(33) for a 30 fps video, the CPU usage hovers around ~30-40%. As far as I understood, that means the receiver thread/slot (GUI) is overwhelmed by the worker thread so much so that the GUI thread is not able to keep up with the worker thread.

            I still believe thread sleep is a bad design. But how do developers in Qt world go around this issue?

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on 19 Mar 2021, 21:35 last edited by
              #6

              Hi,

              @MarKS said in QtConcurrent run with a never ending while loop leads to high CPU usage:

              void MainController::renderFrame(Databuffer frame)
              {
              // process frame and extract all channels
              // lots of computation

                 // emit render signals to be displayed on QLabel
                 emit renderRGB(channel);
                 emit renderConfidence(channel);
                 emit renderDepth(channel);      
              

              }

              Why are you emitting three different signals with the exact same data ?
              From the looks of it, you should rather have three slots connected to one single signal.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              M 1 Reply Last reply 19 Mar 2021, 22:52
              0
              • SGaistS SGaist
                19 Mar 2021, 21:35

                Hi,

                @MarKS said in QtConcurrent run with a never ending while loop leads to high CPU usage:

                void MainController::renderFrame(Databuffer frame)
                {
                // process frame and extract all channels
                // lots of computation

                   // emit render signals to be displayed on QLabel
                   emit renderRGB(channel);
                   emit renderConfidence(channel);
                   emit renderDepth(channel);      
                

                }

                Why are you emitting three different signals with the exact same data ?
                From the looks of it, you should rather have three slots connected to one single signal.

                M Offline
                M Offline
                MarKS
                wrote on 19 Mar 2021, 22:52 last edited by MarKS
                #7

                @SGaist my bad. It was just an example to show that i emit render signals. Of course i am using the right channels to render images. And yes each signal has its own slot.

                Christian EhrlicherC 1 Reply Last reply 20 Mar 2021, 09:38
                0
                • nageshN Offline
                  nageshN Offline
                  nagesh
                  wrote on 19 Mar 2021, 23:08 last edited by
                  #8
                  void Controller::play()
                  {
                      while(m_isPlaying)
                      {
                           // get frames from file
                           // update GUI with frame
                           emit showFrameOnWidget(read());                 
                           // update timestamp label
                           emit updateTimestamp(m_timestamp);
                      } 
                  }
                  

                  As play() function is part of while loop without sleep how do you ensure fps?
                  At present it looks like as soon as data read from file is ready signal is emitted, which is causing high cpu usage.
                  Do a comparison of how much time Same file taking to play in VLC and your application?

                  J M 2 Replies Last reply 20 Mar 2021, 06:10
                  0
                  • nageshN nagesh
                    19 Mar 2021, 23:08
                    void Controller::play()
                    {
                        while(m_isPlaying)
                        {
                             // get frames from file
                             // update GUI with frame
                             emit showFrameOnWidget(read());                 
                             // update timestamp label
                             emit updateTimestamp(m_timestamp);
                        } 
                    }
                    

                    As play() function is part of while loop without sleep how do you ensure fps?
                    At present it looks like as soon as data read from file is ready signal is emitted, which is causing high cpu usage.
                    Do a comparison of how much time Same file taking to play in VLC and your application?

                    J Offline
                    J Offline
                    jeremy_k
                    wrote on 20 Mar 2021, 06:10 last edited by jeremy_k
                    #9

                    @nagesh said in QtConcurrent run with a never ending while loop leads to high CPU usage:

                    As play() function is part of while loop without sleep how do you ensure fps?

                    I missed that the source is a file and not a camera producing frames at a fixed rate.

                    !

                    A timer or blocking IO of some sort is going to be necessary if the goal isn't to be gated by the io, cpu, or memory capacity of the system. Sleeping a fixed interval is a problematic solution because it fails to take into account variability in available capacity. Either set a high precision timer for the desired frame rate, or cause the processing thread to block between each frame while the ui thread deals with it.

                    edit: Or use an interface such as QVideoFilterRunnable that is invoked in a manner suitable for playback.

                    Asking a question about code? http://eel.is/iso-c++/testcase/

                    M 1 Reply Last reply 20 Mar 2021, 08:55
                    0
                    • nageshN nagesh
                      19 Mar 2021, 23:08
                      void Controller::play()
                      {
                          while(m_isPlaying)
                          {
                               // get frames from file
                               // update GUI with frame
                               emit showFrameOnWidget(read());                 
                               // update timestamp label
                               emit updateTimestamp(m_timestamp);
                          } 
                      }
                      

                      As play() function is part of while loop without sleep how do you ensure fps?
                      At present it looks like as soon as data read from file is ready signal is emitted, which is causing high cpu usage.
                      Do a comparison of how much time Same file taking to play in VLC and your application?

                      M Offline
                      M Offline
                      MarKS
                      wrote on 20 Mar 2021, 08:36 last edited by
                      #10

                      @nagesh I think you misunderstood my question. I know to ensure FPS and deal with high CPU usage, I need some way to slow down the thread. I asked for a better way to deal with it rather than using thread sleep which in my opinion, not a good design.

                      1 Reply Last reply
                      0
                      • J jeremy_k
                        20 Mar 2021, 06:10

                        @nagesh said in QtConcurrent run with a never ending while loop leads to high CPU usage:

                        As play() function is part of while loop without sleep how do you ensure fps?

                        I missed that the source is a file and not a camera producing frames at a fixed rate.

                        !

                        A timer or blocking IO of some sort is going to be necessary if the goal isn't to be gated by the io, cpu, or memory capacity of the system. Sleeping a fixed interval is a problematic solution because it fails to take into account variability in available capacity. Either set a high precision timer for the desired frame rate, or cause the processing thread to block between each frame while the ui thread deals with it.

                        edit: Or use an interface such as QVideoFilterRunnable that is invoked in a manner suitable for playback.

                        M Offline
                        M Offline
                        MarKS
                        wrote on 20 Mar 2021, 08:55 last edited by MarKS
                        #11

                        @jeremy_k You're right. So, I made a comparison between using a QtConcurrent::run() and QTimer. Here are my observations:

                        1. QtConcurrent::run() is very fast. So I used QThread::msleep(mstime). mstime is calculated from the native fps. For e.g. 30 fps native needs 33 mstime between the frames. CPU Usage: ~40-45%

                        2. Calling play() using QTimer->start(mstime) where mstime is 33 ms leads to CPU usage to ~30-35%

                        It looks like QTimer gives GUI a bit of breather to process events but runs slower than 30 fps playback speed. Whereas, QtConcurrent::run() achieves 30 fps playback speed but drives higher CPU usage.

                        It means QTimer sleep interval doesn't guarantee accuracy even though I am using Qt::PreciseTimer. Please correct me if I am wrong. I do not actually understand how the QTimer functions.

                        But for now, I am stuck between 2 choices.

                        nageshN 1 Reply Last reply 20 Mar 2021, 09:11
                        0
                        • M MarKS
                          20 Mar 2021, 08:55

                          @jeremy_k You're right. So, I made a comparison between using a QtConcurrent::run() and QTimer. Here are my observations:

                          1. QtConcurrent::run() is very fast. So I used QThread::msleep(mstime). mstime is calculated from the native fps. For e.g. 30 fps native needs 33 mstime between the frames. CPU Usage: ~40-45%

                          2. Calling play() using QTimer->start(mstime) where mstime is 33 ms leads to CPU usage to ~30-35%

                          It looks like QTimer gives GUI a bit of breather to process events but runs slower than 30 fps playback speed. Whereas, QtConcurrent::run() achieves 30 fps playback speed but drives higher CPU usage.

                          It means QTimer sleep interval doesn't guarantee accuracy even though I am using Qt::PreciseTimer. Please correct me if I am wrong. I do not actually understand how the QTimer functions.

                          But for now, I am stuck between 2 choices.

                          nageshN Offline
                          nageshN Offline
                          nagesh
                          wrote on 20 Mar 2021, 09:11 last edited by
                          #12

                          @MarKS Qt::PreciseTimer guarantees accuracy up to 1msec, but in that slot what operation is performed that matters.

                          Calling play() using QTimer->start(mstime) where mstime is 33 ms leads to CPU usage to ~30-35%
                          

                          Does this timer is running in GUI/main context?

                          try to create the worker object having Signal/slot and move it to thread context using movetothread..

                          This might reduce the CPU usage

                          M 1 Reply Last reply 20 Mar 2021, 13:36
                          0
                          • M MarKS
                            19 Mar 2021, 22:52

                            @SGaist my bad. It was just an example to show that i emit render signals. Of course i am using the right channels to render images. And yes each signal has its own slot.

                            Christian EhrlicherC Offline
                            Christian EhrlicherC Offline
                            Christian Ehrlicher
                            Lifetime Qt Champion
                            wrote on 20 Mar 2021, 09:38 last edited by
                            #13

                            @MarKS said in QtConcurrent run with a never ending while loop leads to high CPU usage:

                            And yes each signal has its own slot.

                            This was not what @SGaist said - he said you should not emit three different signals with the same data but only one.

                            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                            Visit the Qt Academy at https://academy.qt.io/catalog

                            M 1 Reply Last reply 20 Mar 2021, 13:32
                            0
                            • Christian EhrlicherC Christian Ehrlicher
                              20 Mar 2021, 09:38

                              @MarKS said in QtConcurrent run with a never ending while loop leads to high CPU usage:

                              And yes each signal has its own slot.

                              This was not what @SGaist said - he said you should not emit three different signals with the same data but only one.

                              M Offline
                              M Offline
                              MarKS
                              wrote on 20 Mar 2021, 13:32 last edited by
                              #14

                              @Christian-Ehrlicher I understood. What I meant was 3 different signals are emitted with 3 different channels to 3 different slots. I put the same channel just as an example.

                              1 Reply Last reply
                              0
                              • nageshN nagesh
                                20 Mar 2021, 09:11

                                @MarKS Qt::PreciseTimer guarantees accuracy up to 1msec, but in that slot what operation is performed that matters.

                                Calling play() using QTimer->start(mstime) where mstime is 33 ms leads to CPU usage to ~30-35%
                                

                                Does this timer is running in GUI/main context?

                                try to create the worker object having Signal/slot and move it to thread context using movetothread..

                                This might reduce the CPU usage

                                M Offline
                                M Offline
                                MarKS
                                wrote on 20 Mar 2021, 13:36 last edited by
                                #15

                                @nagesh yes the timer is created in GUI thread. Never tried QTimer in another thread. Will search how to do that. But if you have any pointers that would be helpful.

                                nageshN kshegunovK 2 Replies Last reply 20 Mar 2021, 14:17
                                0
                                • M MarKS
                                  20 Mar 2021, 13:36

                                  @nagesh yes the timer is created in GUI thread. Never tried QTimer in another thread. Will search how to do that. But if you have any pointers that would be helpful.

                                  nageshN Offline
                                  nageshN Offline
                                  nagesh
                                  wrote on 20 Mar 2021, 14:17 last edited by
                                  #16

                                  @MarKS I would suggest first example provided here
                                  https://doc.qt.io/qt-5/qthread.html

                                  You can use worker objects by moving them to the thread using QObject::moveToThread().
                                  

                                  In worker object create timer.

                                  1 Reply Last reply
                                  1
                                  • M MarKS
                                    20 Mar 2021, 13:36

                                    @nagesh yes the timer is created in GUI thread. Never tried QTimer in another thread. Will search how to do that. But if you have any pointers that would be helpful.

                                    kshegunovK Offline
                                    kshegunovK Offline
                                    kshegunov
                                    Moderators
                                    wrote on 20 Mar 2021, 20:38 last edited by
                                    #17

                                    What is DataBuffer? And how do you render the data in the GUI thread?

                                    Read and abide by the Qt Code of Conduct

                                    1 Reply Last reply
                                    0

                                    1/17

                                    19 Mar 2021, 13:54

                                    • Login

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