Valgrind is a nifty too to do code instrumentation - tell you how
much time gets spent in different parts of your code tree.
KCachegrind is a visualisation tool for valgrind outputs. They are
two separate tools that together can provide useful insight into where
you code is slow or doing too much work. To set them up on ubuntu is
simple:
sudo apt-get install kcachegrind valgrind
After installation, you can lauch QGIS under valgrind like this:
cd /tmp
valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes \
--collect-jumps=yes /usr/local/bin/qgis
Note that everything you do in QGIS will take 10x longer because of the
overhead valgrind places on it. Now load up a project or do something
that you feel is taking longer that it should in QGIS. Then exit QGIS.
You will be left with a nice big unintelligible xml file in your /tmp
directory. Not to worry though, kcachegrind can open it an make sense of
it for you. The file will be called something like:
callgrind.out.18364
So to open it with kcachegrind you can simply do:
kcachegrind callgrind.out.18364
KCacheGrind will take a few moments to digest it and then show you
something like the screenshot below:
The callgraph can be displayed in a number of different ways and
provides extremely useful information if you are trying to identify
bottlenecks. In the image above, you can see that when QGIS starts,
almost 50% of startup time is spent loading python plugins. There are
also views that show how many times a given function is called which can
provide some helpful hints as to what to optimise.
Valgrind can also be used to detect memory leaks, but unfortunately for
GUI lovers, there isn't a nice GUI environment to explore the leak
report data. Don't let that put you off though - you can get extremely
useful feedback from the tool. Here is the syntax to do a leak check on
QGIS:
valgrind --tool=memcheck -v --error-limit=no --leak-check=full /usr/local/bin/qgis
When it finishes running QGIS you will get an extremely verbose report
(printed to stdout) that lists all the potential issues. Here is a short
snippet of what you might see:
==3144== 627 errors in context 151 of 997:
==3144== Invalid read of size 1
==3144== at 0x4C2A06A: __GI_strcmp (mc_replace_strmem.c:540)
==3144== by 0xA3080BA: _nl_load_locale_from_archive (loadarchive.c:161)
==3144== by 0xA30750D: _nl_find_locale (findlocale.c:107)
==3144== by 0xA306B38: setlocale (setlocale.c:379)
==3144== by 0x680F13F: QgsCoordinateReferenceSystem::setProj4String(QString) (qgscoordinatereferencesystem.cpp:753)
==3144== by 0x680C262: QgsCoordinateReferenceSystem::loadFromDb(QString, QString, QString) (qgscoordinatereferencesystem.cpp:271)
==3144== by 0x680B9B3: QgsCoordinateReferenceSystem::createFromSrsId(long) (qgscoordinatereferencesystem.cpp:213)
==3144== by 0x6776E2B: QgsDistanceArea::setSourceCrs(long) (qgsdistancearea.cpp:64)
==3144== by 0x6776CF9: QgsDistanceArea::QgsDistanceArea() (qgsdistancearea.cpp:45)
==3144== by 0x67C06DE: QgsMapRenderer::QgsMapRenderer() (qgsmaprenderer.cpp:46)
==3144== by 0x71B8D7B: QgsMapCanvas::QgsMapCanvas(QWidget*, char const*) (qgsmapcanvas.cpp:115)
==3144== by 0x5314EC: QgisApp::QgisApp(QSplashScreen*, bool, QWidget*, QFlags<Qt::WindowType>) (qgisapp.cpp:419)
==3144== Address 0x144ed1f1 is 1 bytes inside a block of size 12 free'd
==3144== at 0x4C282ED: free (vg_replace_malloc.c:366)
==3144== by 0xA306BC8: setlocale (setlocale.c:173)
==3144== by 0x680F0B0: QgsCoordinateReferenceSystem::setProj4String(QString) (qgscoordinatereferencesystem.cpp:743)
==3144== by 0x680C262: QgsCoordinateReferenceSystem::loadFromDb(QString, QString, QString) (qgscoordinatereferencesystem.cpp:271)
==3144== by 0x680B9B3: QgsCoordinateReferenceSystem::createFromSrsId(long) (qgscoordinatereferencesystem.cpp:213)
==3144== by 0x6776E2B: QgsDistanceArea::setSourceCrs(long) (qgsdistancearea.cpp:64)
==3144== by 0x6776CF9: QgsDistanceArea::QgsDistanceArea() (qgsdistancearea.cpp:45)
==3144== by 0x67C06DE: QgsMapRenderer::QgsMapRenderer() (qgsmaprenderer.cpp:46)
==3144== by 0x71B8D7B: QgsMapCanvas::QgsMapCanvas(QWidget*, char const*) (qgsmapcanvas.cpp:115)
==3144== by 0x5314EC: QgisApp::QgisApp(QSplashScreen*, bool, QWidget*, QFlags<Qt::WindowType>) (qgisapp.cpp:419)
==3144== by 0x52DFBE: main (main.cpp:607)
Just from starting QGIS and then immediately shutting it down, you will
see a rather large list of errors - some of which originate from QGIS
itself, and others which originate from some of the underlying libraries
we use. The leak detection tool is a hand way to debug when you are
getting application crashes and when it seems to be using more memory
than you think reasonable. One of these days lets hope that it returns a
big fat nothing when we run QGIS on it :-)