Solved QStandardItemModel+QTableView get pool performance after 5.9.3
-
Hi,
I found that my app got pool performance after using qt5.9.4 and above.
My App uses QStandardItemModel+QTableView to show about 1M rows and each has 5 columns.
When using 5.9.3, I try add rows as quick as possilbe(about 20k rows/s),and the UI is responsible. CPU is not 100% yet.
But from 5.9.4, (I have tried many versions including 5.11.x 5.12.x 5.13.x, in fact), GUI stuck quickly even when I add rows below 2k/s. CPU usage reach 100% for a long time.Does anyone know something about this? I know my problem is not clear, but just want to try my luck.
-
After some research myself, I think I got the root cause.
Below is linux perf profile result
Difference begins from QHeaderViewPrivate::_q_layoutChanged().
Qt5.9.3 doesn't call QHeaderView::initializeSections(), but 5.9.4 and later versions call it, which cost a lot of CPU.
Here is the change
-
If you want performance, don't use convenience models like QStandardItemModel. This stuff is needed to make sure the hidden sections stay the same after an insert (which wasn't the case previously).
But you can try to create a small example so we can reproduce your problem. -
@Christian-Ehrlicher
OK. Here is the example. When I compile it with qt593, I can drag the scrollbar anytime. Higher version of Qt will stuck quickly.#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QThread> class QStandardItemModel; class AA : public QThread { Q_OBJECT signals: void add(); protected: void run(){ sleep(5); for(int i=0;i<1000000;i++){ emit add(); QThread::usleep(100); } } }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private: QStandardItemModel *model; }; #endif // MAINWINDOW_H
#include "mainwindow.h" #include <QTableView> #include <QStandardItemModel> #include <QThread> #include <QTimer> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { model = new QStandardItemModel(0, 5); int i = 0; model->setHorizontalHeaderItem(i++, new QStandardItem(QObject::tr("Col1"))); model->setHorizontalHeaderItem(i++, new QStandardItem(QObject::tr("Col2"))); model->setHorizontalHeaderItem(i++, new QStandardItem(QObject::tr("Col3"))); model->setHorizontalHeaderItem(i++, new QStandardItem(QObject::tr("Col4"))); model->setHorizontalHeaderItem(i++, new QStandardItem(QObject::tr("Col5"))); QTableView *view = new QTableView; setCentralWidget(view); view->setModel(model); AA *aa = new AA; connect(aa, &AA::add, this, [=]{ int row = model->rowCount(); int i = 0; model->setItem(row, i++, new QStandardItem("AAA")); model->setItem(row, i++, new QStandardItem("BBB")); model->setItem(row, i++, new QStandardItem("CCC")); model->setItem(row, i++, new QStandardItem("DDD")); model->setItem(row, i++, new QStandardItem("EEE")); }); aa->start(); } MainWindow::~MainWindow() { }
-
Thx for the reproducer - but I strongly suggest to use a custom model instead QStandardItemModel - it's slow by design since for example every setItem() call triggers an update to the view which is way to much (and unneeded when a correct model is used)
-
There were some changes in QHeaderViewPrivate::_q_sectionsChanged() (previously _q_layoutChanged) in 5.11. Maybe it helps you.
I tested you stuff with a simple custom model and it really speeds up the stuff. Remove QThread::usleep() and got the following times:
Custom Model:real 0m5,352s user 0m0,373s sys 0m0,091s
QStandardItemModel:
real 0m59,377s user 0m54,159s sys 0m0,298s
Dummy testcode
int TableModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : m_rowCount; } int TableModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : 5; } QVariant TableModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole || !index.isValid()) return QVariant(); switch (index.column()) { case 0: return QStringLiteral("AAA"); case 1: return QStringLiteral("BBB"); case 2: return QStringLiteral("CCC"); case 3: return QStringLiteral("DDD"); case 4: return QStringLiteral("EEE"); } return QVariant(); } void TableModel::addRow() { beginInsertRows(QModelIndex(), m_rowCount, m_rowCount); ++m_rowCount; endInsertRows(); }
-
@Christian-Ehrlicher
OK. I will try to use custom model if this is not a bug.
Thanks a lot! -
@Mr-Pang said in QStandardItemModel+QTableView get pool performance after 5.9.3:
if this is not a bug.
It's maybe a speed regression and maybe you should file a bug report about this (with your testcase) - maybe someone finds a better solution for the problems which introduced this regression.
-
I found the real problem finally. I use model->setItem() to append new row. The correct way is model->appendRow().
QStandardItemModel works well now. -
See also https://bugreports.qt.io/browse/QTBUG-18539 for more information about this problem.