Been on a bit of a performance optimization adventure the past couple of days, with great success! One last one I'm not sure how to tackle is about large forms.
I don't want to load them in advance because there are many and they don't all get used, so I load up the form when needed using a call to CreateNewForm. This works really well and for most forms it is pretty speedy, even with larger forms. But my largest form is pretty large, the DFM on disk is about 500kb. So when CreatNewForm runs, it takes awhile to run through this and process it, I'm guessing.
Aside from the obvious approach of splitting it up into smaller forms, is there anything that can be done to preprocess the DFM to try and cut down on the overhead when CreateNewForm comes along, or something else to otherwise improve the overall speed of CreateNewForm in this kind of situation?
Most everything is embedded within TWebPageControl pages. By default, it takes around 3000ms just to get through the CreateNewForm stage. But if I set the TWebPageControls as Visible := False, in the IDE at designtime, then it gets through CreateNewForm in about 1000ms and about 500ms in WebFormCreate to go back to Visible := True again. Wondering if there are other things like this that I can do to help speed it up. I presume the DFM is processed and compressed, etc. when it is compiled into the project, but maybe there's a way to strip out more stuff that isn't really needed? I scrolled through it and there are lots of properties that aren't really being used (say, BorderColor, BorderStyle in my case) so I'm thinking maybe to filter out those kinds of things ahead of time, maybe?
Indeed, the more properties are persisted in the DFM file, the more lines of code to set all these properties.
Normally, the default decorator is used to not persist properties in the DFM file when these remain at default value.
For what exact controls do you see BorderColor/BorderStyle being persisted in the DFM where it would not be needed? If there is something we can further optimize in the frame, we would of course like to know and do it.
I've attached a copy of the DFM in question. I suggested BorderStyle
only because they stood out as something that I don't use and that showed up frequently, mostly on TWebPanels it looks like. Doesn't mean that nobody uses them, but I tend to explicitly set things like border-0
consistently enough that whatever BorderColor
are set to become irrelevant.
I don't know if that's the best approach, just an idea. Maybe if there could be a whitelist or blacklist of these properties that could be set to just not use them when the project is compiled, that might help. I guess I could just do that myself - strip certain values from the DFM and see how much it helps.
Or maybe if there were global defaults, like ElementFont
is always going to be efCSS
. It's also a form I've spent a lot of time fiddling with, so maybe a lot of default properties have been set/unset and ended up in the DFM when they probably don't need to be.
Would be fun if there was a 'reset to defaults' kind of thing that would clean out everything, or give a list of everything that isn't the default. I will try and go through and see what is 'bold' in the IDE property list and maybe unset any that are set that don't need to be, which I guess is the manual way of doing the same thing?
I just tried stripping the DFM of all of these things....
BorderStyle = bsNone
BorderStyle = bsSingle
BorderColor = clNone
WidthPercent = 100.000000000000000000
HeightPercent = 100.000000000000000000
ElementFont = efCSS
Color = clWindow
...and the DFM is about 100k less right off the bat, with, at first glance at least, absolutely no difference in the app. Oddly, it seems to take longer in CreateNewForm with the stripped down DFM than with the previous version.
It could also strip out any of the Margin values if the AlignWithMargin isn't set, but that's starting to get into some details that may not matter quite so much.
IPM.dfm (507.6 KB)
I cannot see a reason that when properties would have been stripped that execution becomes slower. This shouldn't be the case. The normal logic would be that the fewer properties, the faster.
We'll research if we can further reduce properties and recheck also if all possible property settings are handled properly in relation to BeginUpdate/EndUpdate (which should be the case, but maybe something slipped through).
Thank you. I wonder also if it would make sense to exclude properties from the DFM at compile-time if they correspond to a default setting for whatever processes the DFM at run-time. For example, WidthPercent and HeightPercent might be assumed to be 100.000 at run-time and then only processed at run-time if they are different than that, so no point even including it in the DFM that is compiled if those are the values in the incoming DFM. But maybe it already does this kind of thing.
In any event, hopefully you run across a BeginUpdate/EndUpdate trick like some of these others that you posted that resulted in a +/- 5x improvement. Probably something amiss if the visibility property of a TWebPageControl can impact how long it takes. But maybe that's just a difference between the time it takes to process the DFM and the render that happens after.
I can confirm we worked out now storing of WidthPercent & HeightPercent when these have default values 100. Next update will have this improvement.