Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QCharts performance on Windows is abyssmal compared to Linux
Forum Updated to NodeBB v4.3 + New Features

QCharts performance on Windows is abyssmal compared to Linux

Scheduled Pinned Locked Moved Solved QML and Qt Quick
4 Posts 2 Posters 436 Views 1 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.
  • fcarneyF Offline
    fcarneyF Offline
    fcarney
    wrote on last edited by fcarney
    #1

    I am running the same program on both Windows and Linux to test out QCharts. I am finding the Windows performance for the exact same code is terrible.
    main.qml:

    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    import QtCharts 2.15
    import QtQml.Models 2.15
    
    Window {
        id: window
    
        width: 800
        height: 600
        visible: true
        title: qsTr("Test sending lots of data to chart")
    
        property var model: [0,1,2,3]
        property var cdata
    
        property bool useOpenGL: true
    
        function genData(){
            let data = []
            for(let count=0; count<1024; ++count){
                let val1 = Math.random() * 200
                let val2 = Math.random() * 200
                let val3 = Math.random() * 200
                let val4 = Math.random() * 200
    
                let vlist = [val1,val2,val3,val4]
                data.push(vlist)
            }
            window.cdata = data
        }
    
        Timer {
            id: datasimtimer
    
            interval: 1000
            repeat: true
            running: true
            onTriggered: {
                genData()
                threshchart.updateData(cdata)
            }
        }
    
        ChartView {
            id: threshchart
    
            width: window.width
            height: window.height - 50
            animationOptions: ChartView.NoAnimation
    
            property var seriesList: []
    
            function updateData(cdata){
                //console.log("updateData")
    
                // clear points
                for(let id in seriesList){
                    let series = seriesList[id]
                    series.removePoints(0, series.count)
                }
    
                // add points)
                let xinc = xaxis.max/1024.0
                let pointcount = 0
                for(let count in cdata){
                    for(let subcount in cdata[count]){
                        let series = seriesList[subcount]
                        series.append(xinc*count, cdata[count][subcount])
                        //series.insert(series.count, xinc*count, cdata[count][subcount])
                        pointcount += 1
                    }
                }
                //console.log("updateData", pointcount)
            }
    
            ValueAxis {
                id: xaxis
    
                min: 0
                max: 200
            }
            ValueAxis {
                id: yaxis
    
                min: 0
                max: 200
            }
    
            ValueAxis {
                id: xaxisthresh
    
                visible: false
    
                min: 0
                max: 1
            }
    
            LineSeries {
                id: thresholdseries
    
                name: "Thresh"
    
                axisX: xaxisthresh
                axisY: yaxis
    
                XYPoint {x:0; y: 100}
                XYPoint {x:1; y: 100}
    
                useOpenGL: window.useOpenGL
            }
    
            Instantiator {
                id: seriesinstancer
    
                model: window.model
    
                onObjectAdded: {
                    let series = threshchart.createSeries(object.type, "Data %1".arg(index), xaxis, yaxis)
                    series.useOpenGL = window.useOpenGL
                    threshchart.seriesList.push(series)
                }
    
                QtObject {
                    property var type: ChartView.SeriesTypeLine
                }
            }
        }
    
        Button {
            anchors.top: threshchart.bottom
            text: "Press"
            width: 100
            height: 30
        }
    }
    

    main.cpp:

    #include <QApplication>
    #include <QQmlApplicationEngine>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    

    It runs great on Linux and does not "pause" the user experience. It does pause and cause interface delays on Windows 10. I have run this on 2 different Windows 10 machines with updated NVidia graphics drivers. The Linux machine is running with default Linux drivers that come with Ubuntu 18.04. Without useOpenGL true the performance is much much worse on Windows and Linux.

    I have tested this on 5.15.1, 5.15.2, and 5.15.3.

    C++ is a perfectly valid school of magic.

    1 Reply Last reply
    1
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by fcarney
      #3

      I restructured my data in qml to be linear point list and then updated via this function:

      class PointUpdater : public QObject
      {
          Q_OBJECT
      public:
          PointUpdater(QObject* parent=nullptr)
              : QObject(parent)
          {
          }
      
      public slots:
          void update(QAbstractSeries *series, QVariantList points){
              if(!series){
                  return;
              }
              QVector<QPointF> newpoints;
              for(QVariant point: points){
                  auto list = point.toList();
                  newpoints.push_back(QPointF(list.at(0).toDouble(), list.at(1).toDouble()));
              }
      
              QXYSeries *xySeries = static_cast<QXYSeries *>(series);
              xySeries->replace(newpoints);
          }
      };
      

      I took this from the scope example. It updates very fast.

      Edit:
      We tested the upper bounds of this. Somewhere between 16K and 32K points updated every 100mS performance starts to degrade. So this is a vast improvement.

      C++ is a perfectly valid school of magic.

      1 Reply Last reply
      4
      • fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on last edited by
        #2

        It looks like their oscilloscope example may be the way to go. It updates 10K points at once and does not seem to be slow. I will adjust my code for their method of updating in C++ and see if its better.

        C++ is a perfectly valid school of magic.

        1 Reply Last reply
        0
        • fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on last edited by fcarney
          #3

          I restructured my data in qml to be linear point list and then updated via this function:

          class PointUpdater : public QObject
          {
              Q_OBJECT
          public:
              PointUpdater(QObject* parent=nullptr)
                  : QObject(parent)
              {
              }
          
          public slots:
              void update(QAbstractSeries *series, QVariantList points){
                  if(!series){
                      return;
                  }
                  QVector<QPointF> newpoints;
                  for(QVariant point: points){
                      auto list = point.toList();
                      newpoints.push_back(QPointF(list.at(0).toDouble(), list.at(1).toDouble()));
                  }
          
                  QXYSeries *xySeries = static_cast<QXYSeries *>(series);
                  xySeries->replace(newpoints);
              }
          };
          

          I took this from the scope example. It updates very fast.

          Edit:
          We tested the upper bounds of this. Somewhere between 16K and 32K points updated every 100mS performance starts to degrade. So this is a vast improvement.

          C++ is a perfectly valid school of magic.

          1 Reply Last reply
          4
          • GrecKoG Offline
            GrecKoG Offline
            GrecKo
            Qt Champions 2018
            wrote on last edited by
            #4

            I believe you would have even better performance with VXYModelMapper, and your C++ could stay decoupled from your charting code (no manipulation of your series in your model code).

            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