GUI changes via CachedValue / ValueTree causes high cpu load

I’m starting to use more ValueTree function to update the several components in a better way. As first component I refactored my thumbnail view. Basically it works but I realised a very high cpu load (over 200 % on XCode Debug Navigator) while I move the start / end marker. I’m not sure if I use the ValueTree / CachedValue technic in a prober way.

  1. Preparations
struct ThumbnailEditor    : public Component, public juce::ValueTree::Listener

juce::CachedValue<double> startMarkerPosition;
juce::CachedValue<double> endMarkerPosition;
  1. Grab a piece of ValueTree I want to change / listen
    void setSamplerSoundByValueTree(juce::ValueTree valueTree, int soundIndex)

        if( valueTree.getProperty(te::IDs::type).toString() == "sampler")
            int index = 0;
            juce::Array<juce::ValueTree> sounds;
            for(auto child : valueTree)
                if( child.getType() == te::IDs::SOUND )
            samplerSoundValueTree = sounds[soundIndex];
        startMarkerPosition.referTo (samplerSoundValueTree, te::IDs::startTime, nullptr);
        endMarkerPosition.referTo (samplerSoundValueTree, te::IDs::length, nullptr);

ValueTree as XML

          <SOUND source="Instruments/kick.ogg" name="kick" startTime="0.0" length="0.0"
                 keyNote="60" minNote="60" maxNote="60" gainDb="1.0" pan="0.0"/>
  1. Change the values through CachedValue
    void mouseDrag (const MouseEvent& e) override
        double positionInSeconds = jmax (0.0, xToTime ((float) e.x));

        if (abs(positionInSeconds - startMarkerPosition) < abs(positionInSeconds - endMarkerPosition))
            startMarkerPosition.setValue(positionInSeconds, nullptr);
            if(positionInSeconds > audioFile->getLength())
                endMarkerPosition.setValue(audioFile->getLength(), nullptr);
                endMarkerPosition.setValue(positionInSeconds, nullptr);
  1. Listen for changes and update
    void updateThumbnail()
        float markerThickness = 2.0f;
        startPositionMarker.setBounds ( timeToX(startMarkerPositionValue), 0, markerThickness, getHeight() );
        endPositionMarker.setBounds ( timeToX(endMarkerPositionValue) - markerThickness, 0, markerThickness, getHeight() );
    void valueTreePropertyChanged (ValueTree& v, const Identifier& i) override
        if (v == samplerSoundValueTree)
            if (i == te::IDs::startTime || i == te::IDs::length)

Maybe it isn’t a good idea to change the CachedValues with every mouse move. What’s the right way to have the benefits of ValueTree and good cpu loads?

1 Like

No, that should be fine, that’s what we do when the user scrolls Waveform left/right. It’s also in the Recording examples.

Are you running a release version before profiling?

Ok, that’s reassuring but I have similar cpu loads with a release version. I added a video. (1.2 MB)

Btw: How can I get the “real” cpu load value for the running app. This here doesn’t give me a realistic indicator.

auto& dm = engine.getDeviceManager();
cpuUsage.setText (String::formatted ("%d%% CPU", int (dm.getCpuUsage() * 100)), dontSendNotification);

That will tell you the percentage of an audio callback time slot used. Depending on the device though, glitches can occur anywhere from 65% to 100%. It really depends on the jitter and duration of any single callback.

To find UI performance you need to run a profiler to see where the cpu is being used.

On modern CPUs there isn’t “one” figure that can be relied upon. You really need to look at more practical indicators such as sluggish performance or very low frame rates.