PyQt5 graph view "lazy loading" seems broken with graphopt
Created originally on Bitbucket by lothiraldan (Boris FELD)
I am debugging a performance issue on a pretty big repository (~525000 revisions). The repository is also quite branchy (+20000 heads). All the tests were made on a Mac Mini Sierra (10.12.6).
Opening the repository with thg 4.5 Qt4 (https://bitbucket.org/tortoisehg/files/downloads/TortoiseHg-4.5.0-mac-x64-qt4.dmg) takes between 6 to 8 seconds to load when I'm on tip and 12 to 14 seconds when I'm on revision 500000.
Opening the repository with thg 4.5 Qt5 (https://bitbucket.org/tortoisehg/files/downloads/TortoiseHg-4.5.0-mac-x64-qt4.dmg) takes forever when I'm on tip or not (more than 1 hour).
In both cases, the graphopt
option has been set.
I've tried to diagnosticate it with the showstack
extension and it seems that https://bitbucket.org/tortoisehg/thg/src/d0648f267bec60191f6fe323a69b8cfb404a7189/tortoisehg/hgqt/repomodel.py?at=default&fileviewer=file-view-default#repomodel.py-565 is called for each row in the Qt5 version but not in the Qt4 version.
I tried adding a traceback, but the traceback are not very helpful. I got two different tracebacks:
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 249, in _runcatch
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 340, in runcommand
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 391, in _runcommand
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 345, in checkargs
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 339, in <lambda>
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/qtapp.py", line 471, in __call__
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 261, in _initView
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 860, in _updateRepoViewForModel
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 667, in defaultIndex
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 586, in flags
and
File ".../TortoiseHg45qt4.app/Contents/Resources/__boot__.py", line 82, in _run
File ".../TortoiseHg45qt4.app/Contents/Resources/thg.py", line 116, in <module>
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 48, in dispatch
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 249, in _runcatch
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 340, in runcommand
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 391, in _runcommand
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 345, in checkargs
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 339, in <lambda>
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/qtapp.py", line 471, in __call__
File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 586, in flags
Both tracebacks seems to be missing the frames in PyQt.
I then tried to add a debug line:
diff --git a/tortoisehg/hgqt/repomodel.py b/tortoisehg/hgqt/repomodel.py
--- a/tortoisehg/hgqt/repomodel.py
+++ b/tortoisehg/hgqt/repomodel.py
@@ -567,6 +567,7 @@ class HgRepoListModel(QAbstractTableMode
if not index.isValid():
return flags
row = index.row()
+ print("Flags", row)
if row >= len(self.graph) and not self.repo.ui.debugflag:
# TODO: should not happen; internal data went wrong (issue #754)
return Qt.NoItemFlags
Running with this debug line on the Qt4 version output these lines:
('Flags', 25864) * 2 # The first line is repeated 2 times
('Flags', 25855) * 17 # This line is repeated 17 times
('Flags', 25856) * 17
('Flags', 25857) * 17
...
QPainter::begin: Paint device returned engine == 0, type: 2
QPainter::setCompositionMode: Painter not active
('Flags', 25855) * 3
('Flags', 25856) * 3
('Flags', 25857) * 3
('Flags', 25858) * 3
...
It generates ~300 lines of output but ends-up loading.
Running the Qt5 version is different. The traceback are similar (lines are different because I tried adding more or less lines in one version):
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 249, in _runcatch
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 340, in runcommand
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 391, in _runcommand
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 345, in checkargs
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 339, in <lambda>
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/qtapp.py", line 471, in __call__
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 261, in _initView
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 860, in _updateRepoViewForModel
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 663, in defaultIndex
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 582, in flags
and another one that is different:
File ".../TortoiseHg45qt5.app/Contents/Resources/__boot__.py", line 82, in _run
File ".../TortoiseHg45qt5.app/Contents/Resources/thg.py", line 116, in <module>
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 48, in dispatch
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 249, in _runcatch
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 340, in runcommand
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 391, in _runcommand
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 345, in checkargs
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/run.py", line 339, in <lambda>
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/qtapp.py", line 471, in __call__
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 261, in _initView
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 862, in _updateRepoViewForModel
File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 582, in flags
The output seems to show that it's trying to render every rows at launch:
('Flags', 0) * 2 # The first line is repeated 2 times
('Flags', 1) * 2 # This line is repeated 2 times
('Flags', 2) * 2
('Flags', 3) * 2
...
I tried diffing the Qt4 and Qt5 versions but nothing seems to explain this difference, could it be because of PyQt4 vs PyQt5?