Following the optimization I made last night to KRatingPainter’s paint function, (KRatingPainter is what paints those nice little rating stars in Dolphin, Gwenview, and some Muon-related project that I’m not quite ready to receive UI criticism for :P) I discovered that there were also a suspicious amount of KColorScheme-related calls coming from somewhere. Since KCacheGrind is such a lovely tool, I was able to deduce quickly that these were coming from the KIconEffect::apply() calls that KRatingPainter::paint() was calling.
There are several ways to call KIconEffect::apply(). (See http://api.kde.org/4.x-api/kdelibs-apidocs/kdeui/html/classKIconEffect.html) They all differ in what parameters you supply to the function. Some are more efficient than others. In our case, KRatingPainter was using the following apply() function:
QPixmap apply (const QImage &src, int effect, float value, const QColor &rgb, bool trans) const
This function takes your picture, the effect you want the strength of your effect, a color to use should the effect support a separate color, and a boolean value to determine whether or not to apply transparency. This is actually a convenience function, since icon effects that require colors require two different colors in some cases. In these cases KIconEffect uses KColorScheme to determine what the best color to use in these cases would be.
The effect in use by KRatingPainter, the “to gray” effect, does not require any additional colors to be specified at all, so by using the wrong apply() function KRatingPainter was spending time finding a color that would never be used. I remedied this by using this overload of the apply() function:
QPixmap apply (const QPixmap &src, int effect, float value, const QColor &rgb, const QColor &rgb2, bool trans) const
This one makes you specify two colors, so time is not wasted looking in your color scheme configuration to determine the best color. I just specified two colorless colors (null QColor()’s, to be technical) and everything was fine and dandy from there on out. It sped up KRatingPainter at least another 10x, on top of the 500x gained from last night’s optimization. In my delegate’s case, this optimization cut the time my ItemView delegate spent painting in half. (A bit more, actually, though data for my delegate specifically is not included in the below screenshot.)
I am fairly sure that rating painting is no longer a bottleneck in my ModelView Delegate class anymore. Compared to last night, I can make it much bigger before seeing noticeable losses of scrolling fluidity. It should be really fast now, and other applications should be able to benefit from these changes in KDE 4.6 as well.
So, in conclusion, valgrind/callgrind and KCacheGrind (valgrind/callgrind file viewer) are invaluable tools, and are a must-have for any KDE developer. This is by no means the first time that they’ve helped me discover bottlenecks, but this is one of the more drastic optimizations that they have helped me find.