Plugin editor window slow to open (since JUCE 6.1 possibly?)

I could be totally wrong here… but couldn’t figure this out after a lengthy dig - just confused - I hope somebody can point me in the right direction.

I’ve noticed (but I do need to go back and rebuild against JUCE 6.07 to confirm it though), that my plugin editor window appears to take much longer to open (either AU/VST3 or standalone) recently. It takes over 1 second… but on profiling my code, the code which actually creates the new instance of my editor only takes something like a couple of milliseconds… I verified this by creating and deleting my editor within the ‘createEditor’ function multiple times (and profiling in both standalone and AU inside Ableton)… there’s a lot of dead time in that function where it appears something else with higher priority is blocking the UI thread during ‘createEditor’? (But I don’t think it’s audio processing as I’m testing with an empty patch which does almost no audio processing other than return an empty buffer and profiling the processBlock shows that it is shortly entered/exited.)
‘createEditor’ call happens after state restore… so it’s not any state restore stuff that’s holding things up… nor any background process I have since those are lower priority than the UI thread.
(edit… should add - I am currently testing on Mac OS 11.5.2, building in XCode 12.5)

(Note the text labels should read ‘new HyprSynthPluginAudioProcessorEditor’ - sorry for any confusion in the image)

The trace above is taken after a couple of times open and close the editor window…so well after the plugin is initially loaded in the DAW.

(I have a custom ‘function scoped’ profiling function that is also called in HyprSynthPluginAudioProcessorEditor constructor.)

AudioProcessorEditor* HyprSynthPluginAudioProcessor::createEditor()
{
    UI_PROFILE_FUNCTION();

#if 0 //def _DEBUG
	String paintString = "HyprSynthPluginAudioProcessor::createEditor()";
	DBG(paintString);
#endif
    
    HyprSynthPluginAudioProcessorEditor* ed = nullptr;
    
#ifdef _DEBUG // just testing long it takes...
    ed =  new HyprSynthPluginAudioProcessorEditor (*this, synthUImaster, globallooknfeel);
    
    delete ed;
    
    ed =  new HyprSynthPluginAudioProcessorEditor (*this, synthUImaster, globallooknfeel);
    
    delete ed;
    
#endif
    
     ed =  new HyprSynthPluginAudioProcessorEditor (*this, synthUImaster, globallooknfeel);
   
    return ed;
}

FYI - I just downgraded my JUCE source from 6.1.1 to 6.0.7 and now my plugin editor window (Hyperion) opens without any delay (testing in live 10 on Mac M1 Air - building in Xcode 12.5.1) - building from my latest plugin release source code (v1.12), and only changing the JUCE modules. (Small disclaimer - both these versions of JUCE are taken from official releases, but with some minor changes to the JUCE button and oversampling class - in each case, same code changes in both source sets.)

Secondly, an end user reported Mac M1 version of my latest build (built on 6.1.1) was showing double the CPU load as my prior release build (I confirmed it, but also confirmed this was not observed in the Intel Mac build of the same version - also built in Xcode 12.5.1) ;
I have just retested on Mac M1 rebuilding (release mode build) my current release/latest codebase, but with downgrade from JUCE 6.1.1 to 6.0.7, and the CPU load (actually the spare time between audio callbacks) has returned to normal (audio processing load dropping by 50%).

I don’t have any evidence as to what is causing these issues - it’s just my observation.

I will test rebuilding against JUCE 6.0.7 on my Intel based Mac mini now, to confirm if the editor window launch delay goes away in that case too.

To get to the bottom of what‘s slowing down your plugin, why not profile it? Usually, this gives you some good insight where in your code most of the time is spent.

As a quick guess: Do you use OpenGL? There was some restructuring about which gl functions are loaded after users reported that loading all available extensions at startup can take pretty long. Can’t find the relevant forum topic anymore though…

Firstly, thanks for responding.

I’m not using Open GL, only standard JUCE drawing/widgets, and yes, I am profiling but was using my own profiling functions to check things like how long the audio callback takes to process, how long it takes to restore the plugin state, and how long it takes to open the editor.
(I’m using Perfetto as a visualizer)

I’ve just rebuilt the Intel version of my plugin - again, same code base, but downgrade JUCE to 6.07 from 6.1.1 and I’m measuring the time it takes for ‘createEditor’ to complete is around 1/10th of before (and still the function itself is taking much longer than the constructor of my editor which is then returned).
(createEditor call was taking just over 1 second, now after downgrade to 6.07 about 110ms, and the constructor of my editor window that is returned takes 1.5 ms)

I may well have to use the Xcode or Visual studio profiler tools to look more closely at what could be delaying the ‘createEditor’ virtual function - it must be a higher priority thread.
I’m just wondering if there is anything that has changed since 6.07 to 6.1.1 that might cause the editor window to open more slowly.

I’m grateful for any tips on how to debug this (originally about the editor window open time), but in the immediate case I need to fix the issues for end users, so will make a new release reverting to 6.07.

For the issue of audio processing time/load on M1 with JUCE 6.1.1 vs 6.0.7 more profiling will be done, and maybe I’ll open a separate discussion thread.

Hi Wavesequencer,

do you maybe have a TreeView in your plugin with lots of nodes?
Because we noticed that the TreeView in JUCE 6.1.2 has gotten much slower, compared to JUCE 6.0.7. (Still debugging what is going on, therefore I have not yet opened a separat thread for that). In our case we have a TreeView with hundreds of nodes. With JUCE 6.0.7 that view is displayed in a fraction of a second. But in JUCE 6.1.2 it can take several seconds to show up.
As said, I am still debugging what’s going on there. Might well be an error on our end. And maybe you do not even have a TreeView. But just mentioning it, in case.

Hello @alatar
No, I am not using TreeView - regardless, all of the state restore of my node processing tree happens in the processor init (which only happens once when you load your plugin), and not when opening the editor window every time, and secondly, all of the GUI instantiation code that happens when I create an instance of a editor within the ‘createEditor’ virtual function happens in a very short space of time (1ms or so) regardless of which version of JUCE I am using… what seems to be happening is the the ‘createEditor’ call gets stalled by some other higher priority thread - so that it will only return my editor instance much later (1 second when compiled with JUCE 6.1.1).
I will have to profile more deeply of course, but at first it looks like this is nothing to do with any of my plugin code implementation since I see a big performance difference (in both editor window open time (Windows or Mac builds) and Mac M1 processing time) simply by switching out the JUCE modules code (doing a clean re-build in both cases of testing each JUCE version).

We have also observed graphics performance issues using 6.1.1. I’m wondering if it’s somehow related to the accessibility changes? We’re reverting back to 6.0.7 for now.

Quick coffee break test as I have to return to the day job… but here’s a couple of screenshots of my own profiler with a launch of the standalone build of my plugin:
Juce 6.07 - editorCreate time is 260ms, with 33ms for instantiation of my editor instance within it.
Juce 6.1.1 - editorCreate time is 1second, 368ms, with 33ms for instantiation of my editor instance within it (ie. same time to instantiate the actual GUI elements)
When running as a VST3 plugin, editor open times are faster in general since the audio processor gets instantiated ahead of time (and any task associated with that are completed already) - especially on 2nd and consequent editor opens (since processor doesn’t get instantiated each time).

(The second line/thread of ticks in the profile view is the audio callback)

6.0.7:

6.1.1:


6.1.1:

FYI… the green lines that appear under the audio thread ticks are my UI oscilloscope function… which only gets called with buffer data once the UI is loaded of course.

(edit: there is nothing conclusive about these traces of course, since I don’t see every thread/process
here - I will need to do a deeper/full trace using the Xcode/VS profilers)

Interesting.
Let us know what you find!

Did you try git-bisect ? Maybe it’s just one very specific change which causes this performance issue.

1 Like

How are you measuring the time inside the constructor of HyprSynthPluginAudioProcessorEditor? If you’re just logging the time inside the constructor body, you won’t get an accurate result because it won’t include the time taken to initialise the editor’s data members (including those in base classes).

Here, when I build the DSPModulePluginDemo Standalone from develop in a profiler, createEditor is sampled 4 times (it’s quite quick!). Building from 6.0.7, createEditor is sampled 5 times. There doesn’t seem to be any appreciable performance difference in this particular demo.

As the DSPModulePluginDemo editor is similarly fast to open on develop and 6.0.7, I suspect that any slowdown you’re seeing is due to a performance regression in a particular component that is used in your plugin. I recommend measuring in a sampling profiler to find out where the slowdown is coming from. Once you’ve found the cause of the slowdown, we can attempt to verify the issue here, and then hopefully find a solution.

If you have time, running a git bisect would also provide some useful information. However, depending on the size of the “bad” commit this may not be enough information to pinpoint the problem. Therefore, I’d recommend time profiling as a first step.

1 Like

Thank you for the suggestions and responses.
I don’t have time to dig into this right now, but later in the week I will do some deeper investigation and report back (I admit I don’t even know what git bisect is… so some learning to do too).

Maybe this is of relevance?

Wow, I can’t believe two weeks have gone by already - sorry that I’ve been snowed under with personal and work stuff - no time to dig into this.
I can say that I am not using a tree-view, and whilst I do have a node tree system with potentially lots of child GUI components, it only gets instantiated/built when the plugin process instance is created, and not when the UI window is created/closed/re-opened - however since the elements are made visible/resized when the editor window is created, maybe that’s related to the delays seen.

I’ve been having this issue as well lately, to the point that even optimized release compiled builds would cause interrupts whenever the editor was opened and closed.

I did a high-accuracy performance profiling on the construction of my editor without running any of the audio related systems for improved accuracy.

I found that a lot of the issues for me were caused by the fact that I have a custom slider / textbox / label composite component that called functions in each of their constructors that involved doing sendLookAndFeelChange() callbacks; Things like setColour(), setSliderStyle(), and setLookAndFeel() took up an overwhelming majority of the CPU utilized during construction.

Looking deeper, I found that I’m calling createSystemTypefaceFor() repeatedly when I’m creating these composite components (two times for each knob, and a LOT of knobs) so that would be the fix for me.

I’d probably suggest a more scrutinous look towards the look and feel / typeface related systems within your components (and if you’re loading in components which are not initially visible remember to use addChildComponent() instead of addAndMakeVisible()) for a performance boost.

Thanks for adding your comment to this topic - I’ve just been so wrapped up in building out releases on JUCE 6.0.7 I didn’t get back to investigating this yet.
I do have a lot of custom look and feel stuff, mostly just called one time using setDefaultLookAndFeel in the editor constructor, and also did use defaultTypeface = Typeface::createSystemTypefaceFor = .... in that LookAndFeel_V4 object’s constructor.
Still strange that the initialization behavior would be so different between JUCE versions - I will certainly take a closer look as I now have a couple of weeks without any planned feature/bug fix updates to my plugin.

I found my plugin suddenly started taking >5 seconds to instantiate the editor. Turns out it was because I was adding a bunch of help text to a TextEditor during construction. Interestingly, setting the text on demand is quite quick…

1 Like

Sorry for lack of updates on my side, I really just didn’t get time to investigate this until now - life happens… time flies.
Update:
Updating from 6.0.7 to 6.1.4 - editor opening time seemed a bit quicker vs 6.1.1, but that might have been due to some code changes I made in terms of initialisation sequences, however, there was still a significant delay in opening the plugin editor (especially on Mac).
I don’t know for sure why the time for opening the editor was significantly worse after upgrade from 6.07 to 6.1.x but after some profiling I found that it may partially have been related to some text editor initialisations/reading text from a file (which I now moved to happen only at the point that particular text is required), and the lowest level ‘pin’ component of my node tree having a setLookAndFeel (which I removed by putting the necessary change into my global overrides/default look and feel) - saving a fraction of a second (still this doesn’t explain why these things take longer after moving to 6.1.x).

However, even after these tweaks the Mac build was still taking 2-3 seconds to open the plugin editor when built on 6.1.4 (comparing to 6.0.7 on same Mac/OS version) - even though exact same Windows source code build did not show that delay.

I tracked this down to my patch list/file scanning code which launches a DirectoryContentsList thread - two issues:
The isFileSuitable filter was opening the text files to check for suitability instead of just only checking the file extensions.

Edit: the Directory contents list thread-priority is less significant than I thought after a retest, but still I think has an impact:

Secondly, at least on the Mac build, the default thread priority of DirectoryContentsList thread seems too high… dropping it by calling setPriority(3) made a difference.

So, for me the biggest factor was DirectoryContentsList…(combination of reading files and thread priority) and it seems there’s a difference with Windows vs Mac here, and the priority would appear to be the same as the UI thread by default? (which is not what I want for a background folder scan)
Is it possible that DirectoryContentsList gets a lower priority by default in prior versions of JUCE?

I guess it depends on the DAW/host, but the plugin processor is usually being initialised for the first time when you first add the plugin and if the plugin window is opened automatically - any statically allocated objects you have/wavetable initialisations, restore state, prepare to play etc. happen before the editor is created - so it’s normal for opening time to take longer the first time.

However if the length of time for that is significantly longer since upgrading to 6.1.4 then I’d suggest you do what I did and profile the code more deeply with Xcode/Visual studio profilers and look at what consumes the most time in the startup sequence.

After profiling I found that text initialisations of TextEditor components can take a lot of time - not sure if that is a new issue or was always the case, but I didn’t dig much deeper than moving the worst one out of the plugin editor constructor (reading in a multi-line string from binary data) - and now making it happen only when the component visibility was changed.

In your case it sounds like it’s not your UI/editor initialisation that is the cause of the delay. Maybe also have a look at any breaking changes in the release notes of 6.1.x vs older releases.

For my case, I don’t really know the underlying architecture of how JUCE requests threads/priorities from the OS and didn’t try to dig deeper, but I’m just making an educated guess that something changed for Mac builds between 6.0.7 and 6.1.1 which meant I needed to force a priority drop on the Directory contents list timeslice thread to avoid slowing down UI intialisation (and the reason it was so noticeable was because I was opening every text file in my filter function - if I didn’t do that, the difference is not so much).

Thank you for your suggestions. We strived to profiled our plugins and found the culprit, the editor lagging problem is solved.