QSortFilterProxyModel: port to PMF connects for performance reasons

BEFORE:
   0.21 msecs per iteration (total: 56, iterations: 256)
   801,946 CPU cycles per iteration (total: 801,946, iterations: 1)

AFTER:
   0.084 msecs per iteration (total: 87, iterations: 1024)
   300,259 CPU cycles per iteration (total: 300,259, iterations: 1)

Change-Id: I5b2703c217bb25e18f1d9f6a1eda19c60e1edcb0
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
David Faure 2023-01-26 14:42:26 +01:00
parent ad42833d33
commit c609b8dba0
3 changed files with 62 additions and 108 deletions

View File

@ -109,9 +109,9 @@ private:
class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
{
public:
Q_DECLARE_PUBLIC(QSortFilterProxyModel)
public:
enum class Direction {
Rows = 1,
Columns = 2,
@ -238,6 +238,8 @@ public:
QModelIndexPairList saved_persistent_indexes;
QList<QPersistentModelIndex> saved_layoutChange_parents;
std::array<QMetaObject::Connection, 18> sourceConnections;
QHash<QModelIndex, Mapping *>::const_iterator create_mapping(
const QModelIndex &source_parent) const;
QHash<QModelIndex, Mapping *>::const_iterator create_mapping_recursive(
@ -2006,7 +2008,9 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
: QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
{
connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
Q_D(QSortFilterProxyModel);
QObjectPrivate::connect(this, &QSortFilterProxyModel::modelReset, d,
&QSortFilterProxyModelPrivate::_q_clearMapping);
}
/*!
@ -2031,56 +2035,10 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
beginResetModel();
disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)),
this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QList<int>)));
disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
if (d->model) {
for (const QMetaObject::Connection &connection : std::as_const(d->sourceConnections))
disconnect(connection);
}
// same as in _q_sourceReset()
d->invalidatePersistentIndexes();
@ -2088,57 +2046,61 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
QAbstractProxyModel::setSourceModel(sourceModel);
connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)),
this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QList<int>)));
d->sourceConnections = std::array<QMetaObject::Connection, 18>{
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::dataChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceDataChanged),
connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::headerDataChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged),
connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsAboutToBeInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted),
connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsInserted),
connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsAboutToBeInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted),
connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsInserted),
connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsAboutToBeRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved),
connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsRemoved),
connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsAboutToBeRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved),
connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved),
connect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsAboutToBeMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved),
connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsMoved),
connect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsAboutToBeMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved),
connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsMoved),
connect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::layoutAboutToBeChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged),
connect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::layoutChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceLayoutChanged),
connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::modelAboutToBeReset, d,
&QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset),
QObjectPrivate::connect(d->model, &QSortFilterProxyModel::modelReset, d,
&QSortFilterProxyModelPrivate::_q_sourceReset)
};
endResetModel();
if (d->update_source_sort_column() && d->dynamic_sortfilter)
d->sort();

View File

@ -172,28 +172,6 @@ Q_SIGNALS:
private:
Q_DECLARE_PRIVATE(QSortFilterProxyModel)
Q_DISABLE_COPY(QSortFilterProxyModel)
Q_PRIVATE_SLOT(d_func(),
void _q_sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right,
const QList<int> &roles))
Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceAboutToBeReset())
Q_PRIVATE_SLOT(d_func(), void _q_sourceReset())
Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))
Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(const QModelIndex &source_parent, int start, int end))
Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int))
Q_PRIVATE_SLOT(d_func(), void _q_clearMapping())
};
QT_END_NAMESPACE

View File

@ -31,6 +31,7 @@ class tst_QSortFilterProxyModel : public QObject
private slots:
void clearFilter_data();
void clearFilter();
void setSourceModel();
private:
QStringList m_numberList; ///< Cache the strings for efficiency.
@ -93,6 +94,19 @@ void tst_QSortFilterProxyModel::clearFilter()
QCOMPARE(proxy.rowCount(), itemCount);
}
void tst_QSortFilterProxyModel::setSourceModel()
{
QStringListModel model1;
QStringListModel model2;
QSortFilterProxyModel proxy;
QBENCHMARK {
proxy.setSourceModel(&model1);
proxy.setSourceModel(&model2);
}
}
QTEST_MAIN(tst_QSortFilterProxyModel)
#include "tst_bench_qsortfilterproxymodel.moc"