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. Deleting QChart Causes 30+ Second Application Hang!
Forum Updated to NodeBB v4.3 + New Features

Deleting QChart Causes 30+ Second Application Hang!

Scheduled Pinned Locked Moved Unsolved General and Desktop
51 Posts 5 Posters 3.9k 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.
  • F FleetingMemory

    @JonB I think its not the number of points in a singular line, but the number of series (lines) in total causing the problem. My times I listed are from running on release.

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by JonB
    #20

    @FleetingMemory
    I asked you to produce a minimal example such as mine but you have not. I said earlier I was guessing 10 series to make 500,000 points. If you want help I don't see why you can't convey the necessary information, no point leaving me to create 10 series I mentioned and then say it's not the right number..... And you could always alter my code to whatever numbers you desire to test.....

    1 Reply Last reply
    0
    • F FleetingMemory

      @JonB I think its not the number of points in a singular line, but the number of series (lines) in total causing the problem. My times I listed are from running on release.

      JoeCFDJ Offline
      JoeCFDJ Offline
      JoeCFD
      wrote on last edited by JoeCFD
      #21

      @FleetingMemory try to call
      removeAllSeries() first. It seems this call will not trigger update of qchart.
      and then update,
      next delete chart.

      F 1 Reply Last reply
      1
      • JoeCFDJ JoeCFD

        @FleetingMemory try to call
        removeAllSeries() first. It seems this call will not trigger update of qchart.
        and then update,
        next delete chart.

        F Offline
        F Offline
        FleetingMemory
        wrote on last edited by
        #22

        @JoeCFD Will give this a try and let you know!

        JonBJ 1 Reply Last reply
        0
        • F FleetingMemory

          @JoeCFD Will give this a try and let you know!

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #23

          @FleetingMemory
          In your first post of the steps you have tried you already included

          Removing all series prior to deleting

          1 Reply Last reply
          0
          • F Offline
            F Offline
            FleetingMemory
            wrote on last edited by
            #24

            Yeah, I am going to retry in release with elapsed() to see what is going on and give more info.
            Query Size 450,000 points. Spread across 12,000 series.
            populating the series after query takes 2,964 milliseconds
            Gets stuck on remove all series (freezes main thread), takes 35,774 milliseconds to remove

            JonBJ 1 Reply Last reply
            0
            • F FleetingMemory

              Yeah, I am going to retry in release with elapsed() to see what is going on and give more info.
              Query Size 450,000 points. Spread across 12,000 series.
              populating the series after query takes 2,964 milliseconds
              Gets stuck on remove all series (freezes main thread), takes 35,774 milliseconds to remove

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #25

              @FleetingMemory
              Yes please test. OOI how can you expect to display 12,000 series to a user, I just don't get it?

              1 Reply Last reply
              0
              • F Offline
                F Offline
                FleetingMemory
                wrote on last edited by
                #26

                A little more testing - I used release mode, removed all series from QChart in a QChartView after a new query is run. During this test I re-used the same QChart -- after running removeAllSeries(), I used the points from the query to generate new series and add them to the chart. Points are formatted <millis since epoch, value>. Series have OpenGL turned on in this test.

                1: A Query is run, Qlist<Qlist<QPointF>> generated. I return the Query Count
                2: If QChart Exists, remove all series (this I timed)
                3: for each Qlist<QPointF> generate a new series with replace(), append Axes and insert into chart (this I timed)

                Query Size 450,000 points. Spread across 12,000 series.
                populating 12,000 series after query takes 2.964 s
                Gets stuck on remove all 12,000 series (freezes main thread), takes 35.774 seconds to remove

                Query Size: 332,000 points
                populating 10,600 series: 3.3s
                populating 2nd time diff data: 3.4s
                removing all series: 25.35s
                removing all (2nd time diff data): 25.6s

                Query Size: 247,900 points
                populating 9300 series: 2.5s
                removing all series: 19s

                Query Size 250,000
                Populating Series: 1.32 s
                removing all 8,050 series: 14.33s
                removing all 8,050 series (2nd run diff data): 13.4s

                Query Size 223,200
                Populating 8600 series: 2.4s
                populating 8600 series(2nd run diff data): 2s
                removing all series: 15.6s
                removing all series (2nd run diff data): 15.6s

                Query Size: 195,600
                populating series: 1.7s
                Removing 7820 series: 12.5s
                removing all 7820 series (2nd run diff data): 12.9s

                Query Size 158,543
                populating the series after query: 0.7s
                removing all 4,859 series: 4.9s

                Query Size 21700
                Removing 1240 series: 0.395s
                populating series: 0.1s

                Query Size: 9,818
                populating series: 0.04s
                removing all 735 series: 0.045s
                removing all 735 series (2nd run diff data): 0.044s

                Performance seems to get worse pretty quickly at a non-linear rate

                If it helps, I am compiling this as a plugin loaded in a simple main application (though that shouldn't affect things).
                I have tried with useOpenGL both on and off. As far as I can tell, it makes little difference.
                The fact the removeAll/delete freezes the main thread, which essentially locks up the entire application it is running in is a huge issue for me...

                JoeCFDJ JonBJ 2 Replies Last reply
                0
                • F FleetingMemory

                  A little more testing - I used release mode, removed all series from QChart in a QChartView after a new query is run. During this test I re-used the same QChart -- after running removeAllSeries(), I used the points from the query to generate new series and add them to the chart. Points are formatted <millis since epoch, value>. Series have OpenGL turned on in this test.

                  1: A Query is run, Qlist<Qlist<QPointF>> generated. I return the Query Count
                  2: If QChart Exists, remove all series (this I timed)
                  3: for each Qlist<QPointF> generate a new series with replace(), append Axes and insert into chart (this I timed)

                  Query Size 450,000 points. Spread across 12,000 series.
                  populating 12,000 series after query takes 2.964 s
                  Gets stuck on remove all 12,000 series (freezes main thread), takes 35.774 seconds to remove

                  Query Size: 332,000 points
                  populating 10,600 series: 3.3s
                  populating 2nd time diff data: 3.4s
                  removing all series: 25.35s
                  removing all (2nd time diff data): 25.6s

                  Query Size: 247,900 points
                  populating 9300 series: 2.5s
                  removing all series: 19s

                  Query Size 250,000
                  Populating Series: 1.32 s
                  removing all 8,050 series: 14.33s
                  removing all 8,050 series (2nd run diff data): 13.4s

                  Query Size 223,200
                  Populating 8600 series: 2.4s
                  populating 8600 series(2nd run diff data): 2s
                  removing all series: 15.6s
                  removing all series (2nd run diff data): 15.6s

                  Query Size: 195,600
                  populating series: 1.7s
                  Removing 7820 series: 12.5s
                  removing all 7820 series (2nd run diff data): 12.9s

                  Query Size 158,543
                  populating the series after query: 0.7s
                  removing all 4,859 series: 4.9s

                  Query Size 21700
                  Removing 1240 series: 0.395s
                  populating series: 0.1s

                  Query Size: 9,818
                  populating series: 0.04s
                  removing all 735 series: 0.045s
                  removing all 735 series (2nd run diff data): 0.044s

                  Performance seems to get worse pretty quickly at a non-linear rate

                  If it helps, I am compiling this as a plugin loaded in a simple main application (though that shouldn't affect things).
                  I have tried with useOpenGL both on and off. As far as I can tell, it makes little difference.
                  The fact the removeAll/delete freezes the main thread, which essentially locks up the entire application it is running in is a huge issue for me...

                  JoeCFDJ Offline
                  JoeCFDJ Offline
                  JoeCFD
                  wrote on last edited by JoeCFD
                  #27

                  @FleetingMemory
                  look at source code here.
                  https://codebrowser.dev/qt5/qtcharts/src/charts/qchart.cpp.html
                  removeAllSeries func has a loop to call removeSeries(QAbstractSeries *series)
                  I guess it will trigger update for each removal. This is not efficient.

                  1 Reply Last reply
                  1
                  • F FleetingMemory

                    A little more testing - I used release mode, removed all series from QChart in a QChartView after a new query is run. During this test I re-used the same QChart -- after running removeAllSeries(), I used the points from the query to generate new series and add them to the chart. Points are formatted <millis since epoch, value>. Series have OpenGL turned on in this test.

                    1: A Query is run, Qlist<Qlist<QPointF>> generated. I return the Query Count
                    2: If QChart Exists, remove all series (this I timed)
                    3: for each Qlist<QPointF> generate a new series with replace(), append Axes and insert into chart (this I timed)

                    Query Size 450,000 points. Spread across 12,000 series.
                    populating 12,000 series after query takes 2.964 s
                    Gets stuck on remove all 12,000 series (freezes main thread), takes 35.774 seconds to remove

                    Query Size: 332,000 points
                    populating 10,600 series: 3.3s
                    populating 2nd time diff data: 3.4s
                    removing all series: 25.35s
                    removing all (2nd time diff data): 25.6s

                    Query Size: 247,900 points
                    populating 9300 series: 2.5s
                    removing all series: 19s

                    Query Size 250,000
                    Populating Series: 1.32 s
                    removing all 8,050 series: 14.33s
                    removing all 8,050 series (2nd run diff data): 13.4s

                    Query Size 223,200
                    Populating 8600 series: 2.4s
                    populating 8600 series(2nd run diff data): 2s
                    removing all series: 15.6s
                    removing all series (2nd run diff data): 15.6s

                    Query Size: 195,600
                    populating series: 1.7s
                    Removing 7820 series: 12.5s
                    removing all 7820 series (2nd run diff data): 12.9s

                    Query Size 158,543
                    populating the series after query: 0.7s
                    removing all 4,859 series: 4.9s

                    Query Size 21700
                    Removing 1240 series: 0.395s
                    populating series: 0.1s

                    Query Size: 9,818
                    populating series: 0.04s
                    removing all 735 series: 0.045s
                    removing all 735 series (2nd run diff data): 0.044s

                    Performance seems to get worse pretty quickly at a non-linear rate

                    If it helps, I am compiling this as a plugin loaded in a simple main application (though that shouldn't affect things).
                    I have tried with useOpenGL both on and off. As far as I can tell, it makes little difference.
                    The fact the removeAll/delete freezes the main thread, which essentially locks up the entire application it is running in is a huge issue for me...

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by
                    #28

                    @FleetingMemory
                    Why can't you test exactly these figures, with whatever (hopefully tiny) code you use, against the skeleton I provided? You only have to alter the two loop counters. Then people have actual code they can test, so far as I know we really don't know for sure what your code reads. I seem to have been saying/suggesting this all along. If you want people to help, or even to report a bug, we have to have a complete, minimal, reproducible example.

                    1 Reply Last reply
                    0
                    • JonBJ JonB

                      @FleetingMemory
                      Well I don't find anything like you do. Here is a sample I think you should try:

                      #ifndef WIDGET_H
                      #define WIDGET_H
                      
                      #include <QtCharts>
                      #include <QWidget>
                      
                      class Widget : public QWidget
                      {
                          Q_OBJECT
                      
                      public:
                          Widget(QWidget *parent = nullptr);
                          ~Widget();
                      
                      private:
                          QChart *chart;
                          QChartView *chartView;
                      
                      private slots:
                          void deleteChart();
                      };
                      #endif // WIDGET_H
                      
                      #include <QDebug>
                      #include <QElapsedTimer>
                      #include <QTimer>
                      #include <QVBoxLayout>
                      
                      #include "widget.h"
                      
                      // using namespace QtCharts;
                      
                      Widget::Widget(QWidget *parent)
                          : QWidget(parent)
                      {
                          setGeometry(100, 100, 800, 600);
                          setLayout(new QVBoxLayout);
                      
                          this->chart = new QChart();
                          this->chartView = new QChartView(chart, this);
                          layout()->addWidget(chartView);
                          chartView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
                      
                          for (int i = 0; i < 10; i++)
                          {
                              QLineSeries* series = new QLineSeries();
                              for (int x = 0; x < 50000; x++)
                                  series->append(x, x * (i + 1));
                              chart->addSeries(series);
                          }
                      
                          QTimer::singleShot(2000, this, &Widget::deleteChart);
                      }
                      
                      void Widget::deleteChart()
                      {
                          QElapsedTimer elapsed;
                          qDebug() << "Starting to delete";
                          elapsed.start();
                          layout()->removeWidget(chartView);
                          delete chart;
                          chart = nullptr;
                          delete chartView;
                          chartView = nullptr;
                          qDebug() << "Finished deleting" << elapsed.elapsed();
                      }
                      
                      Widget::~Widget() {}
                      

                      500,000 points, 10 series. For me this takes 6 milliseconds to "delete", where you claim 30 seconds! Ubuntu 24.04, VirtualBox slow machine/not nearly as much memory as you, Qt 6.4.2 supplied with Ubuntu. How long does it take you?

                      Possible it could be slow if compiled for Debug, though that is actually how I ran mine, you might check whether Release makes a huger difference?

                      F Offline
                      F Offline
                      FleetingMemory
                      wrote on last edited by
                      #29

                      @JonB I just tried your loop. I get similar results when increasing series count.

                      JoeCFDJ 1 Reply Last reply
                      1
                      • F FleetingMemory

                        @JonB I just tried your loop. I get similar results when increasing series count.

                        JoeCFDJ Offline
                        JoeCFDJ Offline
                        JoeCFD
                        wrote on last edited by JoeCFD
                        #30

                        @FleetingMemory I tried Jon's code with 10000 series + 10 points and tried different things:

                        1. disable update of QChartView
                        2. disable QChartView and QChart
                        3. hide QChartView and QChart
                          before chart is deleted. Nothing helps.

                        However, I am able to get quick clean-up of qchartview with

                            chartView->setChart( new QChart() );
                            chart->deleteLater();
                        

                        Not sure if this helps you. If this piece of code does not help, you may try to delete the chart in a thread while charview is available for other uses. I guess your app will have issue at exit.

                        F 2 Replies Last reply
                        1
                        • JoeCFDJ JoeCFD

                          @FleetingMemory I tried Jon's code with 10000 series + 10 points and tried different things:

                          1. disable update of QChartView
                          2. disable QChartView and QChart
                          3. hide QChartView and QChart
                            before chart is deleted. Nothing helps.

                          However, I am able to get quick clean-up of qchartview with

                              chartView->setChart( new QChart() );
                              chart->deleteLater();
                          

                          Not sure if this helps you. If this piece of code does not help, you may try to delete the chart in a thread while charview is available for other uses. I guess your app will have issue at exit.

                          F Offline
                          F Offline
                          FleetingMemory
                          wrote on last edited by
                          #31
                          This post is deleted!
                          1 Reply Last reply
                          0
                          • JoeCFDJ JoeCFD

                            @FleetingMemory I tried Jon's code with 10000 series + 10 points and tried different things:

                            1. disable update of QChartView
                            2. disable QChartView and QChart
                            3. hide QChartView and QChart
                              before chart is deleted. Nothing helps.

                            However, I am able to get quick clean-up of qchartview with

                                chartView->setChart( new QChart() );
                                chart->deleteLater();
                            

                            Not sure if this helps you. If this piece of code does not help, you may try to delete the chart in a thread while charview is available for other uses. I guess your app will have issue at exit.

                            F Offline
                            F Offline
                            FleetingMemory
                            wrote on last edited by FleetingMemory
                            #32

                            @JoeCFD I tried that as well, it is marginally faster to delete this way than removeAll. I have tried threading but because QChart calls GUI functions, I was not able to get it to work. I tried threading the delete as well as the removal of Series. Neither works. I usually run into errors like -- widget cannot be moved to a new thread -- accessing widget from wrong thread (usually pertains to the QChartData) -- sending signal accross thread, which results in an immediate crash. This is because the removeALLSeries and delete call on update()

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

                              Hi,

                              Did you try calling setUpdateEnabled(false) on the chart ?

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

                              F 1 Reply Last reply
                              0
                              • SGaistS SGaist

                                Hi,

                                Did you try calling setUpdateEnabled(false) on the chart ?

                                F Offline
                                F Offline
                                FleetingMemory
                                wrote on last edited by FleetingMemory
                                #34

                                @SGaist QChart does not have updatesEnabled(false) only QChartView. Doesn't seem to make a difference. I also tried blocking signals.

                                1 Reply Last reply
                                0
                                • F FleetingMemory

                                  @JoeCFD I tried that as well, it is marginally faster to delete this way than removeAll. I have tried threading but because QChart calls GUI functions, I was not able to get it to work. I tried threading the delete as well as the removal of Series. Neither works. I usually run into errors like -- widget cannot be moved to a new thread -- accessing widget from wrong thread (usually pertains to the QChartData) -- sending signal accross thread, which results in an immediate crash. This is because the removeALLSeries and delete call on update()

                                  JoeCFDJ Offline
                                  JoeCFDJ Offline
                                  JoeCFD
                                  wrote on last edited by
                                  #35

                                  @FleetingMemory My results with Jon's code:

                                  1. use deleteLater
                                    Starting to delete
                                    Finished deleting 771
                                  2. original deletion
                                    Starting to delete
                                    Finished deleting 11663

                                  Qt 6.8.2 + Ubuntu 22.04

                                  F 1 Reply Last reply
                                  0
                                  • JoeCFDJ JoeCFD

                                    @FleetingMemory My results with Jon's code:

                                    1. use deleteLater
                                      Starting to delete
                                      Finished deleting 771
                                    2. original deletion
                                      Starting to delete
                                      Finished deleting 11663

                                    Qt 6.8.2 + Ubuntu 22.04

                                    F Offline
                                    F Offline
                                    FleetingMemory
                                    wrote on last edited by FleetingMemory
                                    #36

                                    @JoeCFD how many series? It still locks the main thread though... I did not see a noticeable difference between delete and deleteLater performance on my side

                                    JoeCFDJ 1 Reply Last reply
                                    0
                                    • F FleetingMemory

                                      @JoeCFD how many series? It still locks the main thread though... I did not see a noticeable difference between delete and deleteLater performance on my side

                                      JoeCFDJ Offline
                                      JoeCFDJ Offline
                                      JoeCFD
                                      wrote on last edited by JoeCFD
                                      #37

                                      @FleetingMemory 10000 series + 10 points

                                      Jon's code and chartView is not deleted. Series are cleared quickly.

                                      #include "chart.h"
                                      
                                      // using namespace QtCharts;
                                      
                                      Widget::Widget(QWidget *parent)
                                          : QWidget(parent)
                                      {
                                          setGeometry(100, 100, 800, 600);
                                          setLayout(new QVBoxLayout);
                                      
                                          this->chart = new QChart();
                                          this->chartView = new QChartView(chart, this);
                                          layout()->addWidget(chartView);
                                          chartView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
                                      
                                          for (int i = 0; i < 10000; i++)
                                          {
                                              QLineSeries* series = new QLineSeries();
                                              for (int x = 0; x < 10; x++)
                                                  series->append(x, x * (i + 1));
                                              chart->addSeries(series);
                                          }
                                          
                                          chart->createDefaultAxes();
                                          chart->axes(Qt::Horizontal).first()->setTitleText("X Axis");
                                          chart->axes(Qt::Vertical).first()->setTitleText("Y Axis");
                                          QTimer::singleShot(5000, this, &Widget::deleteChart);
                                      }
                                      
                                      void Widget::deleteChart()
                                      {
                                          QElapsedTimer elapsed;
                                          qDebug() << "Starting to delete";
                                          elapsed.start(); 
                                      
                                          chartView->setChart( new QChart() );
                                          chart->deleteLater();
                                      
                                          layout()->removeWidget(chartView);
                                          //chart->removeAllSeries();
                                          //delete chart;
                                          //chart = nullptr;
                                          //delete chartView;
                                          //chartView = nullptr;
                                          qDebug() << "Finished deleting" << elapsed.elapsed();
                                      }
                                      
                                      Widget::~Widget() {}
                                      
                                      F 1 Reply Last reply
                                      0
                                      • JoeCFDJ JoeCFD

                                        @FleetingMemory 10000 series + 10 points

                                        Jon's code and chartView is not deleted. Series are cleared quickly.

                                        #include "chart.h"
                                        
                                        // using namespace QtCharts;
                                        
                                        Widget::Widget(QWidget *parent)
                                            : QWidget(parent)
                                        {
                                            setGeometry(100, 100, 800, 600);
                                            setLayout(new QVBoxLayout);
                                        
                                            this->chart = new QChart();
                                            this->chartView = new QChartView(chart, this);
                                            layout()->addWidget(chartView);
                                            chartView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
                                        
                                            for (int i = 0; i < 10000; i++)
                                            {
                                                QLineSeries* series = new QLineSeries();
                                                for (int x = 0; x < 10; x++)
                                                    series->append(x, x * (i + 1));
                                                chart->addSeries(series);
                                            }
                                            
                                            chart->createDefaultAxes();
                                            chart->axes(Qt::Horizontal).first()->setTitleText("X Axis");
                                            chart->axes(Qt::Vertical).first()->setTitleText("Y Axis");
                                            QTimer::singleShot(5000, this, &Widget::deleteChart);
                                        }
                                        
                                        void Widget::deleteChart()
                                        {
                                            QElapsedTimer elapsed;
                                            qDebug() << "Starting to delete";
                                            elapsed.start(); 
                                        
                                            chartView->setChart( new QChart() );
                                            chart->deleteLater();
                                        
                                            layout()->removeWidget(chartView);
                                            //chart->removeAllSeries();
                                            //delete chart;
                                            //chart = nullptr;
                                            //delete chartView;
                                            //chartView = nullptr;
                                            qDebug() << "Finished deleting" << elapsed.elapsed();
                                        }
                                        
                                        Widget::~Widget() {}
                                        
                                        F Offline
                                        F Offline
                                        FleetingMemory
                                        wrote on last edited by
                                        #38

                                        @JoeCFD Going back to my original code, I tried moving setchart(new QChart()) and deletelater() to before I populate the new chart with new series. Previously I was populating a new chart then setting it, then deleting a pointer to the old chart. Now, if I watch the memory, deleteLater still doesn't actually call delete until after the new chart is populated fully. So it looks like it deleted quickly but it still hangs after the new chart pops in with data. Doing it this way, however does take slightly less time to delete.

                                        JoeCFDJ 1 Reply Last reply
                                        0
                                        • F FleetingMemory

                                          @JoeCFD Going back to my original code, I tried moving setchart(new QChart()) and deletelater() to before I populate the new chart with new series. Previously I was populating a new chart then setting it, then deleting a pointer to the old chart. Now, if I watch the memory, deleteLater still doesn't actually call delete until after the new chart is populated fully. So it looks like it deleted quickly but it still hangs after the new chart pops in with data. Doing it this way, however does take slightly less time to delete.

                                          JoeCFDJ Offline
                                          JoeCFDJ Offline
                                          JoeCFD
                                          wrote on last edited by JoeCFD
                                          #39

                                          @FleetingMemory Maybe try to delete it in a thread. Also a splash widget may be needed at exit.

                                          F 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