[Development] updating many QPersistentModelIndices

Milian Wolff milian.wolff at kdab.com
Wed Jun 3 18:56:05 CEST 2015


On Wednesday 03 June 2015 18:32:46 Milian Wolff wrote:
> Hey all,
> 
> for a customer I looked into the performance of a model/view application
> with many (and I mean, many!) add/remove/modify operations on a model with
> a QSortFilterProxyModel on top. The obvious solution to speed things up is
> batching, which works nicely paired with layout{AboutToBe,}Changed. So far
> so good, but the issue that was now reported comes when one now *also*
> wants to enable MultiSelection in the view, and the user "accidentally"
> presses CTRL + A to select all items in the view. This then completely
> kills the performance, due to bottlenecks inside QAbstractItemModel, all
> related to QPersistentModelIndex.
> 
> Some questions now from my side:

I forgot to mention: This targets Qt 4.7, but afaik all my findings below are 
equally valid to current Qt 5 code.

> a) Why is the hash of indexes in QAbstractItemModelPrivate::Persistent not
> unique - i.e. why is insertMulti required? I ask, b/c the "it + 1" operation
> in QAbstractItemModelPrivate::Persistent::insertMultiAtEnd is _extremely_
> slow for large lists of persistent model indices, due to the cache misses
> etc. pp. involved. The documentation says:
> 
>     "There should be only one instance QPersistentModelIndexData per index,
> but in some intermediate state there may be severals of PersistantModelIndex
> pointing to the same index, ..."
> 
> What intermediate state is that? When I look at the uses of this function,
> they always use the pattern
> 
> persistent.indexes.erase(...);
> ...
> persistent.insertMultiAtEnd(...);
> 
> I fail to see how/where this intermediate state can occur.

I just recompiled Qt with this patch applied:

diff --git a/src/corelib/kernel/qabstractitemmodel.cpp 
b/src/corelib/kernel/qabstractitemmodel.cpp
index 1eb709c..ec7006b 100644
--- a/src/corelib/kernel/qabstractitemmodel.cpp
+++ b/src/corelib/kernel/qabstractitemmodel.cpp
@@ -3464,8 +3464,10 @@ bool QAbstractListModel::dropMimeData(const QMimeData 
*data, Qt::DropAction acti
  */
 void QAbstractItemModelPrivate::Persistent::insertMultiAtEnd(const 
QModelIndex& key, QPersistentModelIndexData *data)
 {
+    Q_ASSERT(indexes.count(key) < 2);
     QHash<QModelIndex,QPersistentModelIndexData *>::iterator newIt =
-            indexes.insertMulti(key, data);
+            indexes.insert(key, data);
+    return;
     QHash<QModelIndex,QPersistentModelIndexData *>::iterator it = newIt + 1;
     while (it != indexes.end() && it.key() == key) {
         qSwap(*newIt,*it);

with a developer build, and assertions enabled, everything still works as 
expected (just much faster). I ran the following unit tests, all still pass, 
or behave just as without this patch: 

qabstractitemmodel
qabstractproxymodel
qsortfilterproxymodel
qtreeview
qlistview

My own test app also works without asserting. So again - why the multiHash - 
obsolete? If so, I'll push the required changes to Qt 4 and Qt 5 to remove 
QAbstractItemModelPrivate::Persistent::insertMultiAtEnd.

Bye
-- 
Milian Wolff | milian.wolff at kdab.com | Software Engineer
KDAB (Deutschland) GmbH&Co KG, a KDAB Group company
Tel: +49-30-521325470
KDAB - The Qt Experts



More information about the Development mailing list