PyQt5 graph view "lazy loading" seems broken with graphopt

Issue #5061 resolved
Boris FELD
created an issue

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?

Comments (10)

  1. Boris FELD reporter

    I've cleaned most of my debug statements and rerun both the qt4 and qt5 to see the first calls to flags, here are the first 5 calls to flags in the Qt4 version:

      File ".../TortoiseHg45qt4.app/Contents/Resources/__boot__.py", line 98, in <module>
      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/repowidget.py", line 261, in _initView
      File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 859, in _updateRepoViewForModel
      File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 652, in defaultIndex
      File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 25864)
      File ".../TortoiseHg45qt4.app/Contents/Resources/__boot__.py", line 98, in <module>
      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/repowidget.py", line 261, in _initView
      File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repowidget.py", line 861, in _updateRepoViewForModel
      File ".../TortoiseHg45qt4.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 25864)
      File ".../TortoiseHg45qt4.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 25855)
      File ".../TortoiseHg45qt4.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 25855)
      File ".../TortoiseHg45qt4.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 25855)
    

    And here are the first 5 calls to flags in the Qt5 version:

      File ".../TortoiseHg45qt5.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 859, in _updateRepoViewForModel
      File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 652, in defaultIndex
      File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 25864)
      File ".../TortoiseHg45qt5.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 861, in _updateRepoViewForModel
      File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 0)
      File ".../TortoiseHg45qt5.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 861, in _updateRepoViewForModel
      File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 0)
      File ".../TortoiseHg45qt5.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 861, in _updateRepoViewForModel
      File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 1)
      File ".../TortoiseHg45qt5.app/Contents/Resources/__boot__.py", line 98, in <module>
      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 861, in _updateRepoViewForModel
      File ".../TortoiseHg45qt5.app/Contents/Resources/lib/python2.7/tortoisehg/hgqt/repomodel.py", line 572, in flags
    --------------------------------------------------------------------------------
    ('Flags', 1)
    

    In both cases the local patch applied is the following:

    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,11 @@ class HgRepoListModel(QAbstractTableMode
             if not index.isValid():
                 return flags
             row = index.row()
    +        import traceback
    +        import sys
    +        traceback.print_stack(limit=15, file=sys.stderr)
    +        print("-"*80)
    +        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
    

    I tried printing the default index in repowidget._updateRepoViewForModel and in both the Qt4 and Qt5 version, it's 25864 and setCurrentIndex is called only once.

  2. Yuya Nishihara
    • changed status to open

    TLDR: graphopt.Graph has to simulate the small start of of graph.Graph so the initial rowCount() will never be huge.

    QTreeView scans items up to rowCount() at the initial layout. That was okay on Qt4 since no Python function wasn't called out. However, Qt5 introduced Qt::ItemNeverHasChildren flag for "optimization", and because of this, QTreeViewPrivate::hasVisibleChildren() starts invoking model.flags() per row, where C++/Python heavy lifting occurs.

    So, graphopt is painfully slow on Qt5.

  3. Boris FELD reporter

    What can be done about this issue with Qt5? Is there a plan or leads?

    I'm not an expert in Qt but I have big repositories I can test patches against. I'm also willing to write patches if needed but I would needs pointer where to start digging.

  4. Yuya Nishihara

    graphopt: do not build nodes just for flags() (fixes #5061)

    QTreeView scans items up to rowCount() at the initial layout. That was okay on Qt4, but on Qt5, model.flags(index) is invoked for each row because Qt5 has an "optimized" path to test if a row has children, which information is carried by flags().

    This patch adds a light-weight replacement for graph[row], so the graphopt does not have to build a complete node object until it is requested through model.data(index).

    Fixing graphopt.Graph.len() didn't go well since graphopt has to report a pseudo length so the scrolling of the model can be "optimized." That's the fundamental design of the graphopt.

    → <<cset 07157a0943be>>

  5. Yuya Nishihara

    repoview: switch to QTableView due to performance problem (refs #5061, #5066)

    This patch basically backs out the changeset 7b73fe6d0c17. The initialization of QTreeView is way slower than QTableView's especially on Qt5, because QTreeView scans all rows at the initial layout.

    This change means the HiDPI support is temporarily broken.

    → <<cset e17eb5e3aa44>>

  6. Log in to comment