squizlabs / PHP_CodeSniffer

PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.
BSD 3-Clause "New" or "Revised" License
10.66k stars 1.48k forks source link

Generic/LowerCaseType: improve performance #3839

Closed jrfnl closed 9 months ago

jrfnl commented 1 year ago

Description

Someone reported a performance issue with the Generic.PHP.LowerCaseType sniff to me.

Running the Performance report (PR #3810) over a number of codebases, confirmed that the sniff ranked in the top 10 of "slow" sniffs.

As it was, the sniff would examine all variables it comes across and disregard them if they are not properties or not typed. The "disregard when not a property" was done by catching an exception thrown by the File::getMemberProperties() method.

As the majority of T_VARIABLE tokens in the average file are not property declarations, the File::getMemberProperties() method would be triggered lots and lots of times, with the majority of those times resulting in the need for creating and then catching and throwing away the above mentioned exception.

By changing the logic for the sniff to only look within OO constructs and skip over anything non-property, thus avoiding the unnecessary exception creation, I can see a significant difference in the sniff run time.

Using the test file which was originally shared with me and running the below command on PHP 7.4:

phpcs -ps db.php --standard=Generic --report=source -vvv --sniffs=Generic.PHP.LowercaseType

... yielded the following difference in runtime:

Base time:

        *** START SNIFF PROCESSING REPORT ***
        PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseTypeSniff: 0.3802 secs
        *** END SNIFF PROCESSING REPORT ***

Time with the performance tweak included in this PR:

        *** START SNIFF PROCESSING REPORT ***
        PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseTypeSniff: 0.0113 secs
        *** END SNIFF PROCESSING REPORT ***

Using the performance report to benchmark the improvement with a larger number of files, I see improvement across the board as well:

Command used: phpcs -ps . --extensions=php --ignore=/vendor/ --report=performance --standard=psr12

Output for the Generic.PHP.LowercaseType sniff:

Result PHPCS itself Set of Projects A Set of Projects B Set of Projects C
Nr of Files Scanned 614 4115 25546 2250
Before 0.131587 ( 3.9 %) 1.514729 ( 3.0 %) 5.390167 ( 3.4 %) 0.359674 ( 4.2 %)
After 0.029166 ( 0.9 %) 0.449517 ( 0.9 %) 1.917077 ( 1.2 %) 0.181097 ( 2.2 %)

I've also had a quick look at all other PHPCS native sniffs using the File::getMemberProperties() method. As those are all based on the AbstractVariableSniff, they don't seem to suffer from the same issue, or at least, nowhere near as badly.

I also considered changing the setup of the sniff to start using the AbstractVariableSniff, but considering this particular sniff is also examining functions and type casts, I believe that would make the sniff more complex than necessary.

Suggested changelog entry

Generic.PHP.LowercaseType: improved time-to-result for the sniff

Related issues/external references

N/A

Types of changes

jrfnl commented 1 year ago

This PR will likely conflict with PR #3662 and/or #3833 and either one of those PRs may need rebasing if one of others gets merged first.

jrfnl commented 9 months ago

Closing as replaced by https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/63