-
-
Notifications
You must be signed in to change notification settings - Fork 947
Slow processing type hint of Class::* #7421
Description
Bug report
When updating an internal project from 1.3 to 1.7 phpstan ground to a halt. What used to take a second was taking minutes and on a constrained build server timing out after an hour just running phpstan. The later is extreme and maybe more a problem with the ci runner but I was suddenly blocked. I've generalized and open sourced the relevant parts of the project so it can be reviewed as part of this bug.
After a ton of profiling and bisecting and some red herrings the entire processing was on one line.
With the line:
./vendor/bin/phpstan 244.17s user 0.19s system 99% cpu 4:05.73 total
Without the line:
./vendor/bin/phpstan 1.15s user 0.12s system 92% cpu 1.376 total
What is this terrible line of code? This simple if statement: https://github.com/neclimdul/netsuite-search-iterator/blob/5714f4eac537930b9e55d7c7e1b82bd2d826bd00/src/Exception/StatusFailure.php#L70
The problem seems to be the type of that property. The relevant definition is
https://github.com/netsuitephp/netsuite-php/blob/3c2a5b19c1ab9879a8fc470076261359269098f9/src/Classes/StatusDetail.php#L21-L24
and the referenced types here https://github.com/netsuitephp/netsuite-php/blob/master/src/Classes/StatusDetailCodeType.php
There's something really weird going on here so I'm going to dump everything I've found.
- The profile of this line single line is massive. Without the line line the profile of phpstan running on the project is <1 G. With it is over 13 G.
- Removing the type from the property also fixes the performance.
- The profile signature is a bit hard to narrow down because if the size of the profile and how kcachegrind seems to process it but its clear the time is almost entirely spent in
TypeCombinator::create -> TypeCombinator::remove -> TypeCombinator::intersect -> php::usort. There are 128 calls to ::remove but 499k calls to ::intersect. Kcachegrind and xdebug seem to be unhappy with the trace so some of the time numbers don't make sense but its clear almost all the time seems to be in ::itersect and usort. - there is also a noticable amount of time spent in
isSuperTypeOfcalls from::intersectwith 998k calls.
Code snippet that reproduces the problem
Expected output
Shorter scan of project.
Did PHPStan help you today? Did it make you happy in any way?
This was obviously frustrating taking a lot of time to narrow down and blocking development on this project but in the process of trying to narrow this down I tested it on a lot of vendor projects and found several issues that can be fixed. Also pushed me to finish open sourcing that library. There's always a silver lining if you look for it. 😄