-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add --apcu-autoloader option to enable APCu caching of found/not-found classes #5559
Conversation
Needs to be rebased now. |
Rebased |
Cheers. LGTM :) |
@@ -624,6 +639,14 @@ public static function getLoader() | |||
CLASSMAPAUTHORITATIVE; | |||
} | |||
|
|||
if ($this->apcu) { | |||
$apcuPrefix = substr(base64_encode(md5(uniqid('', true), true)), 0, -3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we use the $suffix
variable instead of generating another randomized string ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is a valid suggestion. On the other hand, the user can choose to specify a specific value for $suffix
if I am not mistaken. Any chance that could cause issues?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You made the same suggestion on #5172, and I have the same answer :) : suffix doesn't change very often since composer tries to reuse it once dumped. Which means it won't work here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The suffix is there for cache busting APC (#963), the reuse of the suffix was implemented to address #3701. Using a non-deterministic method of generating the cache busting string will introduce a regression of #3701.
Perhaps the autoload generation should be fixed to prevent similar problems down the line, or the prefix should be created deterministically such as a shasum of a generated file.
This would be problematic for the PSR loader, but I feel if you are dynamically adding files to the autoloader, you wouldn't want to cache misses or you should take care to clear the apc entries when the file is created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, people should use either apcu or authoritative classmaps if they want further optimizations than regular classmap generation. They are mutually exclusive it seems, it'd be good to document this but we probably need a new doc/article/autoloading.md or so that details all this because we have slowly a lot of options and trade-offs..
Anyway regarding this point in particular, I don't think it's a regression to #3701 as long as people don't turn on apcu usage, which is fine IMO.
For php5.6+, is there a benefit to APC vs using |
If |
I see that the code path is optional but that doesn't make it less crufty in the composer source :) I am just trying to avoid adding more stuff to the autoloader which is already quite complex. I also see that many people don't add the --classmap-authoritative, but as --apcu is not on by default either, that won't solve the problem that many people don't use either of the flags. If using the former is enough to get the added performance then we need to better educate people, not add more unused flags that do the "same". |
The issue is: is |
Or what about enabling |
It is safe as long as you don't use exclude-from-classmap to exclude classes that you need, because then it can't fallback to the PSR-x autoloader. So for most people it's safe. But for most people I think it's also kinda useless, as it really is only useful if you have a lot of attempts at loading classes that don't exist.. Is that such a common case? |
E.g. SwiftMailer generates misses in composer since it has its own autoloader, or all forward compatible code that do some |
Pull-request material right there :p |
@alcohol That's not really possible unless refactoring a lot SwiftMailer (or using a different library) as the library execute callbacks on class autoload (not possible using Composer autolaoder). |
Fair enough :-) |
Also, just curious, but can the same effect not be achieved using https://symfony.com/doc/current/components/class_loader/cache_class_loader.html ? |
Nope: there is no faster cache than the static array when classes exist. This PR is only for classes that are not found, whereas the linked cache is for both (thus slower & less memory efficient). |
Right, my bad. I totally overlooked the fact that this is for caching of found/not found only. |
@@ -341,6 +341,7 @@ function ($val) { | |||
'sort-packages' => array($booleanValidator, $booleanNormalizer), | |||
'optimize-autoloader' => array($booleanValidator, $booleanNormalizer), | |||
'classmap-authoritative' => array($booleanValidator, $booleanNormalizer), | |||
'apcu' => array($booleanValidator, $booleanNormalizer), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apcu
is too generic as config key IMO. It is not clear this is about the autoloader
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe switch to apcu-autoloader?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming things... if anyone has a better name, please propose. Personally, I'm fine with that name + associated doc :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha I missed your comment while adding mine :) Let's go for apcu-autoloader
@alcohol the fact that other autoloaders can be registered alongside the composer one must be kept. @nicolas-grekas classmap-authoritative is safe as long as your classmap is not missing classes. Here are the things breaking autoloading when enabling it:
IMO, the right fix is to encourage people to enable authoritative mode in production when they are concerned about performance. |
I don't expect people to understand the failing-cases-inventory you just posted above (applies for me: while understand it now, I don't want to remember it). Which means I far prefer a fail safe configuration than a fail hard one (authoritative mode enabled). |
For the current PR I can imagine another way of using APCU: do not ask APCU each time when we need a class name to be resolved. This should be integrated with classmap functionality: we initialize a loader, then ask one APCU/WinCache/etc single key that returns us an array with classmap and set it to the loader, so loader will quickly look at provided classmap and can bypass all the logic of file searching. New keys can be added to the APCU if we don't have them in our classmap. Thoughts? |
@nicolas-grekas the list I posted can be simplified like this:
Note that the second case already works bad today in case the source code changes are done in the middle of the process, due to the missing class caching (the difference is that the next PHP process would see your generated class). |
@lisachenko how would that be better than the current patch? Loading a classmap from apcu is going to be way slower that using PHP7 static array (because it needs unserializing that big array and create it in local memory). |
@lisachenko loading the classmap from APCu won't make things faster than loading the classmap from the OPCache shared memory (where it stays for PHP 5.6+ thanks to optimizations done by @nicolas-grekas). The goal of this PR is to optimize the case of class loader misses, not of class loader matches. |
@nicolas-grekas I'm not sure about the benefit of using small keys for RAM. Typically, one FPM serves several apps (or one app, but from several directories after symlink switching during), each app will use then APCU memory for allocation simultaneously and each allocated block can be aligned not very well, so access time will grow due to slow fragmentation. You argument about big array unserialization probably is not valid because your solution also requires N*string number unserializations. I can bet that one single big array unserialization should be faster. To prevent locks |
Yes, it's the best way ) |
Memory fragmentation occurs when allocating, then unallocating, then reusing the unallocated space again but for a different data size. |
use Symfony\Component\ClassLoader\ApcClassLoader;
$loader = require __DIR__.'/../app/autoload.php';
(new ApcClassLoader('missing_class_', $loader))->register(); |
Do you get the same perf with the decorating loader? Because I'd guess you're hitting apcu for every class being loaded that way instead of an isset() in the classmap. Maybe this doesn't result in a noticeable difference, but I'm curious to know. |
In fact, this is decorating the loader only for misses:
|
But in that case I don't understand what the apc loader is good for if you get the hit of figuring out that composer doesn't know how to load the class anyway? |
Ιndeed, sometimes I feel stupid :) |
Why are you in my email
…On Dec 5, 2016 5:04 PM, "Jordi Boggiano" ***@***.***> wrote:
But in that case I don't understand what the apc loader is good for if you
get the hit of figuring out that composer doesn't know how to load the
class anyway?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#5559 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AVokIzhGkSfx3b5ZyQYkMChvqi-7PFwbks5rFJiOgaJpZM4JXCyv>
.
|
Check the notifications box in the sidebar on this thread, you should be able to unsubscribe from there (or use the link in the email). |
@@ -47,6 +47,7 @@ protected function configure() | |||
new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'), | |||
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), | |||
new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), | |||
new InputOption('apcu', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--apcu-autoloader here too (in all except dump-autoload) would be clearer I guess.
I don't know Jason. Do you also hear the voices in your email? :p Anyway joking aside click the link below and then unsubscribe on the right of this comment.. @nicolas-grekas OK I was kinda hoping you found a magical solution and I wouldn't have to merge this, but I guess not ;) Wrote down a few comments about naming, I think if those are addressed it's mergeable, would be great to have the docs article if you have time too but otherwise no biggie. |
PR updated (test failure unrelated IMHO) |
@@ -105,6 +105,7 @@ resolution. | |||
a bit of time to run so it is currently not done by default. | |||
* **--classmap-authoritative (-a):** Autoload classes from the classmap only. | |||
Implicitly enables `--optimize-autoloader`. | |||
* **--apcu-autloader:** Use APCu to cache found/not-found classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: autoloader
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
…ers (nicolas-grekas) This PR was merged into the 3.3-dev branch. Discussion ---------- [ClassLoader] Deprecate Apc/WinCache/Xcache class loaders | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | yes | Tests pass? | no | Fixed tickets | - | License | MIT | Doc PR | - See composer/composer#5559 Commits ------- fa36e1d [ClassLoader] Deprecate Apc/WinCache/Xcache class loaders
Thanks! Please add some details about apcu tradeoffs (fragmentation, do not combine with --classmap-authoritative, less memory use than optimized classmap?, ..?) to #5947 if you get a chance so it's not lost and someone else can carry on with docs @nicolas-grekas. |
APCu is near perfect for caching classes: it is really fast.
Even when using static arrays on PHP 7 (see #5174),
findFile
can be slow in non authoritative mode because of not-found classes. And when the class map is not dumped (esp. on PHP 5.5 where dumped classes don't scale with the number of classes), using e.g. Symfony's ApcClassLoader in front of composer provides a significant speed boost. Let's inline this knowledge into composer, the only loader that should rule them all :)This PR isn't the same as #5172: instead of decorating the loader, we hook apcu between the class map lookup and the filesystem lookup.
As advised by @lisachenko in https://twitter.com/lisachenko/status/719105126439497728, some use case of APCu can lead to slowness because of memory fragmentation. Yet, not everyone is using APCu in a way that led to fragmentation. And for those (I expect the majority), the speedup is significant.
To keep on the safe side, apcu is enabled as an option with an
--apcu
command line flag.