Component::findColour is slower than it needs to be

I was doing some profiling and I found that findColour uses a lot of CPU.

I made a test app that puts 1600 Components on the screen, each one calls findColour and then fills a rect. About 8% of the CPU in a release build goes to findColour. I don’t think this test is unrealistic, it’s about the equivalent of 320 Components that each use 5 colours.

The issue if the colour id gets converted to a string, then looked up in a NamedValueSet. If it’s not there, the parent gets checked, and the colour id gets converted to a string again. Assuming your component hierarchy is 15, that’s 15 strings built, allocated and deleted, just to be thrown away before getting looked up in the LookAndFeel.

My changes take the implementation from LookAndFeel and puts it in the component. This drops CPU usage of findColour to about 2%

My implementation is somewhat backwards compatible. I’ve maintained fetching colours from the NamedValueSet, but not setting. If getting / setting colours via getProperties() a supported API contract or just an implementation detail? Either way, I could remove it or make it work.

Here is my test app: GitHub - FigBug/PaintPerforamnce: JUCE PaintPerforamnce Testbed

Switch the juce repo between develop and feature/findColour to see the performance difference. My changes are here:

14 Likes

Totally agree. When I realized how colour ids are looked up, I immediately put an entry in my backlog to check whether switching to a std::map <int, juce::Colour> would make it faster.

In addition to the string manipulation, another point of inefficiency is the fact that NamedValueSet lookup is linear, whereas for colour ids you could make the storage sorted and make the lookup logarithmic.

Is SortedSet faster than std::unordered_set? Can’t think why having the colours sorted by their ID would make reading/writing faster?

SortedSet does a binary search vs unordered_set being a hash table. I’m guessing SortedSet would still be faster, since most components only have a few colours and it would be a little more cache friendly.