Skip to content

Commit

Permalink
QSortFilterProxyModel: port to PMF connects for performance reasons
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dfaure-kdab committed Feb 2, 2023
1 parent ad42833 commit c609b8d
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 108 deletions.
134 changes: 48 additions & 86 deletions src/corelib/itemmodels/qsortfilterproxymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ struct QRowsRemoval

class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
{
public:
Q_DECLARE_PUBLIC(QSortFilterProxyModel)

public:
enum class Direction {
Rows = 1,
Columns = 2,
Expand Down Expand Up @@ -238,6 +238,8 @@ class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
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(
Expand Down Expand Up @@ -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);
}

/*!
Expand All @@ -2031,114 +2035,72 @@ 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();
d->_q_clearMapping();

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();
Expand Down
22 changes: 0 additions & 22 deletions src/corelib/itemmodels/qsortfilterproxymodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,28 +172,6 @@ public Q_SLOTS:
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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"

0 comments on commit c609b8d

Please sign in to comment.