A faster Paint Bucket in Inkscape means that I make my comics faster, which means I can finish “Candynomics” before I turn 30. The first version of Paint Bucket was pretty much just a proof-of-concept, and was very slow (but faster than the alternative of coloring using the Pen tool, which drove me batty). The second version got a little more clever at analyzing the area to be painted, which brought out a modest speed improvement. For the most recent change, which involved hooking deeper into the potrace bitmap tracing engine, I used Valgrind and KCachegrind to analyze all the steps of a fill operation and to find any potential bottlenecks.
Inkscape uses libgc to handle garbage collection, which is a good thing, except for when you want to profile Inkscape using Valgrind. Valgrind and libgc don’t get along too well, but luckily you can disable the use of libgc in Inkscape with an environment variable.
Additionally, profiling all of Inkscape in Valgrind, and more specifically callgrind, is an excruciating process. Valgrind allows you to disable instrumentation — the gathering of function call statistics, a very slow operation — at the start of the application’s execution, and then turn instrumentation on later in the life of the application, say when you’re about to paint an area of the drawing.
To profile a development build of Inkscape with Valgrind, with instrumentation disabled by default, cd to your build directory and execute the following from a bash shell:
_INKSCAPE_GC=disable valgrind --tool=callgrind --instr-atstart=no src/inkscape
Inkscape will start up…very, very slowly. When you’re ready to profile, run in another shell:
callgrind_control -i on
And callgrind will start recording function calls. Perform the operations you want to profile (the more the better if your machine is fast enough — I performed about 3-4 bucket fills in my testing, which was enough for this purpose), then in your second shell:
callgrind_control -i off
You can kill the valgrind process with [Ctrl]-C once callgrind_control reports that instrumentation is off.
When you’re done profiling, you’ll get a callgrind.out file in the build directory, with a number at the end that is the PID of the valgrind/inkscape process. Move this file somewhere else (I like ~/Desktop) and fire up KCachegrind.
I’ve done a lot of profiling of PHP applications (using Xdebug, a very very useful PHP extension), but essentially nothing of desktop applications. Luckily, the same general process applies to desktop apps:
- Sort functions by number of calls. See if any function is being called more than it should be.
- Sort functions by call time. See if any function is taking a very very long time.
- Check the call graph of the bigger functions. Look for anything suspicious.
- Tackle the biggest offenders first. Don’t waste time squeezing an extra 1% out of the app if it takes you 20 hours to get it (unless you really want to
)
In my case, #3 was what tipped me off to what was going on: after calling Inkscape’s potrace engine to trace the fill bitmap, the engine was calling a function called filter() which seemed to be taking a while to execute. I took a look at what was going on, and saw that filter() was generating a grayscale version of the bitmap fill to be traced, and then passing this along to the tracing engine.
The filter that was being applied was geared more toward generic image filtering, where the input could be anything. My input from Paint Bucket is quite specific, so I decided to try an end-run around the filtering system. After about 20 minutes of refactoring and new coding, I re-ran Inkscape in Valgrind, did some fills, and after comparing the costs of the removed filter function and the new costs of my own filtering, the process was faster!
So in conclusion: if you have spots in your code that are CPU-intensive, or just plain slow, running them through a profiler like Valgrind (or for PHP, Xdebug) can help you determine if it’s a problem in your code and where that problem may be.