-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
Reduce calls to SplFileInfo::realpath() in the Magento\Setup\Module\Di\Code\Reader\ClassesScanner class #8965
Conversation
…ce in a loop instead of several times. This can have a significant performance impact on large codebases.or slow filesystems.
@kschroeder nice one :) I've tested in on dev setup and for me it went down from 7 to 4 min and on CI server from 2:30 to 46 sec. Much appreciated you've saved quite a few CPU cycles :). |
@piotrkwiecinski Sweet, I was hoping it wasn't just me! :-) |
Nice, verifiable PR with huge benefits! Unfortunately your change in |
@schmengler I updated the PR with a new commit that separates the extract() method. If this one doesn't pass I'll separate the $classNames loop. |
|
The best community ever. Great PR. |
…ce in a loop instead of several times. This can have a significant performance impact on large codebases.or slow filesystems.
… class names. It's like FileScanner except it only cares about namespaces and classes.
Note that I found another 2 minutes or so I could squeeze out of it, which is where those new commits are coming from. However, I found an edge case that is breaking it a little bit so it is not ready to be merged yet. |
… word "class" was in a class. This change will now only return the Namespace\Class up until the first {. Given that there should only be one class per file this should have no effect beyond reducing the potential for problems.
…structures are scanned five times over the course of compilation. /var/generation is excluded.
…y so other unit tests wouldn't break. It just checks to see if /generation/ is in the filename,
@maghamed the PR still needs your approval, please leave feedback. This is an important change and it would be a shame if we don't get it into the next release. |
if ($directoryList === null) { | ||
$directoryList = ObjectManager::getInstance()->get(DirectoryList::class); | ||
} | ||
$this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); |
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.
it's not allowed to make function calls in the constructor, just assignments to class variables.
here we receive $directoryList and after that make a call to get Path
|
||
namespace Magento\Setup\Module\Di\Code\Reader; | ||
|
||
class InvalidFileException extends \InvalidArgumentException |
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.
Custom Exceptions are not recommended to be introduced in each module.
Here is more discussion on this subject - https://github.com/magento/magento2/pull/9315/files#r112514206
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.
For Magento\Setup\Module\Di\Code\Reader\FileClassScanner::__construct
I'd suggest to go with \Magento\Framework\Exception\FileSystemException
. It's used the same way in \Magento\Framework\Filesystem\Directory\Write::assertIsFile
.
For Magento\Setup\Module\Di\Code\Reader\FileClassScanner::isBracedNamespace
, I'm a bit undecided which of the existing exeptions is the best fit. Maybe \Magento\Framework\Exception\NotFoundException
, at least for one of the two cases?
* | ||
* @var 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.
empty line
* Warnings are suppressed for this method due to a micro-optimization that only really shows up when this logic | ||
* is called several millions of times, which can happen quite easily with even moderately sized codebases. | ||
* | ||
* @SuppressWarnings(PHPMD.CyclomaticComplexity) |
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.
So I would like a little guidance on what you would prefer: reduce the individual method complexity or notate MD to ignore CC?
If reducing the method complexity has performance impact, I'd say go for optimized performance in this case and mark the class as ignored.
@schmengler Performance and Complexity are two different metrics. And in this specific case these metrics do not correlate. Because high Cyclomatic complexity doesn't lead to high performance and vice versa.
In Magento we have a rule, that any new code should not have SuppressWarnings for CouplingBetween objects and CyclomaticComplexity. Because it's from the beginning has a Technical Debt.
High CyclomaticComplexity often says that some functionality has not been fully covered with automated testing. Because it's too hard to cover all the possible conditional logic and exit points for this method.
Moreover such code is fragile and really hard to maintain in future.
Some time ago we even actively used CRAP metrics for this.
So, this method should be decomposed on some smaller once
) | ||
); | ||
} | ||
$this->filename = $filename; |
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.
magento constructors should contain just assigments, and no business logic allowed inside
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.
@maghamed I'd like to argue that this is a valid use case according to 2.3.1 of the Technical Guidelines:
2.3.1. Constructor SHOULD throw an exception when validation of an argument has failed.
In the example for 2.3.1, an array of options is validated and an InvalidArgumentException
is thrown if one of the objects in the array doesn't implement a particular interface.
In the given code the provided filename has to be an existing file so for me, this is a valid validation. Which alternative approach would you suggest?
Forget this. I'm done. I have about a thousand other things I need to be working on. |
@kschroeder Thank you for putting so much work into this pull request! I hope we still can get your changes into core because - as @schmengler said - it would be a shame to not have it in future Magento versions. |
@kschroeder I was about to jump to your defense on rewriting that method and I still think it should be accepted and then it can be reworked at any point in the future. Then I checked out the class and I looked at your argument. Taking a method and rewriting it to use internal (to the class) methods, even at 55 million calls, should not make any noticeable difference. I think all of those variables you're declaring in the extract() method are properties of the class. When you call extract(), they represent the state of that object. The class's only purpose is for that method (which is good). I don't care to submit a PR or follow the coding guidelines, but I created a test of what it would look like and how that would affect performance: https://gist.github.com/joshuaadickerson/240f3633d99106fb7aed44a98a0ef0fd It would be interesting to see what the difference between your class and my class are for the build that you said requires 55m calls. |
@maghamed Please can you have a look at the comments I gave on April 23rd? Thanks! |
The PR improves the state of the product. Let's merge. |
…\Setup\Module\Di\Code\Reader\ClassesScanner class #8965
…\Setup\Module\Di\Code\Reader\ClassesScanner class #8965 - fixed code style
…\Setup\Module\Di\Code\Reader\ClassesScanner class #8965 - fixed code style
…\Setup\Module\Di\Code\Reader\ClassesScanner class #8965 - fixed code style
…-27-2024 [Support Tier-4-Kings glo02433] 05.27.2024 Regular delivery of bugfixes and improvements
Reduces calls to SplFileInfo::realpath() in the Magento\Setup\Module\Di\Code\Reader\ClassesScanner class.
Description
I have had issues with fairly slow setup:di:compile calls. In the course of my investigation, I ran the XDebug profiler and found that there were several million calls to SplFileInfo::realpath(). This change reduced my compile time from 9-10 minutes to 3 minutes.
[update]
I have been able to find several 10's of seconds (100+ seconds on my test box) of efficiency to be gained by creating a single extraction class that looks only for the first namespace/class match.
[update]
The single extraction class has been changed so that it now scans the entire PHP source file to find unconventionally defined classes as well
Manual testing scenarios
This test simply reduces the number of system calls on the filesystem. There is a functional change, not a logical change.
Contribution checklist