Why is this GUI so brutally slow to build and load?


#1

I’ve got my GUI interface to more or less the way I want it. It is all based on Flexbox, which I got started with via @daniel 's primer and Bruce Dawson has given me a lot of help as well.

This is just for my own purposes where the Flexbox design works beautifully. If I want to add a knob/button or change a group, it’s pretty easy and I don’t have to specifically re-lay anything out. So overall I really like the design.

But there is one major problem - it is brutally slow just to build or startup. Here for example is a very simple implementation in a “sandbox” kind of basic test/experiment synth (don’t expect it to sound good - it’s not intended to, it’s just for testing things):


This tiny version of the implementation with only 17 components and 4 groups takes 3.5 minutes to build on my i7 dual core laptop and 1.75 minutes to open as a standalone exe. While opening the standalone exe it is using ~50% CPU (likely one full core) and 2.1 GB RAM during these 1.75 minutes.

So there is obviously an insane amount of work it is doing trying to get this project loaded/running each time. In one of my actual synthesisers which I have now built, with somewhere between 60-100 knobs/buttons/etc, it now takes roughly over 10 minutes to build or open the synth. It has become insanely difficult to work with.

As noted in updates below, this only seems to be happening in Release Mode. In Debug mode, the GUI builds and runs quickly and easily.

In short, the way the system works is as follows:

  • Parameters are declared in UsedParameters.h and then defined PluginProcessor.cpp.
  • Functions which create groups of sliders/combo-boxes/buttons from these Parameters are defined in PluginEditor.h/cpp and the included file GUIElements.h.
  • The individual components (sliders/combo/buttons) are created in GUIElements.h using the LabeledComponent class, while groups are created using the LabeledGroup class.
  • Flexboxing is performed first in the LabeledGroup class where a FlexBox is placed around each individual component and group (knobBox & fb).
  • Flexboxing is finished in “PluginEditor.cpp” where each LabeledGroup is added to groupsBox and lastly parentBox to arrange finally on the screen.

So two levels of Flexboxing are required - one to FlexBox the LabeledComponents within the LabeledGroups, and a second one to FlexBox the LabeledGroups on the screen.

It is definitely working, but at a massive computational cost every time it must be built or started up in Release Mode.

Is there any possible solution? Is there any obvious error that has been made or could be corrected?

I would greatly appreciate any help as this GUI method is otherwise in the big sense exactly as I would like it to be. But currently, if I had 10 of these synths loaded as VSTs I would dread to think how long that project might take to start, even on my desktop.

Thanks


Why is this build lagging on "NumberToStringConverters"?
#2

Here with Windows 7 64 bit and Visual Studio 2017 (latest update) it builds as fast as a typical JUCE based project. (Initial build somewhat slow because it builds all the JUCE stuff, but not insanely long, maybe 20 seconds.) Starting/running it doesn’t take a particularly long time, only a few seconds, even under the debugger.

Making a release build takes quite a lot of time (close to a minute) but that’s probably because of the link time optimization, you could turn that off while developing. The release build starts to run almost instantly.

What operating system and compiler are you using?

You are dumping quite a lot of debug text output, maybe your particular system doesn’t like that?

Is there something I can easily change in the code to have more components to be added?


#3

My builds took a long time to even start, then I realised it was ‘Intellisense’ that was slowing things down, it all went back to normal after I ran CCleaner to clear any cache just one time months ago, and it’s been fine ever since. All a bit weird TBH, perhaps something else happened that I didn’t know about. It doesn’t explain your load times though. Try turning off any Anti-Virus checkers?
Perhaps use Profile sampling will show you where it’s spending its time.


#4

Hi Xenakios,

Thanks for your reply as always. I added another 20 knobs for testing:

I am on Windows 10 up to date using Visual Studio 15.8.2.

This is what my Task Manager looks like while the build is happening (ie. Debug > Start Debugging in Release Mode) and it hangs like this with massive utilization for between 0:45-1:30 minutes or so in this current version:

Currently it takes 1.5-3.5 minutes to build via Debug > Start Debugging in Release mode 0.5-1.5 minutes to run the exe on average after this.

Edit: See next post for better clarification of existing abnormal behavior, which seems to be resulting specifically from the GUI creation method used in Release Mode.


#5

I’ve done a bit more testing and I believe I can confirm the behavior as follows:

1) “Start without Debugging” on “Debug Mode” - Extremely fast to build and run exe. No issue there. However, because on “Debug Mode,” final synthesiser is extremely CPU inefficient and 1 voice uses what 6 voices would on Release Mode.

2) “Start Debugging” on “Debug Mode” - Very fast also to build and run exe. Again, however, final synthesiser is very CPU inefficient.

3) “Start Debugging” on “Release Mode” - Takes an extremely long time to build and run exe. >10 minutes is not unusual on my larger synth.

4) “Start Without Debugging” on “Release Mode” - Takes an extremely long time to build and run exe. Same issue.

So this clarifies that the problem is definitely “Release Mode”, though it is necessary to get an audio efficient outcome.

Furthermore, I am certain the issue is the GUI for two reasons:

  • When building/running the standalone plugin in Release Mode, I can play on my keyboard and have audio output normally coming through within 1 minute of starting the build and immediately after running the exe. It will then spend the next 10-20 min or so trying to make the screen that comes up, but the audio function is working very quickly with no issues.

  • Commenting out all but one of the functions that create the GUI Elements in PluginEditor.cpp allows the synth to build reasonably quickly (within 1-2 minutes) and run proportionately quicker even in Release Mode (within 1-2 minutes, down from 10+).

Thus this would imply that in Release Mode specifically, there is some abnormal behavior being triggered by the GUI code.

Is there something specific that it would be doing with the GUI in Release Mode but not in Debug Mode? Is there any way to get the audio part built using Release Mode (so I have normal audio efficiency) but the GUI using Debug Mode (so it doesn’t take 2-20 minutes)?

If I could somehow have Release Mode audio with Debug Mode GUI it would be perfect …


#6

When you say “build and run” do you mean both building takes awhile (totally normal in Release) and running (as in double clicking the executable) take a long time? (the latter is normal with a debugger attached, less so if it’s not).

But regardless it’s impossible to tell you what’s going on with your code on your machine, especially with differences between release/debug configurations. The task manager is also pretty useless. You’ll need to use profiling tools to see where your bottlenecks are, if any.


#7

Yes, Holy_City. I mean no matter what when I use Release Mode it is taking forever both to build the GUI both directly from Visual Studio and/or to running the exe once it finally is built. (Although despite this, the audio parts get running pretty quick either way and I can play quickly on the keyboard as the GUI keeps getting built in the background for minutes on end.)

I posted the Task Manager only because there was a question about whether an AntiVirus or other process might be the culprit and it is not.

I ran the Profiling Tools under the GUI-problematic Release Mode, but I’m not sure what I’m looking for. This is some of the data that it gave me.

Release Mode - GUI problems


What can help me figure out what the problem might be?

Given that this only happens when building in Release Mode, I can only presume some optimization Visual Studio is applying in Release Mode is causing an unintended problem. Is there any way to one-by-one disable the Release optimizations so I can narrow the problem further?


#8

So you’re going to want to build with Release + Debug symbols or else the profiling data is basically worthless. It will show you which functions are at issue.

msvcp140.dll is where the standard library functions are implemented and based on the situation it sounds like this is an issue with mutex locking, your code is running faster so resources are more likely to be contested, resulting in more locking/waiting. But try with debug info to verify.


#9

Here are the same images to compare from the Profiler in Debug Mode (ie. where there is no problem with the GUI during building or running the exe that results).

Debug Mode (no GUI issues)



The most obvious difference is in Debug Mode it is actually spending a decent % of the processing on actual synth related tasks. While on Release Mode it’s just stuck on repeating the same nonsense under Functions over and over I can’t make any sense of.

Any further thoughts or suggested next steps?

Thanks


#10

this:

parentBox.items.add(FlexItem(groupsBox).withFlex(2.5, 2).withMargin(outerScreenMargin)); //adds margin around edge of screen

parentBox is a member variable, so every time resized() is called, the parentBox.items array grows and grows.

also, in this constructor:

AudioPlugInAudioProcessorEditor::AudioPlugInAudioProcessorEditor (AudioPlugInAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
    // Make sure that before the constructor has finished, you've set the
    // editor's size to whatever you need it to be.
    
    //double timer = Time::getMillisecondCounterHiRes();

    createNumPartialsGroup();
    createGainGroup();
    createEnvelopeGroup();
    createDelayGroup();
	createdummy1Group();
	createdummy2Group();
	createdummy3Group();
	createdummy4Group();
	createdummy5Group();

	setResizable(true, true);
	setSize(screenWidth, screenHeight);
    
    //double currentTime = Time::getMillisecondCounterHiRes() - timer;
    //DBG("construction time: " << currentTime << "ms.");
}

those functions are called, but they’re not defined in the cpp file. they’re declared in the .h file, so that’s just weird. If you declare a member function for MyClass in MyClass.h, and you start implementing some of MyClass’s member functions in MyClass.cpp, you should put ALL of the member functions declared for MyClass in MyClass.cpp.

Header files with actual C++ code (not just declarations) get recompiled every time you compile. so, move everything in this file into a .cpp

for this:

	LabeledComponent* dummySlider1 = new LabeledComponent(kLabeledComponentStyle_Slider, processor.parameters, id_Dummy5);
	dummySlider1->setInterval(0.001);
	dummySlider1->setNumDecimalPlacesToDisplay(2);
	dummy2GroupSliders.add(dummySlider1);

write something safer, like this:

LabeledComponent* dummySlider1 = dummy2GroupSliders.add(new LabeledComponent(kLabeledComponentStyle_Slider, processor.parameters, id_Dummy5) );
dummySlider1->setInterval(0.001);
dummySlider1->setNumDecimalPlacesToDisplay(2);

#11

If you’re experiencing slow link-times with a release build it might be worth disabling the “Link-Time Optimisation” setting in the Projucer (although of course you might miss out on some whole program optimisation).