Problem/Motivation
During install most of the time is spent building the container. See https://blackfire.io/profiles/0aae6482-d431-43e3-8bef-ee0916976585/graph...() which clearly shows the 14 module installs of a minimal install and their subsequent container rebuilds.
Our container by default registers a number of container passes to optimise the container. Considering we're going to throw the container away maybe the time spent making the optimisations is not worth it.
Proposed resolution
Remove InlineServiceDefinitionsPass, RemoveUnusedDefinitionsPass, AnalyzeServiceReferencesPass and ReplaceAliasByActualDefinitionPass during the installer do not do unnecessary work. This results in 1000s of less function calls and a quicker install. See the comparison for a standard install - https://blackfire.io/profiles/compare/612e435c-5c03-48b3-99a3-80c1846396...
Remaining tasks
User interface changes
None
API changes
None
Data model changes
None
Release notes snippet
Comment | File | Size | Author |
---|---|---|---|
#9 | 3185768-5.patch | 2.17 KB | alexpott |
#7 | 3185768-9.0.x.patch | 4.62 KB | alexpott |
#6 | 3185768-8.9.x.patch | 3.52 KB | alexpott |
#5 | 3185768-5.patch | 2.17 KB | alexpott |
#3 | 3185768-3.patch | 1.43 KB | alexpott |
Comments
Comment #2
alexpottComment #3
alexpottI think we can remove even more of these passes. Here's a comparison of the latest patch and installing standard - https://blackfire.io/profiles/compare/612e435c-5c03-48b3-99a3-80c1846396...
Here's a comparison of the standard install using
time
..Without patch
With patch
Comment #4
alexpottComment #5
alexpottHere's a slightly better way of removing the compiler passes. It means that Symfony's PassConfig can change and we'll get the benefits (if they are benefits). Also the ResolveHotPathPass pass is useless for Drupal. It would only work with Symfony's PHP dumper which do not use. We use our own dumper. On a minimal install this results in over 7000 less calls to Symfony\Component\DependencyInjection\Definition::hasTag() (taking it down to 324,594 :D)
I've not bothered with interdiffs because the same piece of code is changing again and again.
Comment #6
alexpottHere's the equivalent patch for 8.9.x for anyone who wants to try it out there.
Comment #7
alexpottAnd here's a 9.0.x patch ... the patch in #6 applies but that is for SF3 only.
Comment #8
BerdirSo after, the usual patch reroll party, I've updated our install profile with ~133 modules being installed to Drupal 9.1 and tested this.
With blackfire and xdebug enabled but not active, just "time" to report execution time:
D9.1 rc3 (-ish, 32 or so patches)
1m57.685s
+ this patch:
1m43.925s
That's nice. I suspect this is something that active profiling with blackfire massively overcounts as we're mostly saving a lot of very fast function calls. But even without that, if I got my basic math right, that's an improvement of 18%. That's great, but even not active, those extension are a massive performance hit. I disabled them to see just how much and was surprised...
Without the patch and those extensions, install time for me was merely 48s and the patch made it just ~2s (or less, results seem to vary by ~.5s) faster, that's ~4%, not 18%. Still nice and I can confirm that this seems to work fine for us, but clearly the first thing you should do if you want a fast install is disabling those extensions :)
Watching top while doing those installs shows that PHP CPU usage is between 50-90% and mysql up to 50%, so I suspect that the bottleneck is then mysql and IO to it more than PHP itself. It's worth pointing out that we create a lot of fields/tables (250) during install and we install a ton of default content and even generate some thumbnails with convert, that's all included in that time.
Comment #9
alexpottRe-upping the 9.2.x patch. I still think a 4% boost on a massive site install like the one tested by @Berdir is a nice result. Plus standard and minimal are quicker.
Comment #10
longwaveDo we need any of the "removing" passes if we are more interested in container build time than runtime performance?
Comment #11
alexpottHere's the list of passes that are still there... RemovePrivateAliasesPass, RemoveAbstractDefinitionsPass, DefinitionErrorExceptionPass
I think we need RemovePrivateAliasesPass because
Therefore we're removing things we've added. I wouldn't we something in the installer to be abler to use one of these
I think a similar thing goes for the RemoveAbstractDefinitionsPass - although it's a bit more tenuous. I guess we can remove this pass - it's not that costly but it does mean we do less.
I think we need DefinitionErrorExceptionPass in order to report errors. Not sure about the impact of removing RemoveAbstractDefinitionsPass on that.
Comment #13
alexpottThis is still relevant and results in 1000s of less function calls for a standard install... https://blackfire.io/profiles/compare/822bbc6d-f165-4431-a59b-596f66b219...()
It doesn't really result in much of a speed up locally for me but in more constrained environments it will probably make a difference. Note with the performance timings on blackfire they need to be take with a pinch of slat because the thousands of function calls less result in bigger savings when blackfire is profiling.
Comment #14
longwaveRemoveAbstractDefinitionsPass is very simple so let's not worry about a nano-optimisation here, to ensure we don't accidentally use an abstract service somehow.
DefinitionErrorExceptionPass also looks necessary in case there is an error in the dependency graph somewhere, so let's keep that too.
Therefore this is RTBC as it stands, we can always revisit later if we want to trim more off somewhere.
Comment #16
catchThis seems worth doing, apart from the time it's also noise removed if we're trying to find more installer optimisations. Being relatively conservative with which passes we removed seems sensible. Also putting this into 9.3.x-only for the same reason.
Committed c671ff1 and pushed to 9.3.x. Thanks!