Optimizing tips and tools for Krita

Hot Spots

  • thumbnails are recalculated a lot

  • the histogram docker calculates even when hidden

  • brush outline seems slow

  • the calculation of the mask for the autobrush is very slow and doesn’t cache anything

  • caching a whole row or column of tiles in the h/v line iterators should speed up things a lot

  • tile engine 1 has the BKL; tile engine 2 cannot swap yet and isn’t optimized yet

  • projection recomposition doesn’t take the visible area into account

  • pigment preloads all profiles (startup hit)

  • gradients are calculated on load, instead of being associated with a PNG preview image that is cheap to load

Tools

Valgrind

Tips

You can tell callgrind to focus only on the part of the code you want to optimize. This results in cleaner data. For example, you may want to only monitor the performance when drawing a stroke. Unless the thing you’re trying to optimize is the program startup, you can tell valgrind to run with the logging, or instrumentation, turned off at start:

valgrind --tool=callgrind --instr-atstart=no krita

Instrumentation can then be activated and deactivated with callgrind_control. To begin performance monitoring:

callgrind_control -i on

And then to end it:

callgrind_control -i off

I usually write a few aliases in my .bashrc (or .zshrc):

  1. alias callgrind="valgrind --tool=callgrind --instr-atstart=no"
  2. alias callgrind-on="callgrind_control --instr=on"
  3. alias callgrind-off="callgrind_control --instr=off"

Sysprof

mutrace

mutrace is a tool that count how much time is spend waiting for a mutex to unlock.

Easy optimization

As soon as you see slow code, try to have a look at the code to see if we aren’t creating a lot of unnecesserary objects, 90% of the time slow code is caused by this (the remain 10% are often caused by a lot of access to the tilesmanager, like with random accessor)

For instance:

Avoid:

  1. for(whatever)
  2. {
  3. QColor c;
  4. ...
  5. }

Do:

  1. QColor c;
  2. for(whatever)
  3. {
  4. }

It might seems insignificant, but really it’s not, on a loop of a milion of iterations, this is expensive as hell.

An other example:

Avoid:

  1. for(y = 0 to height)
  2. {
  3. KisHLineIterator it = dev->createHLineIterator(0, y, width);
  4. for(whatever)
  5. {
  6. ...
  7. }
  8. }

Do:

  1. KisHLineIterator it = dev->createHLineIterator(0, 0, width);
  2. for(y = 0 to height)
  3. {
  4. for(whatever)
  5. {
  6. ...
  7. }
  8. it.nextRow(); // or nextCol() if you are using a VLine iterator
  9. }

Vector instructions

Krita takes heavy advantage of the Vc library to speed up its brush strokes with CPU vector instructions. If you are planning to work with that library, it is worth reading through its documentation.

There are more general introductions to what vector instructions are for, and how they work here.

Profile guided optimization

Profile guided optimization is something else though. It is a special way of compiling and linking, that the compiler and linker use profiling information to know how best to optimize the code. So code that is used a lot is compiled with -O3 (the most optimizations), while code that is not used a lot gets -Os (to take less space), and so forth. This is a very useful technique that was not available on Linux until last year, and the news today is that Firefox now builds properly with it and there is a nice noticeable speed improvement for Linux users.

source:

https://linux.slashdot.org/comments.pl?sid=2117150&cid=35987784

wikipedia:

https://en.wikipedia.org/wiki/Profile-guided_optimization

  1. g++ -O3 -march=native -pg -fprofile-generate ...
  2. // run my program's benchmark
  3. g++ -O3 -march=native -fprofile-use ...
  • Design for Performance: great read about performance optimization (aimed at game developers, but many tricks apply for Krita).

  • TCMalloc: a malloc replacement which make faster allocation of objects by caching some reserved part of the memory.

  • Optmizing CPP: extensive manual on writing optimized code.