Problem/Motivation

Symfony's UniversalClassLoader uses artificial distinction between namespaced classes and unnamespaced ones. We're using PSR-0, which does not distinguish between the two.

Proposed resolution

Switch to Symfony's ClassLoader which directly advertises PSR-0 support, which does not differentiate between namespaces classes and unnamespaced ones. This cleans up a bunch of the class loader code.

Remaining tasks

The patch is RTBC, and needs to be committed.

User interface changes

None.

API changes

drupal_classloader() now provides a ClassLoader object.

Original report by chx

https://github.com/doctrine/common/pull/154#discussion_r1040649

UniversalClassLoader was adding an artificial distinction between namespaced classes and unnamespaced ones whereas PSR-0 does not. And Symfony 2.1 introduced a ClassLoader which has a simpler API by avoiding this distinction (just like Composer avoids it too)

CommentFileSizeAuthor
#107 UniversalClassLoader.png34 KBRobLoach
#107 ClassLoader.png29.26 KBRobLoach
#104 interdiff.txt1.97 KBdawehner
#103 1658720.patch15.04 KBRobLoach
#102 drupal-1658720-102.patch13.75 KBdawehner
#102 interdiff.txt441 bytesdawehner
#100 drupal-1658720-100.patch13.75 KBdawehner
#93 1658720.patch13.72 KBRobLoach
#94 interdiff.txt2.02 KBdawehner
#91 1658720.patch12.11 KBRobLoach
#87 1658720.patch12.12 KBRobLoach
#83 drupal-1658720-83.patch12.1 KBdawehner
#83 interdiff.txt1.2 KBdawehner
#82 1658720.patch12.09 KBRobLoach
#80 1658720.patch9.88 KBRobLoach
#76 drupal-1658720-76.patch10.85 KBdawehner
#72 1658720_70.patch10.84 KBchx
#70 1658720.patch11.35 KBRobLoach
#67 drupal-1658720-67.patch10.9 KBdawehner
#67 interdiff.txt2.03 KBdawehner
#65 drupal-1658720-65.patch10.76 KBdawehner
#65 interdiff.txt1.22 KBdawehner
#60 1658720-59.patch10.78 KBRobLoach
#59 1658720-59.patch40.34 KBRobLoach
#56 drupal-1658720-56.patch15.44 KBdawehner
#5 6159818.patch3.36 KBRobLoach
#51 1658720.patch24.67 KBRobLoach
#49 1658720.patch6.96 KBRobLoach
#45 1658720.patch6.23 KBRobLoach
#41 classloader-callgrind.png74.07 KBsun
#39 drupal8.classloader.39.patch6.23 KBsun
#37 classloader.patch5.93 KBRobLoach
#35 classloader.patch5.75 KBRobLoach
#21 after.png59.36 KBdawehner
#21 before.png73.02 KBdawehner
#19 interdiff.txt999 bytesdawehner
#19 drupal-1658720-19.patch4.79 KBdawehner
#17 drupal-1658720-17.patch3.67 KBdawehner
#4 classloader.patch3.36 KBRobLoach
#2 1658720.patch3.36 KBRobLoach
#1 1658720.patch3.33 KBRobLoach
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

RobLoach’s picture

Status: Active » Needs review
FileSize
3.33 KB

Using straight up ClassLoader makes complete sense here.

The APC ClassLoader is removed as it doesn't work with what we have (drupal_classloader_register() gives an exception). In replacement of it, once generate classmaps for all PSR-0 packages hits, we should switch to the Composer ClassLoader as there would be a 1:1 classmap given to us. This would make it extremely fast as we wouldn't even need to check the PSR-0 namespaces. This must follow after #1424924: Use Composer for updating Symfony components (without removing Symfony code from repo) hits though.

In the mean time, we're using Symfony's straight up ClassLoader without its APC counterpart.

RobLoach’s picture

FileSize
3.36 KB

Forgot to remove a line.

Crell’s picture

Status: Needs review » Needs work
+++ b/core/includes/bootstrap.inc
@@ -2994,45 +2993,21 @@ function drupal_classloader() {
+      'Drupal\\Core' => DRUPAL_ROOT . '/core/lib',
+      'Drupal\\Component' => DRUPAL_ROOT . '/core/lib',

I think we decided on a coding standard of not including the \\ in single-quoted class name strings, didn't we?

Aside from that quibble, I'm fine here.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
3.36 KB

Typo.

RobLoach’s picture

Status: Needs work » Needs review
Issue tags: -Performance
FileSize
3.36 KB

I think we decided on a coding standard of not including the \\ in single-quoted class name strings, didn't we?

Updated

RobLoach’s picture

Status: Needs review » Postponed

Let's post-pone this one until #1424924: Use Composer for updating Symfony components (without removing Symfony code from repo) gets in. Angie wanted to bring the needs review threshold down.

chx’s picture

12 insertions(+), 37 deletions(-). That's some some serious simplification right there. I love this patch. It also eats up at least #1628040: Univerclassloader fallbacks are not namespaced and #1620114: Explicitly register \Drupal\Component and \Drupal\Core to increase class lookup performance

webchick’s picture

Should we do some benchmarks here?

RobLoach’s picture

Should we do some benchmarks here?

They'd be along the same lines as the benchmarks catch did in Explicitly register \Drupal\Component and \Drupal\Core:
before.png
after.png

chx’s picture

Status: Postponed » Needs review

There is no need to wait on the Composer patch with this one. However, yes, new benchmarks are in order because despite the benefit of not using fallback there is one str_replace added per findFile which was not there before because UniversalClassLoader made a distinction between namespace and pear like class names which is now gone so the replace underscore to dirseparator always happens.

@RobLoach, Symfony is PHP code. I heartily recommend reading it before following up on an issue. This is the second issue I am following up on just today where you have followed up on an issue without reading the relevant Symfony code. I am sorry I need to write this. This is not meant to be a personal attack at all.

RobLoach’s picture

Status: Needs review » Needs work
Issue tags: -Performance

This needs work as we might actually be able to make ApcClassLoader work for us here.

RobLoach’s picture

Status: Needs review » Needs work
cweagans’s picture

Patch looks pretty straightforward and I'm inclined to RTBC it, but it sounds like we want to see some benchmarks first, so tagging.

cweagans’s picture

RobLoach’s picture

amateescu’s picture

Status: Postponed » Needs work
dawehner’s picture

Status: Needs work » Needs review
Issue tags: +Performance
FileSize
3.67 KB

Adding a tag

Let's rerole the patch against recent changes in this part.

Status: Needs review » Needs work

The last submitted patch, drupal-1658720-17.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
4.79 KB
999 bytes

Oh right, annotations have to be converted as well to use the new namespaces

sun’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me.

Unless we need benchmarks here (I doubt it?), this should be ready to fly.

dawehner’s picture

FileSize
73.02 KB
59.36 KB

I'm not sure whether this is just random fluctuation (running 100 requests and aggregated here).
This is not a normal drupal page you see here, one with pretty heavy class usage.

dawehner’s picture

Note: this patch IS using the APCClassLoader part, see #1658720-1: Use ClassLoader instead of UniversalClassLoader, maybe robloach should review as well before getting this in.

sun’s picture

Status: Reviewed & tested by the community » Needs review

1) Hm. So ClassLoader is minimally/slightly slower, and involves more function calls.

2) I looked at the ApcClassLoader docs and the changes in this patch seem to be correct.

RobLoach’s picture

Status: Needs work » Needs review
Issue tags: +Performance
+++ b/core/includes/bootstrap.incundefined
@@ -3111,50 +3111,29 @@ function drupal_classloader() {
+    if (variable_get('autoloader_mode', 'default') == 'apc') {
+      require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php';
+      $loader = new ApcClassLoader('drupal.' . $GLOBALS['drupal_hash_salt'], $loader);

Putting the benchmarks aside, it looks like we're instantiating a ClassLoader twice. Once using "ClassLoader", and then again later on if it's APC.

sun’s picture

Yes, that's how ApcClassLoader is supposed to be used. Make sure to read its docs:
http://drupalcode.org/project/drupal.git/blob/HEAD:/core/vendor/symfony/...

RobLoach’s picture

Ah, thanks!

Damien Tournoud’s picture

Twig doesn't use PSR-0 classes, so are we sure that we can use the non-universal class loader here?

RobLoach’s picture

Twig doesn't use PSR-0 classes, so are we sure that we can use the non-universal class loader here?

PSR-0 covers PEAR-like autoloading as it replaces any "_" in the class name with a directory separator for the class's path. You can see that on line 181:

    $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

In Twig's composer.json, you can see it asks for the Composer's PSR-0 ClassLoader, which pretty much does the same thing. The benefit of using Symfony's straight up ClassLoader is that Symfony's ClassLoader component comes with the APC one. Composer's performance optimization comes in with composer dump-autoload --optimize, which caches a straight up classmap array, which would help even APC. But, that's a separate issue: #1818628: Use Composer's optimized ClassLoader for Core/Component classes.

Fabianx’s picture

Status: Needs review » Reviewed & tested by the community

More benchmarks:

=== core..core-1658720--core compared (508d81486ceb0..508d826a1e350):

ct  : 37,686|37,686|0|0.0%
wt  : 143,797|143,618|-179|-0.1%
cpu : 144,009|140,009|-4,000|-2.8%
mu  : 9,707,000|9,707,000|0|0.0%
pmu : 9,810,424|9,810,424|0|0.0%

=== core..core-1658720--19 compared (508d81486ceb0..508d833c057f5):

ct  : 37,686|37,830|144|0.4%
wt  : 143,797|144,021|224|0.2%
cpu : 144,009|144,010|1|0.0%
mu  : 9,707,000|9,705,784|-1,216|-0.0%
pmu : 9,810,424|9,808,944|-1,480|-0.0%

ct = number of function calls, wt = wall time, cpu = cpu time used, mu = memory usage, pmu = peak memory usage

First benchmark is baseline, which shows some slight variance here of 179 micro secs.

144 function calls more, but the overhead is 224 micro secs plus, which is within variance, I think this is fine. The overhead are more calls to strpos (135, besides that CL uses file_exists instead of is_file, but that makes no real difference. file_exists is also called 5 times more in this benchmark.

I think this is good to go!

Fabianx’s picture

Status: Reviewed & tested by the community » Needs work

Tested with

$conf['autoloader_mode'] = 'apc';

Got:

PHP Fatal error:  Call to undefined method Symfony\Component\ClassLoader\ApcClassLoader::addPrefixes() in /var/www/core/includes/bootstrap.inc on line 3128
PHP Fatal error:  Class 'Symfony\Component\DependencyInjection\ContainerBuilder' not found in /var/www/core/includes/bootstrap.inc on line 2437

Please fix.

RobLoach’s picture

Status: Needs work » Closed (duplicate)
sun’s picture

Status: Closed (duplicate) » Needs work

The classloader change should happen here. It doesn't make sense to do it in that issue, because as you can obviously see, it requires discussion, reviews, and benchmarks.

Crell’s picture

For the record: Performance-tweaking about our class loader right now is an epic waste of time. We can, by design, swap our class loader at any time without impacting functionality. We could do so post-freeze, post-code-freeze, hell we could do it in June or July or August and it would be fine. Right now the focus should be on easy, not micro-optimized. Do what makes development each, and stuff the rest. Revisit before release. Done.

Composer's class loader "just works" without much additional effort, and we're still adding libraries through it and updating others. Using that for now makes that process easier. Easy trumps optimized for the next 3 months at least.

Fabianx’s picture

#33: The only thing that needs work here is that the APC Class Loader is not working.

That is my only complaint of this patch.

I am not sure why the ApcClassLoader Decorator is not implementing addPrefixes, but the normal ClassLoader is, because I think we are doing this right.

Lets get a new patch in and unblock the update.

I am happy to test.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
5.75 KB

Right now the focus should be on easy, not micro-optimized. Do what makes development each, and stuff the rest. Revisit before release. Done. Composer's class loader "just works" without much additional effort, and we're still adding libraries through it and updating others. Using that for now makes that process easier. Easy trumps optimized for the next 3 months at least.

+1.... As many have said, Premature optimization is the root of all evil.... But we desperately need the Symfony and Composer updates in as soon as possible. I'm a fan of whatever will get those in sooner rather than later.

catch’s picture

-    // Get all PSR-0 namespaces.
-    $namespaces = drupal_classloader()->getNamespaces();
-    foreach ($namespaces as $ns => $namespace_dirs) {
+    // Get all PSR-0 prefixes.
+    $prefixes = drupal_classloader()->getPrefixes();
+    foreach ($prefixes as $ns => $prefix_dirs) {

I don't think getPrefixes() is a public method on every PSR-0 classloader. If it's not, could we look at removing the dependency on whichever classloader we happen to be using from the plugin discovery?

RobLoach’s picture

FileSize
5.93 KB

If APC was selected to be used, but was not available, the above patch would fail. This one fixes that. Is that function_exists() check really needed? I'd assume if they're asking to use APC, then they know it's there.

I don't think getPrefixes() is a public method on every PSR-0 classloader. If it's not, could we look at removing the dependency on whichever classloader we happen to be using from the plugin discovery?

Correct... This is not a limitation of PSR-0, however. PSR-0 is simply an ideology, not an interface. Most systems wouldn't get a list of namespaces that the classloader has registered. You're right that we should remove that dependency. Let's do that here: #1836008: Remove drupal_classloader() use in Drupal\Core\AnnotatedClassDiscovery

Fabianx’s picture

Status: Needs review » Needs work

Please disregard and see below.

===================

#37: Not necessary.

+++ b/core/includes/bootstrap.incundefined
@@ -3112,64 +3112,45 @@ function ip_address() {
+    if ($mode == 'apc' && function_exists('apc_store')) {
+      require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php';
+      $apc_loader = new ApcClassLoader('drupal.' . $GLOBALS['drupal_hash_salt'], $loader);
+      $apc_loader->register();

Unnecessary, because APCClassLoader does:

  if (!extension_loaded('apc')) {
            throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
        }

BUT the real problem is:

+++ b/core/includes/bootstrap.incundefined
@@ -3112,64 +3112,45 @@ function ip_address() {
-    $loader->registerNamespaces(array(
+    $loader->addPrefixes(array(
       'Drupal\Core' => DRUPAL_ROOT . '/core/lib',
...
-    $loader->register();
+    $loader->addPrefixes($namespaces);
   }
   return $loader;

This needs to happen, before the wrapping, because APCClassLoader does not implement addPrefixes method.

See: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cla...

+++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.phpundefined
@@ -47,14 +47,14 @@ public function getDefinitions() {
+    // Get all PSR-0 prefixes.
+    $prefixes = drupal_classloader()->getPrefixes();
+    foreach ($prefixes as $ns => $prefix_dirs) {

And this method also does not exist.

The APCClassLoader is pretty basic.

Can we add our own APCClassLoader that acts like a real decorator / proxy and implements the same functions as the ClassLoader?

============================================

Ah, I got it now :-).

We are just registering the APCClassLoader, but using the normal class loader still for getPrefixes, etc.

Makes sense :-).

Maybe use try / catch to make use of Exceptions?

  $registered = FALSE;
  if ($mode == 'apc') {
    try {
      $apc_classloader->register();
      $registered = TRUE;
    } catch (Exception $e) {
    }
  }
  if (!$registered) {
    $loader->register();
  }
sun’s picture

Status: Needs work » Needs review
FileSize
6.23 KB

Test failures seem to be irrelevant.

Regardless of that, slightly revamped this patch, and also filed https://github.com/symfony/symfony/pull/5950

Status: Needs review » Needs work

The last submitted patch, drupal8.classloader.39.patch, failed testing.

sun’s picture

FileSize
74.07 KB

The good news: @fabpot merged https://github.com/symfony/symfony/pull/5950 already. :)

The bad news: This patch causes a 300% slowdown in performance. A single web test that normally takes ~20 secs takes ~60 seconds.

I already checked whether the most current ClassLoader in Symfony contains any noteworthy changes compared to the current in core, but there are none.

The only thing that stands out in the callgrind is an exceptional amount of time being spent in annotation parsing. See attached.

It's possible that this is caused by #1836008: Remove drupal_classloader() use in Drupal\Core\AnnotatedClassDiscovery and we might need to resolve that first.

catch’s picture

Since we blindly use any namespace registered to the classloader, I have a feeling we're scanning everything in vendor/ for plugins. Haven't verified this but it came up when EclipseGc asked me about this issue on irc yesterday.

RobLoach’s picture

Status: Needs work » Needs review
Issue tags: -Performance, -WSCCI

#39: drupal8.classloader.39.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +Performance, +WSCCI

The last submitted patch, drupal8.classloader.39.patch, failed testing.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
6.23 KB

Status: Needs review » Needs work
Issue tags: -Performance, -WSCCI

The last submitted patch, 1658720.patch, failed testing.

Crell’s picture

Status: Needs work » Needs review

#45: 1658720.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +Performance, +WSCCI

The last submitted patch, 1658720.patch, failed testing.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
6.96 KB

Status: Needs review » Needs work

The last submitted patch, 1658720.patch, failed testing.

RobLoach’s picture

FileSize
24.67 KB

Anyone know why this fails? We might need the Bootstrap's Bootstrap fix...

Fabianx’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 1658720.patch, failed testing.

Wim Leers’s picture

[Assetic's classes fail to be loaded] because our classloader decides it's a PEAR-style library rather than being properly namespaced & PSR0 […] in the meantime, i've rolled an updated patch including the two-character fix that makes it work

From #1762204-15: Introduce Assetic compatibility layer for core's internal handling of assets.

RobLoach’s picture

This patch needs an update. Sun's ClassLoader decorator updates have made it into Symfony now too. Hopefully Symfony has been updated in Core by now as well.

dawehner’s picture

Issue tags: +Performance
FileSize
15.44 KB

Rerolled against all the recent changes. I tested a drupal installation and it worked pretty fine.

The original patch contained some "random" changes in some of the composer files, so it seems to be that we should update to recent versions.

Status: Needs review » Needs work

The last submitted patch, drupal-1658720-56.patch, failed testing.

sun’s picture

For everyone following at home:

Fatal error: Call to undefined method Symfony\Component\ClassLoader\ClassLoader::registerPrefixes()
 in /core/lib/Drupal/Core/DrupalKernel.php on line 313
FATAL Drupal\system\Tests\DrupalKernel\DrupalKernelTest: test runner returned a non-zero error code (255).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/vendor/doctrine/common/lib/Doctrine/Common/Annotations/TokenParser.php on line 53
Segmentation fault
FATAL Drupal\comment\Tests\CommentPreviewTest: test runner returned a non-zero error code (139).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php on line 143
FATAL Drupal\text\Tests\TextSummaryTest: test runner returned a non-zero error code (255).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/vendor/doctrine/common/lib/Doctrine/Common/Annotations/TokenParser.php on line 69
FATAL Drupal\text\Tests\TextTranslationTest: test runner returned a non-zero error code (255).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php on line 88
FATAL Drupal\filter\Tests\FilterAdminTest: test runner returned a non-zero error code (255).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php on line 147
FATAL Drupal\system\Tests\Module\ModuleApiTest: test runner returned a non-zero error code (255).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php on line 165
FATAL Drupal\rdf\Tests\RdfaMarkupTest: test runner returned a non-zero error code (255).

Fatal error: Maximum execution time of 500 seconds exceeded
 in /core/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php on line 165
FATAL Drupal\search\Tests\SearchCommentTest: test runner returned a non-zero error code (255).

Fatal error: Cannot redeclare class Drupal\Core\Plugin\Validation\Constraint\PrimitiveTypeConstraint
 in /core/lib/Drupal/Core/Plugin/Validation/Constraint/PrimitiveTypeConstraint.php on line 24
FATAL Drupal\system\Tests\TypedData\TypedDataTest: test runner returned a non-zero error code (255).

1) "Segmentation fault". *ugh*

2) Still a massive slow-down in Annotation parser code/infrastructure. *doubleugh*

3) Fatals on registerPrefixes() and duplicate PrimitiveTypeConstraint class names are most probably real. *tripleugh* ;)

RobLoach’s picture

Status: Needs work » Needs review
FileSize
40.34 KB
RobLoach’s picture

FileSize
10.78 KB

Uploading the correct patch would help.

sun’s picture

+++ b/core/vendor/composer/autoload_namespaces.php
@@ -25,6 +25,9 @@
     'Guzzle\\Http' => $vendorDir . '/guzzle/http/',
     'Guzzle\\Common' => $vendorDir . '/guzzle/common/',
     'EasyRdf_' => $vendorDir . '/easyrdf/easyrdf/lib/',
+    'Drupal\\Driver\\' => $baseDir . '/lib',
+    'Drupal\\Core\\' => $baseDir . '/lib',
+    'Drupal\\Component\\' => $baseDir . '/lib',
     'Doctrine\\Common' => $vendorDir . '/doctrine/common/lib/',
     'Assetic' => $vendorDir . '/kriswallsmith/assetic/src/',

Can you clarify whether this change is auto-generated?

Whatever the technical lookup facility/method is, the vast majority of class file name lookups will be considerably faster when checking for Drupal\Component + Drupal\Core first.

RobLoach’s picture

Everything in core/vendor/composer is auto-generated by Composer.

Status: Needs review » Needs work

The last submitted patch, 1658720-59.patch, failed testing.

RobLoach’s picture

Instead of

+    "psr-0": {
+      "Drupal\\Core\\": "lib",
+      "Drupal\\Component\\": "lib",
+      "Drupal\\Driver\\": "lib"
+    }

It should be:

+    "psr-0": {
+      "Drupal\\Core": "lib",
+      "Drupal\\Component": "lib",
+      "Drupal\\Driver": "lib"
+    }
dawehner’s picture

Status: Needs work » Needs review
Issue tags: -WSCCI
FileSize
1.22 KB
10.76 KB

Let's see whether this last addition should fix it.

chx’s picture

    $class_loader = 'default';
     if (!isset($class_loader) && 

mmmmm.

dawehner’s picture

FileSize
2.03 KB
10.9 KB

Thanks chx!

Status: Needs review » Needs work

The last submitted patch, drupal-1658720-67.patch, failed testing.

chx’s picture

You need to manually load the Drupal\Component\Utility\Settings class. There is no way to avoid that: the classloader depends on it... but that's OK it's very very small.

Edit: sorry for not realizing this earlier, I wasn't awake properly when doing the previous review as it shows in the highly intelligent remark I made there about the code :)

RobLoach’s picture

FileSize
11.35 KB

Good catch, chx.

RobLoach’s picture

Status: Needs work » Needs review
chx’s picture

FileSize
10.84 KB

Putting the require_once into settings(), when settings() might be often called is needlessly slow. And when looking, I found Settings is already manually loaded in drupal_settings_initialize. Just do $class_loader = settings()->get('class_loader', 'default');.

The last submitted patch, 1658720_70.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review

#72: 1658720_70.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +Performance

The last submitted patch, 1658720_70.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
10.85 KB

Just another rerole, though we still struggle with #1658720-41: Use ClassLoader instead of UniversalClassLoader

I try hard to find the real reason, but I didn't succeeded yet.

Status: Needs review » Needs work

The last submitted patch, drupal-1658720-76.patch, failed testing.

jthorson’s picture

Status: Needs work » Needs review

Just me. (Kicking it off the bot so we can test the 5.3.10 upgrade. Has been re-queued on a different bot.)

Status: Needs review » Needs work

The last submitted patch, drupal-1658720-76.patch, failed testing.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
9.88 KB

There are still some follow ups from #1836008: Remove drupal_classloader() use in Drupal\Core\AnnotatedClassDiscovery, so I didn't touch AnnotatedClassDiscovery, but here's an updated patch.

Status: Needs review » Needs work

The last submitted patch, 1658720.patch, failed testing.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
12.09 KB

Splitting the tests into their own respective test functions fixes the issue.

dawehner’s picture

FileSize
1.2 KB
12.1 KB

Just fixing two small nitpicks. This looks really good as it is.

RobLoach’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

sun’s picture

Looks great to me. Thanks all!

Fabianx’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/core/vendor/composer/autoload_namespaces.phpundefined
@@ -6,6 +6,9 @@
+    'Drupal\\Driver' => $baseDir . '/lib/',

I guess this should be 'drivers' instead of $baseDir (=== "core")? At least it looks not equivalent to what was changed.

RobLoach’s picture

FileSize
12.12 KB

Good catch, Fabian. In order to match what was there previously, it should be "../drivers/lib/".

There's a follow up at #1805316: Move composer.json to the project root which would allow us to avoid transversing up a directory.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC

RobLoach’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Performance

This patch needs an update... #87: 1658720.patch queued for re-testing.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 1658720.patch, failed testing.

RobLoach’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Performance
FileSize
12.11 KB

Status: Needs review » Needs work

The last submitted patch, 1658720.patch, failed testing.

RobLoach’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
13.72 KB

Confirmed working on APC.

dawehner’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
2.02 KB

This changes look fine.

RobLoach’s picture

Issue summary: View changes

Updated summary

webchick’s picture

Assigned: Unassigned » catch
Status: Needs review » Reviewed & tested by the community

Seems like catch has been all over this one, so assigning to him.

RobLoach’s picture

Issue tags: -Performance

#93: 1658720.patch queued for re-testing.

RobLoach’s picture

Issue tags: +Performance

#93: 1658720.patch queued for re-testing.

Crell’s picture

Status: Reviewed & tested by the community » Needs work

Guaranteed to need reroll after #1805316: Move composer.json to the project root

webchick’s picture

Assigned: catch » Unassigned

Also, it doesn't look like we ever got fresh benchmarks after we figured out this degraded performance by 300%. Let's do that before re-assigning to catch.

dawehner’s picture

Status: Needs work » Needs review
FileSize
13.75 KB

Comment number 100 and a reroll :)

RobLoach’s picture

Status: Needs review » Needs work
+++ b/composer.jsonundefined
@@ -21,6 +21,13 @@
     "phpunit/phpunit": "3.7.15"
   },
+  "autoload": {
+    "psr-0": {
+      "Drupal\\Core": "lib/",
+      "Drupal\\Component": "lib/",
+      "Drupal\\Driver": "../drivers/lib/"
+    }
+  },
   "minimum-stability": "dev",

Now that composer.json is in the root, it should probably be:

+  "autoload": {
+    "psr-0": {
+      "Drupal\\Core": "core/lib/",
+      "Drupal\\Component": "core/lib/",
+      "Drupal\\Driver": "drivers/lib/"
+    }

I'll be able to re-roll tomorrow if one isn't up by then! :-)

dawehner’s picture

Status: Needs work » Needs review
FileSize
441 bytes
13.75 KB

Oh right, I'm wondering whether we can and should the composer file.

RobLoach’s picture

FileSize
15.04 KB

Re-roll with a couple other new instances.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
1.97 KB

These changes look good.

webchick’s picture

Status: Reviewed & tested by the community » Needs review

Fresh benchmarks?

RobLoach’s picture

#103: 1658720.patch queued for re-testing.

RobLoach’s picture

Reports from xdebug in percentage cost...

UniversalClassLoader (current)

UniversalClassLoader.png

ClassLoader (#103)

ClassLoader.png

As I've said before, although the benchmarks do show improvement, the primary benefit of this is not performance. The primary reason for this is that UniversalClassLoader requires you to register This\Type\Of\Class (how we namespace our classes) and This_Type_Of_Class (PEAR-like) differently (PEAR-like is used in Twig). ClassLoader directly supports PSR-0, which covers both methodologies.

RobLoach’s picture

Issue tags: -Performance

This issue isn't about performance, it's about class loading sanity.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

So back to RTBC.

webchick’s picture

Assigned: Unassigned » catch

Yeah, I understand this issue isn't about performance, but earlier patches showed a 300% slowdown in performance, which is totally unacceptable.

Re-assigning to catch for sign-off, thanks!

catch’s picture

Status: Reviewed & tested by the community » Fixed

This looks much better now. My original objection here was to ditching the APC class loader, I'm not yet convinced that a generated classmap is going to be better than APC for Drupal sites, since we tend to have a very high proportion of un-used classes which I doubt most Symfony projects do, at least not without some customization. This doesn't do that any more though and the diff looks great so committed/pushed to 8.x.

It'd be good if changing the classloader didn't require such a large diff, does there need to be a PSR for the classloaders themselves :(

RobLoach’s picture

Does there need to be a PSR for the classloaders themselves

Not sure if this would be viable since there are so many different ways of loading classes. Definitely worth considering, however. Psr\Log has proved helpful, Psr\Loader\LoaderInterface could be deemed useful as well.

Status: Fixed » Closed (fixed)

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

Anonymous’s picture

Issue summary: View changes

Updated issue summary.