Details
-
Bug
-
Resolution: Fixed
-
P2: Important
-
6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8
-
-
2f9c72028 (dev), ff3398199 (dev), 4304bab5d (dev)
Description
When QAbstractItemView dataChanged is called with topLeft != bottomRight and topLeft and bottomRight span a large number of indices, it is orders of magnitude slower in Qt6 than in Qt5.
This is because commit
8de62d34321cd827e60b0a7b6e7434070de301ae (https://codereview.qt-project.org/c/qt/qtbase/+/285280) attempted to address https://bugreports.qt.io/browse/QTBUG-58580 by determining the exact intersected rectangle of all the indices and only updating the viewport if one of the indices updated was visible.
However, if the number of changed indices is very large, then computing the intersected rectangle has much higher CPU cost than unconditionally updating the viewport and scales linearly. E.g., on a QTreeView with a QAbstractItemModel with 1.4 million rows, computing the intersected rectangle takes 1 second on a modern workstation. With 12 million rows, it takes over 9 seconds, during which time a CPU core is running at 100%. This is compare to 5-10 milliseconds to update with Qt 5.
In such cases, the Qt 5 performance can be achieved by forgoing dataChanged() and instead emitting layoutAboutToBeChanged() and layoutChanged() around the affected time.
While in smaller views, such as the one in QTBUG-58580 (200 rows, 50 columns) where nearly the entire model is visible at once, it gives better performance to only update the part of the viewport that view updated indices, it's not worth doing the calculations for large models.
Is the recommended practice in Qt6 to use layoutChanged for large changes instead of dataChanged()? If so, perhaps the documentation should be changed.