So – obviously we shouldn’t be grabbing properties out of value trees on every callback – but occasionally I need to check a property or two here or there. Most of the time I make an identifier to speed it up, but just found something quite cryptic.
I had some hard to track down random CPU spikes in my app, after digging for awhile I found it was due to:
This appears to sometimes occur from my audio thread if it’s the place that grabs a fresh value from the tree. (sometimes I need to get a value from somewhere else in the app and I don’t have a cached value or identifier for it)
So – not much an issue but, wouldn’t it make sense for JUCE to always defer this garbage collection to the message thread out of the box? I.E. – could we wrap this entire thing in a && isMessageThread()?
Seems it would reduce the chance of undesirable behavior quite a bit.
I think this implementation is fine, because ValueTrees were never designed to be used from a realtime thread. I think of them as explicitly “message thread objects”.
What do you do for stuff which doesn’t have any automagical binding you always setup a cached value?
I agree they typically are, but I still don’t think they should
construct an identifier →
perform garbage collection in a non deterministic way.
Well, it’s kind of a QoL feature from JUCE, that strings and identifiers are managed safe and fast. It’s just not designed to be used for real-time or for processor-close code.
I feel like you’ll have to make the message thread push updates into your real-time accessible cache to make sure you know what is going on.
It’s very easy with the Snapshot Source from Palmer Hogan shown at ADC23
It’s not a critical issue for me it’s solved now, but I think everyone on this forum would have a lot of money if they got a dollar for every time a new user posted code they need help with that used a valuetree in the RT thread.
We’re all sitting here saying, “this should be on the message thread” and agreeing, yet I myself after many years working with JUCE, wasn’t aware of this. I just thought they were slow.
So people will do it have no idea why they’re getting CPU spikes, and for beginners it’s not a few hours to find it’s probably months or maybe never. Just some feedback!
How are you creating your identifier? If you make them const static they shouldn’t affect the StringPool as they’re passed to the ValueTree functions by reference.
Yeah – I swapped the area I found the issue with const identifiers and it solved the problem.
My concern is just that’s it’s quite a large codebase, and I often have students and less senior engineers working with me, and it’s a pretty easy / harmless mistake to make.
It might just edit our instance of JUCE to only call the garbage collection if it’s the message thread.
Yes, for situations like that I just have a listener that listens to changes and stores the value in an atomic.
Non-atomic values (arrays, etc) would have race conditions if you’re trying to read them in the RT thread anyway, so you need a better way to pass the values down the processor following changes, using a FIFO, a SpinLock, etc.