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. Render/Layout performance very slow. High CPU usage for only 20 QLabels in 30fps
Forum Updated to NodeBB v4.3 + New Features

Render/Layout performance very slow. High CPU usage for only 20 QLabels in 30fps

Scheduled Pinned Locked Moved Unsolved General and Desktop
22 Posts 3 Posters 11.0k Views 2 Watching
  • 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 marcj

    Thanks Mrjj,

    that helped me quite a lot!

    I've come up with following code to use GraphicsView directly and draw some texts (hopefully in OpenGL) using QGraphicsTextItem.

    // main.cpp
    #include <QtWidgets/QApplication>
    #include <QTimer>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QtOpenGL>
    
    int main(int argc, char *argv[])
    {
    
        QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
        QApplication app(argc, argv);
    
        const int labelsCount = 20;
        QGraphicsScene scene;
    
        QGraphicsView view(&scene);
    
        //regarding documentation, this enabled OpengGL
        //and in fact, the rendered font looks different when having this line active
        view.setViewport(new QGLWidget());
    
        QVarLengthArray<QGraphicsTextItem, labelsCount> labels(labelsCount);
    
        for (int i =0; i < labelsCount; i++ ){
            auto text = QStringLiteral("(%1)").arg(i);
            labels[i].setPlainText(text);
            labels[i].setPos(0, i * 15);
            scene.addItem(&labels[i]);
        }
    
        QTimer *timer = new QTimer();
        timer->setInterval(1000/30);
    
        int counter = 0;
        QObject::connect(timer, &QTimer::timeout, [&] {
            counter++;
            for (int i =0; i < labelsCount; i++ ){
                auto text = QStringLiteral("(%1): %3").arg(i).arg(counter);
                labels[i].setPlainText(text);
            }
        });
    
        timer->start();
        view.show();
    
        return app.exec();
    }
    

    However, I'm still at 18% CPU usage. To me, displaying 20 text item without layout manager shouldn't be anything that costs so much CPU. Do I do something wrong here? It looks to me, it uses now OpenGL (text renders different, not so sharp anymore).

    mrjjM Offline
    mrjjM Offline
    mrjj
    Lifetime Qt Champion
    wrote on last edited by mrjj
    #6

    @marcj
    Hi
    Could you test http://doc.qt.io/qt-5/qtwidgets-graphicsview-chip-example.html
    and zoom in and out.

    As far as i recall you have to do
    QOpenGLWidget *glWidget = new QOpenGLWidget();
    setViewport(glWidget); to switch to openGl.

    But i have only tried the older QGLWidget so not sure it still applies.

    Wait a bit and other more heavy openGL users will tell if you need something to use openGl.
    I also seen many posts about it here but search-fu didnt bring it up ;)

    1 Reply Last reply
    0
    • M Offline
      M Offline
      marcj
      wrote on last edited by
      #7

      Here is my code using QGraphicsProxyWidget that is returned when I add QLabel into a QGraphicsView.

      // main.cpp
      #include <QtWidgets/QApplication>
      #include <QTimer>
      #include <QGraphicsScene>
      #include <QGraphicsView>
      #include <QtOpenGL>
      
      int main(int argc, char *argv[])
      {
          QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
          QApplication app(argc, argv);
      
          const int labelsCount = 20;
          QGraphicsScene scene;
      
          QGraphicsView view(&scene);
      
          //regarding documentation, this enabled OpengGL
          //and in fact, the rendered font looks different when having this line active
          view.setViewport(new QGLWidget());
      
          QVarLengthArray<QLabel, labelsCount> labels(labelsCount);
      
          for (int i =0; i < labelsCount; i++ ){
              auto text = QStringLiteral("(%1)").arg(i);
              labels[i].setText(text);
              labels[i].setGeometry(QRect(QPoint(0, i * 15), QSize(100, 15)));
              scene.addWidget(&labels[i]);
          }
      
          QTimer *timer = new QTimer();
          timer->setInterval(1000/30);
      
          int counter = 0;
          QObject::connect(timer, &QTimer::timeout, [&] {
              counter++;
              for (int i =0; i < labelsCount; i++ ){
                  auto text = QStringLiteral("(%1): %3").arg(i).arg(counter);
                  labels[i].setText(text);
              }
          });
      
          timer->start();
          view.show();
      
          return app.exec();
      }
      

      It is in fact OpenGL rendered now, however on my working station OSX 10.12.4 I get tons of warning messages in the console every time the text renders.

      QMacCGContext:: Unsupported painter devtype type 1
      QMacCGContext:: Unsupported painter devtype type 1
      QMacCGContext:: Unsupported painter devtype type 1
      QMacCGContext:: Unsupported painter devtype type 1
      

      Probably related to https://bugreports.qt.io/browse/QTBUG-32639.

      However, still same slow performance of over 15% CPU usage.

      Running out of ideas here. :)

      mrjjM 1 Reply Last reply
      0
      • M marcj

        Here is my code using QGraphicsProxyWidget that is returned when I add QLabel into a QGraphicsView.

        // main.cpp
        #include <QtWidgets/QApplication>
        #include <QTimer>
        #include <QGraphicsScene>
        #include <QGraphicsView>
        #include <QtOpenGL>
        
        int main(int argc, char *argv[])
        {
            QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
            QApplication app(argc, argv);
        
            const int labelsCount = 20;
            QGraphicsScene scene;
        
            QGraphicsView view(&scene);
        
            //regarding documentation, this enabled OpengGL
            //and in fact, the rendered font looks different when having this line active
            view.setViewport(new QGLWidget());
        
            QVarLengthArray<QLabel, labelsCount> labels(labelsCount);
        
            for (int i =0; i < labelsCount; i++ ){
                auto text = QStringLiteral("(%1)").arg(i);
                labels[i].setText(text);
                labels[i].setGeometry(QRect(QPoint(0, i * 15), QSize(100, 15)));
                scene.addWidget(&labels[i]);
            }
        
            QTimer *timer = new QTimer();
            timer->setInterval(1000/30);
        
            int counter = 0;
            QObject::connect(timer, &QTimer::timeout, [&] {
                counter++;
                for (int i =0; i < labelsCount; i++ ){
                    auto text = QStringLiteral("(%1): %3").arg(i).arg(counter);
                    labels[i].setText(text);
                }
            });
        
            timer->start();
            view.show();
        
            return app.exec();
        }
        

        It is in fact OpenGL rendered now, however on my working station OSX 10.12.4 I get tons of warning messages in the console every time the text renders.

        QMacCGContext:: Unsupported painter devtype type 1
        QMacCGContext:: Unsupported painter devtype type 1
        QMacCGContext:: Unsupported painter devtype type 1
        QMacCGContext:: Unsupported painter devtype type 1
        

        Probably related to https://bugreports.qt.io/browse/QTBUG-32639.

        However, still same slow performance of over 15% CPU usage.

        Running out of ideas here. :)

        mrjjM Offline
        mrjjM Offline
        mrjj
        Lifetime Qt Champion
        wrote on last edited by
        #8

        @marcj said in Render/Layout performance very slow. High CPU usage for only 20 QLabels in 30fps:

        Unsupported painter devtype type 1

        Gah , i think you hit a bug with QGLWidget.
        (its the old one, the new is QOpenGLWidget )

        https://bugreports.qt.io/browse/QTBUG-32639
        sounds like that.

        Are you on mac ?

        1 Reply Last reply
        0
        • mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by
          #9

          Btw, do you need anything besides an array of texts ?
          I wondering how how fast a small custom class would be.
          (to draw text)

          But i get the feeling you need openGL for other stuff too?

          1 Reply Last reply
          0
          • M Offline
            M Offline
            marcj
            wrote on last edited by marcj
            #10

            Yes, I'm on a Mac.

            @mrjj said in Render/Layout performance very slow. High CPU usage for only 20 QLabels in 30fps:

            As far as i recall you have to do
            QOpenGLWidget *glWidget = new QOpenGLWidget();
            setViewport(glWidget); to switch to openGl.

            I tried both separately, the differences weren't that big.

                //not having openGL here results in 18.5% usage
                view.setViewport(new QOpenGLWidget()); //17.1% usage
                view.setViewport(new QGLWidget()); //17.8% usage
            

            The thing is, I see definitely differences in the rendered text (openGL is more blurry and more bold), however the CPU-usage is almost the same, that leads me to the conclusion that there is something somewhere else the bottleneck.

            @mrjj said in Render/Layout performance very slow. High CPU usage for only 20 QLabels in 30fps:

            Btw, do you need anything besides an array of texts ?

            Yes, actually the main view is a TableList/Grid, with roughly 10 columns and max 20 rows.
            Most columns are text, but we have also small plots in one column and in another column a progress-bar. The data for that view is coming from a streaming server that is holding machine learning data that yields real-time data in high frequency. It's important to display the stuff in at least 15fps (so plot and progress-bar is smooth). I actually thought rendering the text alone is the smallest thing to think about. :D well it turned out, I have to go to the basics first.

            The other first is actually more complex (both are displayed at the same time, the second when a row from the TableList is selected) which shows anything in realtime about that in more detail manner. Bigger and more plots (up to 20 at the same time), console outputs in realtime, some graphs, progress-bars, quite a lot of status text (single QLabels aligned in a grid).

            Here's a screen of it:

            alt text

            I need OpenGL for the plots and progress-bars (Custom made), due to performance reason. Obviously :)

            1 Reply Last reply
            0
            • mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by mrjj
              #11

              Hi
              hmm, i would have imagined better performance.
              I think the CPU usage comes from keeping event loop busy
              when you set the text, it triggers a paint event and since it does it
              very fast i assume the main event loop is always busy.

              Ah, ok so we cant just cheat and make a custom control that draws array of text.
              You have other elements in that layout ?

              QLabel can have border and and be styles so compared to raw
              QPainter.drawText it is a it heavy(er).
              Not sure how much it would help with custom though.
              Going to try with your sample and see.

              Update:: looks nice. very modern.

              1 Reply Last reply
              0
              • mrjjM Offline
                mrjjM Offline
                mrjj
                Lifetime Qt Champion
                wrote on last edited by
                #12

                Wondering:
                Those in Created ID etc
                are the labels ?

                1 Reply Last reply
                0
                • mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by
                  #13

                  Just for test
                  Seems to use 6-8% on windows
                  alt text

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    marcj
                    wrote on last edited by
                    #14

                    The thing is, the prototype that has most of the stuff already is implemented in TypeScript/HTML5 (no OpenGL here), and we have at 15fps roughly the same CPU usage as QT has with displaying 20 QLabels at 30fps. We wanted to pump it up to 60 fps to get a very smooth running GUI, but that would have cost one CPU core using the HTML5 engine, so I gave QT a try. I'm afraid QT's CPU usage goes through the roof when I implement it using TableView and way more QLabels, Buttons, SelectBox etc as well.

                    So strictly speaking, I thought we could go the native approach to save a LOT cpu circles, but it seems Chromium's HTML engine is already highly optimised as we can compare directly the CPU usage here. I see however an incredible huge CPU usage difference when I compare QT/Chromium with imGUI, so I still have the hope that I can get the same performance using QT. 😎

                    "Create ID" It's actually a simple table grid, just text. First row has special styling due to be the table header with some onclick events.

                    1 Reply Last reply
                    0
                    • mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by mrjj
                      #15

                      Hi
                      Give it a day more so other timezones come online.
                      Some user knows far more about Qt on mac than me.

                      Im pretty sure it can get better but i agree with you that
                      it doesn't look as it will scale well.

                      I have seen reports on QWidgets and macOS having not optimal performance especially
                      with retina displays but im not using macOS so im not sure what current status is.

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        marcj
                        wrote on last edited by
                        #16

                        Thanks MrJJ, much appreciated.

                        mrjjM 1 Reply Last reply
                        1
                        • M marcj

                          Thanks MrJJ, much appreciated.

                          mrjjM Offline
                          mrjjM Offline
                          mrjj
                          Lifetime Qt Champion
                          wrote on last edited by
                          #17

                          @marcj
                          Np. i wish you good luck with project. Looks very nice. ( im GUI lover)

                          1 Reply Last reply
                          0
                          • SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #18

                            Hi,

                            If you want something fancy and with OpenGL then @mrjj's recommendation of QtQuick is the way to go. QtQuick is OpenGL rendered by default.

                            Qt Widgets have never been hardware accelerated and likely won't be any time soon. They allow you to build applications for system with lower specs.

                            As the warning of QGraphicsProxyWidget states, that class should not be used in hight performance scenarios which your application is.

                            As for Apple's OpenGL stack, AFAIK, it's known to not be most recent or up to date regarding the standard, so beware of that when comparing to other systems.

                            On an unrelated note, it's Qt, QT stands for Apple QuickTime which you are likely not using even if developing on macOS.

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

                            1 Reply Last reply
                            1
                            • M Offline
                              M Offline
                              marcj
                              wrote on last edited by marcj
                              #19

                              Alright, I played more with QPainter, and made my own custom QWidget that uses paintEvent() to call painter->drawText directly. That should be the fastest I can get, right? Indeed, it was roughly twice the speed (8% vs 17%). However, there's no automatic geometric calculation yet for the layout manager.

                              My code:

                              // main.cpp
                              #include <QtWidgets/QApplication>
                              #include <QTimer>
                              #include <QGraphicsScene>
                              #include <QGraphicsView>
                              #include <QGridLayout>
                              #include <QtOpenGL>
                              #include <QOpenGLWidget>
                              #include <QDebug>
                              
                              class MyWidget: public QWidget {
                              
                              
                              public:
                                  QString text;
                                  QSize size;
                              
                                  MyWidget() : QWidget() {
                                      setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
                                      size.setWidth(100);
                                      size.setHeight(15);
                                  }
                              
                                  void paintEvent(QPaintEvent *event) override {
                                      QPainter painter(this);
                                      painter.setPen(Qt::black);
                                      painter.setFont(QFont("Helvetica", 14));
                                      painter.drawText(0, 14, text);
                                  }
                              
                                  QSize sizeHint() const
                                  {
                                      return size;
                                  }
                              
                                  void setPlainText(QString text) {
                                      this->text = text;
                                      update();
                                  }
                              
                              };
                              
                              int main(int argc, char *argv[]) {
                                  QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
                                  QApplication app(argc, argv);
                              
                                  const int labelsCount = 200;
                                  const int cols = 10;
                                  QGraphicsScene scene;
                              
                                  QGridLayout *layout = new QGridLayout();
                              
                                  QGraphicsView view(&scene);
                                  view.setLayout(layout);
                              
                                  //regarding documentation, this enabled OpengGL
                                  //and in fact, the rendered font looks different when having this line active
                                  view.setViewport(new QOpenGLWidget()); //helps a lot the more draws we have
                              //    view.setViewport(new QGLWidget()); //doesnt work on OSX
                              
                                  QVarLengthArray<MyWidget, labelsCount> labels(labelsCount);
                              
                                  for (int i =0; i < labelsCount; i++ ){
                                      labels[i].setPlainText(QString("Hallo %1").arg(i));
                                      layout->addWidget(&labels[i], floor(i / cols), i % cols);
                                  }
                              
                                  QTimer *timer = new QTimer();
                                  timer->setInterval(1000/30);
                              
                                  int counter = 0;
                                  QObject::connect(timer, &QTimer::timeout, [&] {
                                      counter++;
                                      for (int i =0; i < labelsCount; i++ ){
                                          auto text = QStringLiteral("(%1): %3").arg(i).arg(counter);
                                          labels[i].setPlainText(text);
                                      }
                                  });
                              
                                  timer->start();
                                  view.show();
                              
                                  return app.exec();
                              }
                              

                              After this good news I tested with a more realistic scenario: Having 200 labels updating in real-time (30fps). Screenshot:

                              0_1527716563882_Screen Shot 2018-05-30 at 23.42.26.png

                              At the bottom you see my HTOP Cpu utilization from that process. Unfortunately, still at 50% of a Intel i7 with over 3Ghz. The GPU isn't the bottleneck either, since I got a NVIDIA Titan Xp with 12GB RAM - no retina Display.

                              I'm running out of ideas here since I've never used QT until today and probably lack some fundamentals. I actually can't believe that printing directly with the QPainter is so darn slow. so there must be something I'm currently missing . Does anyone have an idea what else I could do? (except to leave QT behind)

                              1 Reply Last reply
                              0
                              • M Offline
                                M Offline
                                marcj
                                wrote on last edited by marcj
                                #20

                                I tried further to see where the bottleneck is. My next example shows how 200 very simple progress-bars perform. Result is that it renders way faster, only 13% CPU usage (30fps). However, drawing such OpenGL primitives is in other GUI abstraction an extremely easy task and costs almost zero CPU.

                                Code:

                                // main.cpp
                                #include <QtWidgets/QApplication>
                                #include <QTimer>
                                #include <QGraphicsScene>
                                #include <QGraphicsView>
                                #include <QGridLayout>
                                #include <QtOpenGL>
                                #include <QOpenGLWidget>
                                #include <QDebug>
                                
                                class MyWidget: public QWidget {
                                
                                
                                public:
                                    QString text;
                                    int value = 0; //0 -> 100
                                    QSize size;
                                
                                    MyWidget() : QWidget() {
                                        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
                                        size.setWidth(100);
                                        size.setHeight(15);
                                    }
                                
                                    void paintEvent(QPaintEvent *event) override {
                                        QPainter painter(this);
                                        painter.fillRect(QRect(0, 0, value % 100, 14), Qt::black);
                                    }
                                
                                    QSize sizeHint() const
                                    {
                                        return size;
                                    }
                                
                                    void setValue(int value) {
                                        this->value = value;
                                        update();
                                    }
                                
                                };
                                
                                int main(int argc, char *argv[]) {
                                    QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
                                    QApplication app(argc, argv);
                                
                                    const int labelsCount = 200;
                                    const int cols = 10;
                                    QGraphicsScene scene;
                                
                                    QGridLayout *layout = new QGridLayout();
                                
                                    QGraphicsView view(&scene);
                                    view.setLayout(layout);
                                
                                    //regarding documentation, this enabled OpengGL
                                    //and in fact, the rendered font looks different when having this line active
                                    view.setViewport(new QOpenGLWidget()); //helps a lot the more draws we have
                                
                                    QVarLengthArray<MyWidget, labelsCount> labels(labelsCount);
                                
                                    for (int i =0; i < labelsCount; i++ ){
                                        layout->addWidget(&labels[i], floor(i / cols), i % cols);
                                    }
                                
                                    QTimer *timer = new QTimer();
                                    timer->setInterval(1000/30);
                                
                                    int counter = 0;
                                    QObject::connect(timer, &QTimer::timeout, [&] {
                                        counter++;
                                        for (int i =0; i < labelsCount; i++ ){
                                            labels[i].setValue(counter);
                                        }
                                    });
                                
                                    timer->start();
                                    view.show();
                                
                                    return app.exec();
                                }
                                

                                Screen:

                                0_1527717767958_Screen Shot 2018-05-31 at 00.01.37.png


                                I also just made sure it's really not my hardware and implemented in another GUI library almost the same case: 200 progress-bars (although in this example it shows also text). Result is 4% CPU usage, but with a major difference that it renders at 100fps. If I go 100 fps in Qt example above, I get 50% cpu usage. If I add text right next to the rect I get probably 100%.

                                Screen of the other GUI lib:

                                0_1527718484641_Screen Shot 2018-05-31 at 00.14.28.png

                                So I guess there must be something in QT where I can have more direct access to the OpenGL abstraction.

                                1 Reply Last reply
                                0
                                • M Offline
                                  M Offline
                                  marcj
                                  wrote on last edited by marcj
                                  #21

                                  I tried now as you guys suggested the QT Quick Widgets, which should be rendered with OpenGL and with performance in mind (I mean it should run on mobile devices right?). Result is not really satisfying, I guess even worse. 100 labels, 30fps -> 33% CPU burn.

                                  0_1527725605455_Screen Shot 2018-05-31 at 02.13.11.png

                                  Code for that:

                                  //main.cpp
                                  #include <QGuiApplication>
                                  #include <QTimer>
                                  #include <QQuickItem>
                                  #include <QQmlApplicationEngine>
                                  
                                  int main(int argc, char *argv[])
                                  {
                                      QGuiApplication app(argc, argv);
                                  
                                      QQmlApplicationEngine engine;
                                      engine.load(QUrl(QStringLiteral("main.qml")));
                                  
                                      QQuickItem *list = engine.rootObjects()[0]->findChild<QQuickItem *>(QString("list"),
                                                                                                           Qt::FindChildrenRecursively);
                                  
                                      QTimer *timer = new QTimer();
                                      timer->setInterval(1000/30);
                                      int counter = 0;
                                  
                                      QObject::connect(timer, &QTimer::timeout, [&] {
                                          counter++;
                                          for(auto const& item: list->childItems()) {
                                              item->setProperty("text", QString("WTF %1").arg(counter));
                                          }
                                      });
                                  
                                      timer->start();
                                  
                                      return app.exec();
                                  }
                                  
                                  import QtQuick 2.6
                                  import QtQuick.Controls 2.0
                                  
                                  ApplicationWindow {
                                      id: root
                                      width: 600
                                      height: 500
                                      visible: true
                                  
                                      Grid {
                                          objectName: "list"
                                          rows: 50
                                          columns: 10
                                          spacing: 10
                                  
                                          Repeater {
                                              model: 100;
                                              objectName: "repeater"
                                              Label {
                                                  text: "Hello world"
                                                  width: 60
                                                  objectName: "label" + index
                                              }
                                          }
                                      }
                                  }
                                  
                                  1 Reply Last reply
                                  0
                                  • SGaistS Offline
                                    SGaistS Offline
                                    SGaist
                                    Lifetime Qt Champion
                                    wrote on last edited by
                                    #22

                                    If you'd like to go on with raw OpenGL, then the Qt OpenGL and GUI modules are what you want to look at, they provide everything you need to write OpenGL application.

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

                                    1 Reply Last reply
                                    1

                                    • Login

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