Sharing (KIconEffects) is caring

This evening I made an optimization to KRatingPainter (a class in libnepomuk in kdelibs) that I just have to blog about. I was using the KRatingPainter class to paint one of those 5-star rating dealies onto the item delegate of a listview. When I maximized the window, scrolling this list view became very slow. I broke out callgrind for a debugging session and scrolled down the list using the arrow key whilst my other hand assisted me in eating a jelly doughnut whilst I waited for the (now considerably slower thanks to callgrind) view to scroll enough to get sufficient data from callgrind.

Looking at callgrind’s output, the culprit was obvious. The paint() function of KRatingPainter was 20% of all computing time that had been spent during the program’s run. More specifically, the KIconEffect constructions going on in paint() were the culprit.

So I delved into the source to figure out why so many KIconEffects were being constructed during paint(). It turned out that KRatingPainter was using the KIconEffect class to apply enabled/disabled/hover effects to the stars it painted, but was creating a new KIconEffect each time it wanted to paint(). It ended up creating 2 KIconEffect objects every time paint() was called. KIconEffects are quite expensive to construct, as they have to read configuration files each time they are made. (The above picture illustrates the expensiveness nicely.)

But, as it turns out, KIconLoader provides a shared KIconEffect object that all KDE apps can use (unless they want a custom one for some reason). Using a pointer to this shared KIconEffect object rather than creating 2 per paint resulted in a speedup of near 500x.

Whereas before KRatingPainter had consumed 20% of all computing time spent, the second time around KRatingPainter painting took only 0.04% of all computing; meaning that, if it wanted too, it could have done 500 times more paints in the same amount of time it took to paint the first time around. Notice too from the picture that KIconEffect::KIconEffect (the constructor) was only called once after the fix, whereas it was called 400-something times without the fix. So take this as a lesson: always use the shared KIconEffect unless it is absolutely necessary not to.

This was just to epic a win not to blog about.😛

8 Responses to Sharing (KIconEffects) is caring

  1. Vivek says:

    Thanks for the blog post and your excellent work.

    I’m wondering how we can leverage general users’ observations on such things into bug reports. I know that I’ve noticed slowdowns sometimes, but I’ve never done anything about it – and I don’t have the technical expertise to identify the issues like you did. So maybe a clear explanation on how to report bugs about slowdowns (including pasting in a log from callgrind or other tools, for example) would be really useful. Just an idea..

  2. TheBlackCat says:

    Great to hear! Is this fix going to make it into 4.5.1 or 4.5.2 or not until later?

  3. Matt says:

    Nitpick: it’s more like 625 times faster, since the .04% you measured is from much less total time as well.

  4. arwa says:

    A slow scrolling of a listview reminds me of the “all effects” list in the system settings. There are no stars in this list. But maybe there is a similar issue there?

  5. …which reminds me to use Callgrind more often.

    Good work, thanks🙂

  6. […] KRatingPainter optimizations Following the optimization I made last night to KRatingPainter’s paint function, (KRatingPainter is what paints those […]

  7. […] triggered by Jonathan’s blog post (and the followup) on speeding up KRatingPointer via finding bottlenecks through callgrind I did […]

  8. […] (As a note for regular readers of my blog, the Muon Software Center is what prompted me to do my KRatingPainter optimizations. Scrolling the applications list was seriously slow before them. It’s nice and […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: