Problem/Motivation

Now that #1973618: DIC: Lazy instantiation of service dependencies (ProxyManager for "proxy services") has landed, we finally have the ability to mark services as lazy. That was the infrastructure issue. This issue is about determining which services should be lazy, by doing the necessary profiling work.

Proposed resolution

Mark more services as lazy.

Remaining tasks

  • (done) profiling. see #24
  • reviews

User interface changes

None.

API changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

FileSize
15.42 KB

This is the patch I tried to test (enabled proxy for all the services), but it failed on the loading of the dumped container, I don't understand why yet.

jibran’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 1: 2407177-1.patch, failed testing.

dawehner’s picture

Alright, no idea is bugfree, here are two bugs which came out of this so far.

dawehner’s picture

FileSize
3.69 KB

Enable all of them is tricky, here is a list of classes I at least had to exclude for now, as they don't use an interface.

alexpott’s picture

Title: Determine which services should be lazy » Profile to determine which services should be lazy
Issue tags: +Triaged D8 critical

Discussed with @xjm, @catch, @webchick, and @effulgentsia. Changing the issue title to reflect focus of the issue. According to @effulgentsia d8's bootstrap is still 3 ro 4 times slower than d7. This is one approach to solving that performance regression.

dawehner’s picture

Here is a list of classes which is loaded on the most simplest page you can imagine: admin/reports/status/php

classes:
  - Symfony\Component\HttpFoundation\Request
  - Symfony\Component\HttpFoundation\ParameterBag
  - Symfony\Component\HttpFoundation\FileBag
  - Symfony\Component\HttpFoundation\ServerBag
  - Symfony\Component\HttpFoundation\HeaderBag
  - Drupal\Core\DrupalKernel
  - Drupal\Core\DrupalKernelInterface
  - Symfony\Component\HttpKernel\HttpKernelInterface
  - Symfony\Component\HttpKernel\TerminableInterface
  - Drupal\Component\Utility\Unicode
  - Drupal\Core\Site\Settings
  - Symfony\Component\ClassLoader\ApcClassLoader
  - Drupal\Core\Database\Database
  - Drupal\Component\Utility\Timer
  - Drupal\Core\PhpStorage\PhpStorageFactory
  - Drupal\Core\StreamWrapper\PublicStream
  - Drupal\Core\StreamWrapper\LocalStream
  - Drupal\Core\StreamWrapper\StreamWrapperInterface
  - Drupal\Core\StreamWrapper\PhpStreamWrapperInterface
  - Drupal\Component\PhpStorage\MTimeProtectedFileStorage
  - Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage
  - Drupal\Component\PhpStorage\FileStorage
  - Drupal\Component\PhpStorage\PhpStorageInterface
  - Drupal\Core\DependencyInjection\Container
  - Symfony\Component\DependencyInjection\Container
  - Symfony\Component\DependencyInjection\IntrospectableContainerInterface
  - Symfony\Component\DependencyInjection\ContainerInterface
  - Drupal\Core\PageCache\ChainResponsePolicyInterface
  - Drupal\Core\PageCache\ResponsePolicyInterface
  - Drupal\Core\DependencyInjection\DependencySerializationTrait
  - Drupal\Core\CronInterface
  - Drupal\Component\Utility\Crypt
  - Drupal\Core\StackMiddleware\ReverseProxyMiddleware
  - Drupal\Core\StackMiddleware\PageCache
  - Drupal\Core\StackMiddleware\KernelPreHandle
  - Symfony\Component\HttpKernel\HttpKernel
  - Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher
  - Symfony\Component\EventDispatcher\EventDispatcherInterface
  - Drupal\Core\Controller\ControllerResolver
  - Symfony\Component\HttpKernel\Controller\ControllerResolver
  - Symfony\Component\HttpKernel\Controller\ControllerResolverInterface
  - Drupal\Core\Controller\ControllerResolverInterface
  - Drupal\Core\DependencyInjection\ClassResolver
  - Drupal\Core\DependencyInjection\ClassResolverInterface
  - Symfony\Component\DependencyInjection\ContainerAwareInterface
  - Symfony\Component\DependencyInjection\ContainerAwareTrait
  - Symfony\Component\HttpFoundation\RequestStack
  - Drupal\Core\Cache\CacheFactory
  - Drupal\Core\Cache\CacheFactoryInterface
  - Drupal\Core\Cache\NullBackendFactory
  - Drupal\Core\Cache\NullBackend
  - Drupal\Core\Cache\CacheBackendInterface
  - Drupal\Core\PageCache\DefaultRequestPolicy
  - Drupal\Core\PageCache\ChainRequestPolicy
  - Drupal\Core\PageCache\ChainRequestPolicyInterface
  - Drupal\Core\PageCache\RequestPolicyInterface
  - Drupal\Core\Session\SessionConfiguration
  - Drupal\Core\Session\SessionConfigurationInterface
  - Drupal\Core\PageCache\RequestPolicy\CommandLineOrUnsafeMethod
  - Drupal\Core\PageCache\RequestPolicy\NoSessionOpen
  - Drupal\Core\ContentNegotiation
  - Stack\StackedHttpKernel
  - Drupal\Core\Config\ConfigFactory
  - Drupal\Core\Config\ConfigFactoryInterface
  - Symfony\Component\EventDispatcher\EventSubscriberInterface
  - Drupal\Core\Config\CachedStorage
  - Drupal\Core\Config\StorageInterface
  - Drupal\Core\Config\StorageCacheInterface
  - Drupal\Core\Config\DatabaseStorage
  - Drupal\Core\Database\Driver\mysql\Connection
  - Drupal\Core\Database\Connection
  - Drupal\Core\Database\Statement
  - Drupal\Core\Database\StatementInterface
  - Drupal\Core\Cache\ChainedFastBackendFactory
  - Drupal\Core\Cache\ChainedFastBackend
  - Drupal\Core\Cache\CacheTagsInvalidatorInterface
  - Drupal\Core\Cache\DatabaseBackendFactory
  - Drupal\Core\Cache\DatabaseCacheTagsChecksum
  - Drupal\Core\Cache\CacheTagsChecksumInterface
  - Drupal\Core\Cache\DatabaseBackend
  - Drupal\Core\Cache\ApcuBackendFactory
  - Drupal\Core\AppRootFactory
  - Drupal\Core\Cache\ApcuBackend
  - Drupal\Core\Config\TypedConfigManager
  - Drupal\Core\TypedData\TypedDataManager
  - Drupal\Core\Plugin\DefaultPluginManager
  - Drupal\Component\Plugin\PluginManagerBase
  - Drupal\Component\Plugin\PluginManagerInterface
  - Drupal\Component\Plugin\Discovery\DiscoveryInterface
  - Drupal\Component\Plugin\Factory\FactoryInterface
  - Drupal\Component\Plugin\Mapper\MapperInterface
  - Drupal\Component\Plugin\Discovery\DiscoveryTrait
  - Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface
  - Drupal\Component\Plugin\Discovery\DiscoveryCachedTrait
  - Drupal\Core\Config\TypedConfigManagerInterface
  - Drupal\Core\Config\ExtensionInstallStorage
  - Drupal\Core\Config\InstallStorage
  - Drupal\Core\Config\FileStorage
  - Drupal\Core\Extension\ModuleHandler
  - Drupal\Core\Extension\ModuleHandlerInterface
  - Drupal\Core\Extension\Extension
  - Drupal\Core\Cache\Cache
  - Drupal\Core\Config\Schema\ConfigSchemaDiscovery
  - Drupal\Core\Config\ImmutableConfig
  - Drupal\Core\Config\Config
  - Drupal\Core\Config\StorableConfigBase
  - Drupal\Core\Config\ConfigBase
  - Drupal\Component\Utility\NestedArray
  - Drupal\Core\File\FileSystem
  - Drupal\Core\File\FileSystemInterface
  - Drupal\Core\StreamWrapper\StreamWrapperManager
  - Symfony\Component\DependencyInjection\ContainerAware
  - Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
  - Drupal\Core\StreamWrapper\TemporaryStream
  - Drupal\Component\Utility\UrlHelper
  - Drupal\Core\File\MimeType\MimeTypeGuesser
  - Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface
  - Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser
  - Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser
  - Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser
  - Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser
  - Symfony\Component\HttpKernel\Event\GetResponseEvent
  - Symfony\Component\HttpKernel\Event\KernelEvent
  - Symfony\Component\EventDispatcher\Event
  - Symfony\Component\HttpKernel\KernelEvents
  - Drupal\Core\EventSubscriber\PathSubscriber
  - Drupal\Core\Path\AliasManager
  - Drupal\Core\Path\AliasManagerInterface
  - Drupal\Core\CacheDecorator\CacheDecoratorInterface
  - Drupal\Core\Path\AliasStorage
  - Drupal\Core\Path\AliasStorageInterface
  - Drupal\Core\Path\AliasWhitelist
  - Drupal\Core\Cache\CacheCollector
  - Drupal\Core\Cache\CacheCollectorInterface
  - Drupal\Core\DestructableInterface
  - Drupal\Core\Path\AliasWhitelistInterface
  - Drupal\Core\Lock\DatabaseLockBackend
  - Drupal\Core\Lock\LockBackendAbstract
  - Drupal\Core\Lock\LockBackendInterface
  - Drupal\Core\State\State
  - Drupal\Core\State\StateInterface
  - Drupal\Core\KeyValueStore\KeyValueFactory
  - Drupal\Core\KeyValueStore\KeyValueFactoryInterface
  - Drupal\Core\KeyValueStore\KeyValueDatabaseFactory
  - Drupal\Component\Serialization\PhpSerialize
  - Drupal\Component\Serialization\SerializationInterface
  - Drupal\Core\KeyValueStore\DatabaseStorage
  - Drupal\Core\KeyValueStore\StorageBase
  - Drupal\Core\KeyValueStore\KeyValueStoreInterface
  - Drupal\Core\Language\LanguageManager
  - Drupal\Core\Language\LanguageManagerInterface
  - Drupal\Core\Language\LanguageDefault
  - Drupal\Core\Language\Language
  - Drupal\Core\Language\LanguageInterface
  - Drupal\Core\PathProcessor\PathProcessorFront
  - Drupal\Core\PathProcessor\InboundPathProcessorInterface
  - Drupal\Core\PathProcessor\OutboundPathProcessorInterface
  - Drupal\Core\PathProcessor\PathProcessorAlias
  - Drupal\Core\PathProcessor\PathProcessorManager
  - Drupal\Core\PathProcessor\PathProcessorDecode
  - Drupal\Core\EventSubscriber\AjaxSubscriber
  - Drupal\Component\Utility\Html
  - Drupal\Core\Ajax\AjaxSubscriber
  - Symfony\Component\HttpKernel\EventListener\RouterListener
  - Drupal\Core\Routing\AccessAwareRouter
  - Drupal\Core\Routing\AccessAwareRouterInterface
  - Symfony\Component\Routing\RouterInterface
  - Symfony\Component\Routing\Matcher\UrlMatcherInterface
  - Symfony\Component\Routing\RequestContextAwareInterface
  - Symfony\Component\Routing\Generator\UrlGeneratorInterface
  - Symfony\Component\Routing\Matcher\RequestMatcherInterface
  - Symfony\Cmf\Component\Routing\ChainRouter
  - Symfony\Cmf\Component\Routing\ChainRouterInterface
  - Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface
  - Drupal\Core\Routing\RequestContext
  - Symfony\Component\Routing\RequestContext
  - Symfony\Cmf\Component\Routing\DynamicRouter
  - Symfony\Cmf\Component\Routing\ChainedRouterInterface
  - Symfony\Cmf\Component\Routing\VersatileGeneratorInterface
  - Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
  - Drupal\Core\Routing\RouteProvider
  - Drupal\Core\Routing\RouteProviderInterface
  - Symfony\Cmf\Component\Routing\RouteProviderInterface
  - Symfony\Cmf\Component\Routing\PagedRouteProviderInterface
  - Drupal\Core\Routing\RouteBuilder
  - Drupal\Core\Routing\RouteBuilderInterface
  - Drupal\Core\Routing\MatcherDumper
  - Drupal\Core\Routing\MatcherDumperInterface
  - Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface
  - Drupal\Core\Access\CheckProvider
  - Drupal\Core\Access\CheckProviderInterface
  - Drupal\Core\Routing\RouteBuilderIndicator
  - Drupal\Core\Routing\RouteBuilderIndicatorInterface
  - Drupal\Core\Routing\UrlMatcher
  - Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher
  - Symfony\Component\Routing\Matcher\UrlMatcher
  - Symfony\Cmf\Component\Routing\NestedMatcher\FinalMatcherInterface
  - Drupal\Core\Routing\LazyRouteFilter
  - Symfony\Cmf\Component\Routing\NestedMatcher\RouteFilterInterface
  - Drupal\Core\Routing\UrlGenerator
  - Symfony\Cmf\Component\Routing\ProviderBasedGenerator
  - Symfony\Component\Routing\Generator\UrlGenerator
  - Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface
  - Drupal\Core\Routing\UrlGeneratorInterface
  - Drupal\Core\RouteProcessor\RouteProcessorManager
  - Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface
  - Drupal\Core\RouteProcessor\RouteProcessorCurrent
  - Drupal\Core\Routing\CurrentRouteMatch
  - Drupal\Core\Routing\RouteMatchInterface
  - Drupal\Core\Routing\StackedRouteMatchInterface
  - Drupal\Core\Access\RouteProcessorCsrf
  - Drupal\Core\Access\CsrfTokenGenerator
  - Drupal\Core\PrivateKey
  - Drupal\Core\Session\MetadataBag
  - Symfony\Component\HttpFoundation\Session\Storage\MetadataBag
  - Symfony\Component\HttpFoundation\Session\SessionBagInterface
  - Drupal\Core\Logger\LoggerChannelFactory
  - Drupal\Core\Logger\LoggerChannelFactoryInterface
  - Drupal\dblog\Logger\DbLog
  - Psr\Log\LoggerInterface
  - Drupal\Core\Logger\RfcLoggerTrait
  - Drupal\Core\Logger\LogMessageParser
  - Drupal\Core\Logger\LogMessageParserInterface
  - Drupal\Core\Logger\LoggerChannel
  - Drupal\Core\Logger\LoggerChannelInterface
  - Psr\Log\LoggerTrait
  - Psr\Log\LogLevel
  - Drupal\Core\Logger\RfcLogLevel
  - Drupal\Core\Session\AccountProxy
  - Drupal\Core\Session\AccountProxyInterface
  - Drupal\Core\Session\AccountInterface
  - Drupal\Core\Authentication\AuthenticationManager
  - Drupal\Core\Authentication\AuthenticationProviderInterface
  - Drupal\Core\Authentication\AuthenticationManagerInterface
  - Drupal\Core\Authentication\Provider\Cookie
  - Drupal\Core\Session\SessionManager
  - Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage
  - Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface
  - Drupal\Core\Session\SessionManagerInterface
  - Drupal\Core\Session\SessionHandler
  - Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy
  - Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler
  - Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy
  - Drupal\Core\Routing\LazyRouteEnhancer
  - Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface
  - Drupal\Core\Access\AccessManager
  - Drupal\Core\Access\AccessManagerInterface
  - Drupal\Core\ParamConverter\ParamConverterManager
  - Drupal\Core\ParamConverter\ParamConverterManagerInterface
  - Drupal\Core\ParamConverter\EntityConverter
  - Drupal\Core\ParamConverter\ParamConverterInterface
  - Drupal\Core\Entity\EntityManager
  - Drupal\Core\Entity\EntityManagerInterface
  - Drupal\Core\Entity\EntityTypeListenerInterface
  - Drupal\Core\Entity\EntityBundleListenerInterface
  - Drupal\Core\Field\FieldStorageDefinitionListenerInterface
  - Drupal\Core\StringTranslation\StringTranslationTrait
  - Drupal\Core\StringTranslation\TranslationManager
  - Drupal\Core\StringTranslation\TranslationInterface
  - Drupal\Core\StringTranslation\Translator\TranslatorInterface
  - Drupal\Core\StringTranslation\Translator\CustomStrings
  - Drupal\Core\StringTranslation\Translator\StaticTranslation
  - Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery
  - Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery
  - Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator
  - Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator
  - Drupal\Core\Plugin\Factory\ContainerFactory
  - Drupal\Component\Plugin\Factory\DefaultFactory
  - Drupal\Core\Validation\ConstraintManager
  - Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator
  - Drupal\Component\Plugin\Discovery\StaticDiscovery
  - Drupal\Core\KeyValueStore\KeyValueExpirableFactory
  - Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
  - Drupal\Core\ParamConverter\AdminPathConfigEntityConverter
  - Drupal\Core\Routing\AdminContext
  - Drupal\Core\ParamConverter\MenuLinkPluginConverter
  - Drupal\Core\Menu\MenuLinkManager
  - Drupal\Core\Menu\MenuLinkManagerInterface
  - Drupal\Core\Menu\MenuTreeStorage
  - Drupal\Core\Menu\MenuTreeStorageInterface
  - Drupal\Core\Cache\CacheTagsInvalidator
  - Drupal\Core\Menu\StaticMenuLinkOverrides
  - Drupal\Core\Menu\StaticMenuLinkOverridesInterface
  - Drupal\Core\Access\AccessArgumentsResolverFactory
  - Drupal\Core\Access\AccessArgumentsResolverFactoryInterface
  - Symfony\Component\Routing\RouteCollection
  - Symfony\Component\Routing\Route
  - Drupal\Core\Routing\CompiledRoute
  - Symfony\Component\Routing\CompiledRoute
  - Drupal\Core\Routing\AcceptHeaderMatcher
  - Drupal\Core\Routing\RouteFilterInterface
  - Symfony\Component\HttpFoundation\AcceptHeader
  - Symfony\Component\HttpFoundation\AcceptHeaderItem
  - Drupal\Core\Routing\ContentTypeHeaderMatcher
  - Symfony\Cmf\Component\Routing\RouteObjectInterface
  - Drupal\Core\Routing\Enhancer\ParamConversionEnhancer
  - Drupal\Core\Routing\Enhancer\RouteEnhancerInterface
  - Drupal\Core\Routing\Enhancer\AuthenticationEnhancer
  - Drupal\Core\Routing\RouteMatch
  - Drupal\Core\Session\UserSession
  - Drupal\Core\Access\AccessResult
  - Drupal\Core\Access\AccessResultInterface
  - Drupal\Core\Cache\CacheableInterface
  - Drupal\Core\Access\AccessResultNeutral
  - Drupal\Component\Utility\ArgumentsResolver
  - Drupal\Component\Utility\ArgumentsResolverInterface
  - Drupal\Core\Access\AccessResultAllowed
  - Drupal\Core\Routing\Access\AccessInterface
  - Drupal\Core\EventSubscriber\ContentControllerSubscriber
  - Drupal\Core\Routing\UrlGeneratorTrait
  - Drupal\Core\Site\MaintenanceMode
  - Drupal\Core\Site\MaintenanceModeInterface
  - Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
  - Drupal\Core\Render\BareHtmlPageRenderer
  - Drupal\Core\Render\BareHtmlPageRendererInterface
  - Drupal\Core\Render\Renderer
  - Drupal\Core\Render\RendererInterface
  - Drupal\Core\Theme\ThemeManager
  - Drupal\Core\Theme\ThemeManagerInterface
  - Drupal\Core\Theme\Registry
  - Drupal\Core\Extension\ThemeHandler
  - Drupal\Core\Extension\ThemeHandlerInterface
  - Drupal\Core\Extension\InfoParser
  - Drupal\Core\Extension\InfoParserInterface
  - Drupal\Core\Asset\CssCollectionOptimizer
  - Drupal\Core\Asset\AssetCollectionOptimizerInterface
  - Drupal\Core\Asset\CssCollectionGrouper
  - Drupal\Core\Asset\AssetCollectionGrouperInterface
  - Drupal\Core\Asset\CssOptimizer
  - Drupal\Core\Asset\AssetOptimizerInterface
  - Drupal\Core\Asset\AssetDumper
  - Drupal\Core\Asset\AssetDumperInterface
  - Drupal\Core\Config\ConfigInstaller
  - Drupal\Core\Config\ConfigInstallerInterface
  - Drupal\Core\Config\ConfigManager
  - Drupal\Core\Config\ConfigManagerInterface
  - Drupal\Core\Theme\ThemeNegotiator
  - Drupal\Core\Theme\ThemeNegotiatorInterface
  - Drupal\Core\Theme\ThemeAccessCheck
  - Drupal\Core\Batch\BatchStorage
  - Drupal\Core\Batch\BatchStorageInterface
  - Drupal\Core\Theme\AjaxBasePageNegotiator
  - Drupal\Core\Theme\DefaultNegotiator
  - Drupal\Core\Theme\ThemeInitialization
  - Drupal\Core\Theme\ThemeInitializationInterface
  - Drupal\Core\Render\ElementInfoManager
  - Drupal\Core\Render\ElementInfoManagerInterface
  - Drupal\Core\Cache\CacheContexts
  - Drupal\Core\Routing\RoutePreloader
  - Drupal\Core\EventSubscriber\ReplicaDatabaseIgnoreSubscriber
  - Drupal\Core\DependencyInjection\ContainerInjectionInterface
  - Drupal\system\SystemManager
  - Drupal\Core\Menu\MenuLinkTree
  - Drupal\Core\Menu\MenuLinkTreeInterface
  - Drupal\Core\Menu\MenuActiveTrail
  - Drupal\Core\Menu\MenuActiveTrailInterface
  - Symfony\Component\HttpKernel\Event\FilterControllerEvent
  - Symfony\Component\HttpFoundation\Response
  - Symfony\Component\HttpFoundation\ResponseHeaderBag
  - Symfony\Component\HttpKernel\Event\FilterResponseEvent
  - Drupal\Core\EventSubscriber\EnforcedFormResponseSubscriber
  - Drupal\Core\EventSubscriber\FinishResponseSubscriber
  - Drupal\Core\EventSubscriber\RedirectResponseSubscriber
  - Drupal\Core\EventSubscriber\AuthenticationSubscriber
  - Symfony\Component\HttpKernel\Event\FinishRequestEvent
  - Symfony\Component\HttpKernel\Event\PostResponseEvent
  - Drupal\Core\EventSubscriber\RouterRebuildSubscriber
  - Drupal\Core\EventSubscriber\RequestCloseSubscriber
  - Drupal\Core\EventSubscriber\KernelDestructionSubscriber

Some random ideas, which should probably be moved into their own subissues

  • We should drop the timer and instead let contrib just implement its functionality
  • Making page cache disabled entirely by default would safe around 10 loaded classes
  • Why do we need the various mimetype guessers on every request?
  • Can we store the private key as a container parameter and retrieve it from state?
  • Make the creation of the discovery objects lazy in the default plugin manager. They aren't used in most cases anyway, as most requests serve from cache
  •   - Drupal\Core\Config\ConfigInstaller
      - Drupal\Core\Config\ConfigInstallerInterface
      - Drupal\Core\Config\ConfigManager
      - Drupal\Core\Config\ConfigManagerInterface
    

    they are loaded, maybe they should be marked as lazy

  • Why does theme.negotiator.system.batch have to be loaded.
Berdir’s picture

+ 1 on dropping timer.

- private key change sounds interesting, but would be an API change.

* Making page cache disabled entirely by default would safe around 10 loaded
classes

Actually, we want to do the opposite, enable by default, without configuration checks: #2368987: Move internal page caching to a module to avoid relying on config get on runtime.

That list is interesting. Any chance you can provide a tree-like output, based on how they are created through the container? That would help with understanding what is needed why.

Wim Leers’s picture

Actually, we want to do the opposite, enable by default, without configuration checks: #2368987: Move internal page caching to a module to avoid relying on config get on runtime

And doing that will allow any site that doesn't use the page cache to save those 10 classes.

(BTW: those 10 classes are 1) only a small fraction of the grand total of classes, 2) the page cache itself is very fast, and on a page cache hit, these classes are also loaded, so that's definitely not going to make a huge difference for overall bootstrap performance.)

yched’s picture

Woah. Scary :-(

"Make the creation of the discovery objects lazy in the default plugin manager" sounds like something we should totally do...

Berdir’s picture

FileSize
23.47 KB
2.13 KB

Attached is my version for that output, patch is the hacks that i used to generate it. The classes are indented based on the "container recursion level". That makes it visible which service caused which class to be loaded.

Fabianx’s picture

Here is my classes with usage count gotten via XHProf for anonymous stock front page:

Starts with:

"-" == class used 0 times, potentially problematic
"+" == class used 1 times
"*" == class used more than 1 times
"=" == is a service

Removed traits and interfaces and did not count __construct obviously.

Patch attached to create output, too.

(Edit: Review with dreditor to see problematic (red) and less used (green) services on a glance).

dawehner’s picture

Really nice idea to leverage + and -!!

Just some random comments.

  1. = = = = lock
    - - - - Drupal\Core\Lock\DatabaseLockBackend(0)
    - - - - Drupal\Core\Lock\LockBackendAbstract(0)
    

    So lock should be lazy by default?

  2. = = = = = = = router.builder
    * * * * * * * Drupal\Core\Routing\RouteBuilder(2)
    = = = = = = = = router.dumper
    - - - - - - - - Drupal\Core\Routing\MatcherDumper(0)
    = = = = = = = = access_manager.check_provider
    * * * * * * * * Drupal\Core\Access\CheckProvider(3)
    = = = = = = = = router.builder_indicator
    

    I'd argue that the entire router.builder should be lazy, but for now the MatcherDumper should be.
    Note: #356399: Optimize the route rebuilding process to rebuild on write would also remove the initialization in the first place.

  3. * * * * * Drupal\Core\Routing\UrlGenerator(4)
    - - - - - Symfony\Cmf\Component\Routing\ProviderBasedGenerator(0)
    

    The script seems to include base classes

  4. = = = = = paramconverter.views_ui
    - - - - - Drupal\views_ui\ParamConverter\ViewUIConverter(0)
    - - - - - Drupal\Core\ParamConverter\EntityConverter(0)
    = = = = = = entity.manager
    * * * * * * Drupal\Core\Entity\EntityManager(22)
    = = = = = = = container.namespaces
    = = = = = = = string_translation
    * * * * * * * Drupal\Core\StringTranslation\TranslationManager(8)
    = = = = = = = = string_translator.custom_strings
    + + + + + + + + Drupal\Core\StringTranslation\Translator\CustomStrings(1)
    + + + + + + + + Drupal\Core\StringTranslation\Translator\StaticTranslation(1)
    = = = = = = = typed_data_manager
    - - - - - - - Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery(0)
    - - - - - - - Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery(0)
    - - - - - - - Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator(0)
    - - - - - - - Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator(0)
    + + + + + + + Drupal\Core\Plugin\Factory\ContainerFactory(1)
    + + + + + + + Drupal\Component\Plugin\Factory\DefaultFactory(1)
    = = = = = = = = validation.constraint
    - - - - - - - - Drupal\Core\Validation\ConstraintManager(0)
    - - - - - - - - Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator(0)
    - - - - - - - - Drupal\Component\Plugin\Discovery\StaticDiscovery(0)
    = = = = = = = entity.definitions.installed
    = = = = = = user.shared_tempstore
    - - - - - - Drupal\user\SharedTempStoreFactory(0)
    = = = = = = = keyvalue.expirable
    - - - - - - - Drupal\Core\KeyValueStore\KeyValueExpirableFactory(0)
    = = = = = paramconverter.configentity_admin
    - - - - - Drupal\Core\ParamConverter\AdminPathConfigEntityConverter(0)
    = = = = = = router.admin_context
    - - - - - - Drupal\Core\Routing\AdminContext(0)
    = = = = = paramconverter.entity
    = = = = = node_preview
    - - - - - Drupal\node\ParamConverter\NodePreviewConverter(0)
    = = = = = = user.private_tempstore
    - - - - - - Drupal\user\PrivateTempStoreFactory(0)
    = = = = = paramconverter.menu_link
    - - - - - Drupal\Core\ParamConverter\MenuLinkPluginConverter(0)
    = = = = = = plugin.manager.menu.link
    + + + + + + Drupal\Core\Menu\MenuLinkManager(1)
    = = = = = = = menu.tree_storage
    + + + + + + + Drupal\Core\Menu\MenuTreeStorage(1)
    = = = = = = = = cache.menu
    = = = = = = = = cache_tags.invalidator
    * * * * * * * * Drupal\Core\Cache\CacheTagsInvalidator(2)
    = = = = = = = menu_link.static.overrides
    - - - - - - - Drupal\Core\Menu\StaticMenuLinkOverrides(0)
    

    Maybe this is a sign that param converter should be loaded lazy again.

  5. = = bare_html_page_renderer
    - - Drupal\Core\Render\BareHtmlPageRenderer(0)
    

    Given that the bare html page renderer should be needed on just a really limited amount of pages, it should be lazy.

  6. = = = = = = = info_parser
    - - - - - - - Drupal\Core\Extension\InfoParser(0)
    ...
    = = = = = = = = asset.css.dumper
    - - - - - - - - Drupal\Core\Asset\AssetDumper(0)
    = = = = = = = config.installer
    - - - - - - - Drupal\Core\Config\ConfigInstaller(0)
    

    So module installer, config installer, info_parser certainly falls into the category of: just used rarely.

  7. = user.permissions
    - Drupal\user\PermissionHandler(0)
    

    that one certainly should also be lazy. Its just needed for UI purposes, either in admin/people/... or in the views UI.

Wim Leers’s picture

Fabianx++ — clever usage of our existing infra :D

Fabianx’s picture

Issue tags: +needs profiling

#13:

The script seems to include base classes.

Yes, that is pretty hard to check here, with the reflection class, I could get the base class, but the problems are calls to the base class:

To which class would you count those?

--

Can you do a patch for the services now found that could be lazy?

Every non-loaded class is a _huge_ win, so lets focus on things with large dependency chains as we need to load the proxy dumped class anyway.

dawehner’s picture

Status: Needs work » Needs review
FileSize
6.47 KB

Here are a couple of those services marked as lazy.

Status: Needs review » Needs work

The last submitted patch, 16: 2407177-16.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
6.04 KB
439 bytes

Again ...

Status: Needs review » Needs work

The last submitted patch, 18: 2407177-18.patch, failed testing.

yched’s picture

As @dawehner pointed above, most (plugin) Discovery objects are created but not used, since the definitions are cached anyway.

dawehner’s picture

Status: Needs work » Needs review
FileSize
5.73 KB
469 bytes

I'm not sure whether its right to exclude the config.manager from being lazy, but the error message just scares the hell out of me,
and marking the other ones lazy is some progress for itself.

Status: Needs review » Needs work

The last submitted patch, 21: 2407177-21.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
5.73 KB

Quickly rerolled.

dawehner’s picture

Did some quick profiling for the following usecases:

I'm have profiled the entire request, with opcache as well as the apcu based classloader enabled.

Absolute numbers

Scenario HEAD PATCH
Default frontpage, no content, anonymous user 254ms 236ms
admin/report/status/php, anonymous (bootstrap + phpinfo()) 31ms 28.3ms
REST request: /node/1 with hal_json 68.4ms 65.7ms
YesCT’s picture

Issue summary: View changes
Issue tags: -needs profiling

removing needs profiling tag (unless there were some other cases that needed profiling?)

dawehner’s picture

Fabian asked me to create a separate issue: #2454287: Make a couple of services lazy to get the current changes in

Fabianx’s picture

Status: Needs review » Active
Issue tags: +needs profiling

Back to active here then, lets get more profiling for other scenarios done after #2454287: Make a couple of services lazy is in.

dawehner’s picture

Other ideas for scenarious:

  • Frontpage with actual content (10 nodes)
  • /node/1 with HTML
  • /nodes (a view rendering 10 nodes as hal_json)
effulgentsia’s picture

@dawehner or @Fabianx: can you provide an updated list along the lines of #7 or #12 for the admin/reports/status/php scenario? Seems like our bootstrap is still too slow (relative to D7). Maybe there's nothing left that can be made lazy for that scenario, but a list of loaded classes could perhaps point to some other optimizations we should open issues for?

Fabianx’s picture

#29 It is Fabian_x with lowercase x ... *grmbl* :-D

Yes, can provide new classes for the scenario if dawehner does not beat me to it :).

effulgentsia’s picture

with lowercase x

Oops. Sorry. Edited #29 to fix that.

Fabianx’s picture

FileSize
4.02 KB
13.97 KB

Re-rolled and attached classes.txt for /admin/reports/status/php

dawehner’s picture

Opened up an issue for some of them, see #2463343: Lazy load typed config related services. but the result is not really positive yet.

borisson_’s picture

Assigned: Unassigned » borisson_
borisson_’s picture

Assigned: borisson_ » Unassigned

I tested this by using boom to do 100 requests with a concurrency of 2 to my local machine with page cache disabled.
The command I used is this one: $ ~/go/bin/boom -n 100 -c 2 http://d8.dev/node/4

I used the 90th percentile of time distribution.

The results I have are these:

Service lazy 90th percentile
none 0.5061 secs
file_system 0.5008 secs
config.storage.schema 0.4862 secs
page_cache_no_cache_routes 0.5048 secs
cache_context.languages 0.5013 secs
page_cache_no_server_error 0.5009 secs

With all those services made lazy though I get an interesting result. The result is then 0.6296 secs.

Berdir’s picture

We can't make the services lazy that we know that we will call, that makes performance worse, not better. config.storage.schema is different, there's an issue for that.

Note: Testing concurrency > 1 is just testing your system and not the code. How many requests in parallel are processed doesn't matter how long a single request has, if anything, it makes it a bit slower when it has to wait.

dawehner’s picture

Right, as we deal with potential just small changes, using an external HTTP based tool is IMHO the wrong approach.
Nonetheless its great to see that marking config.storage.schema is quite helpful in terms of performance, itself.

effulgentsia’s picture

Status: Active » Fixed

Determining which services should be lazy seems like a subset of #2470679: [meta] Identify necessary performance optimizations for common profiling scenarios, so raised that one to critical. Marking this as fixed rather than duplicate, because of the early work done in this issue that resulted in us making some services lazy already.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.