-
-
Notifications
You must be signed in to change notification settings - Fork 363
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
Optimise checking the node types allowed for each rule #6232
Optimise checking the node types allowed for each rule #6232
Conversation
Thanks for proposal! This would be better to have directly in php-parser, as all projects would benefit. Could you share |
A couple of time measurements in my machine:
Regarding adding the code change to |
Thanks 👍 Could you share full E.g. time vendor/bin/rector ↓ vendor/bin/rector 0.64s user 0.28s system 44% cpu 2.108 total |
Timings: Running Rector on the rector-src project: Running Rector on our company project: I am running this on a MacBook Pro with an M1 chip and 16gb of RAM. Php is 8.2.18 |
@carlos-granados I tested locally with only 8gb ram on m1 mac, and can see faster as well 👍 Before
After
|
I added some tests for the |
@samsonasik thanks! Should I go ahead and create a PR in |
I will let @TomasVotruba decide on this first |
I created the PR to add the patch to the |
@carlos-granados Patch merged 👍 |
@TomasVotruba I updated the PR with the patch from |
I thin this is ready to go. Last but not least, I like to ask you @staabm if you have time. Could you run Blackfire before/after this PR? Just to see change in performnace/calls. |
I am on vacation until start of next week |
@staabm no hurry, enjoy your holidays! |
43ac292
to
eaf34a7
Compare
Started some testing but got interrupted. Will continue later today and report back |
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 can confirm this is running consistently faster between 15% and 20% - tested across several codebases on windows 11 and latest macos
great job.
btw: since rector-src seem to have dropped the memory-peak information in the debug output some time ago I was not able to verify whether this PR introduces memory leak or consumes more ram |
assert($visitor instanceof RectorInterface); | ||
foreach ($visitor->getNodeTypes() as $nodeType) { | ||
if (is_a($nodeClass, $nodeType, true)) { | ||
$this->visitorsPerNodeClass[$nodeClass][] = $visitor; |
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.
this code assumes that every rules public function getNodeTypes()
does only return a non-conditional static array.
something like (artificial example)
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
if (phpversion() >= "8") {
return [New_::class];
}
return [ClassLike::class];
}
would break because of the caching.
I don't think its a meaningful BC break, just want to point it out.
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.
That example in particular would not be a problem because phpversion()
returns a single value each time Rector is run. The list of visitors per node type is not cached across runs. But I understand what you mean. In any case I can't think of any case where this function would not return a non-conditional static array
@staabm Thank you for confirmation 👍 Let's give this a try. We need to test downgrade itself + downgraded version before release, so there is a chance this might get reverted. Let's roll :) |
@TomasVotruba thanks, let me know if I can help with the testing of the downgraded version in any way |
@carlos-granados The version is now published. Could you try |
btw: I checked the PHPStan codebase today whether there is a similar problem/opportunity. I think the problem is solved differently in there it seems to work in a way which does not need patching nikic/php-parser and does not rely on inheritance, which decouples the inner working of PHPStan and php-parser internals. maybe that something which can be taken as inspiration to solve this same problem in a more elegant way |
Before this improvement: This is when running Rector on my company's code base, about 1K files and about 100K lines of code |
@staabm PHPStan is able to use this because they don't use the node traverser from the php parser, they use their own traverser and in this way they are able to filter the rules that need to be applied to each node in a way which is similar to what I have added. |
I tested on a project with 4869 files, it has 1 minutes 30 seconds faster 👍 Before v1.2.4 vendor/bin/rector process --clear-cache --dry-run 1629.64s user 49.34s system 651% cpu 4:17.87 total After dev-main vendor/bin/rector process --clear-cache --dry-run 1211.25s user 39.69s system 744% cpu 2:47.94 total |
Numbers on one bigger project 🥳 Before: vendor/bin/rector -n --clear-cache 4735.58s user 111.60s system 983% cpu 8:13.08 total After: vendor/bin/rector -n --clear-cache 2887.89s user 73.34s system 1197% cpu 4:07.38 total |
Modifies the PHP parser node traverser so that it can get a list of the visitors that apply to each node. When the visitors are Rector rules, we can compute which rules apply to each node class and cache this. By doing this we improve the performance of Rector by 20-25% according to my tests
To implement this optimisation we need to patch the PHP parser. In order to make this PR easy to review and test, I have added the patch to the code. If you agree that this code is fine I will create another PR in the
rectorphp/vendor-patches
repository with the patch and modify this PR to link to that patch instead of a local one