Skip to content

Performance - optimize run with result cache #14072

Open
phpstan/phpstan-src
#5927

Description

@ondrejmirtes

Feature request

What happens with the result cache: we get list of modified files, ExportedNodeResolver decides whether the modifications were only inside function bodies. If not, we also add dependent files to the list of files to analyse. If only function bodies were modified, we only analyse the modified file. Analysis runs for the list of files to analyse, results get merged with the rest from the result cache.

PHPStan only takes a few seconds to compute all this, but we never ran Blackfire to see if there are bottlenecks to conquery. In order to run with result cache even with --debug (to enforce single process), these lines in the ResultCacheManager have to be commented out:

		if ($debug) {
			if ($output->isVeryVerbose()) {
				$output->writeLineFormatted('Result cache not used because of debug mode.');
			}
			return new ResultCache($allAnalysedFiles, true, time(), $this->getMeta($allAnalysedFiles, $projectConfigArray), [], [], [], [], [], [], [], [], [], $currentFileHashes);
		}

Did PHPStan help you today? Did it make you happy in any way?

No response

Activity

  1. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    Patched phpstan/phpstan-src@ac46a7f 2.1.x with

    diff --git a/src/Analyser/ResultCache/ResultCacheManager.php b/src/Analyser/ResultCache/ResultCacheManager.php
    index 3b929cc59e..702d657082 100644
    --- a/src/Analyser/ResultCache/ResultCacheManager.php
    +++ b/src/Analyser/ResultCache/ResultCacheManager.php
    @@ -129,7 +129,7 @@ final class ResultCacheManager
                            }
                            $currentFileHashes[$analysedFile] = $this->getFileHash($analysedFile);
                    }
    -               if ($debug) {
    +               if (false && $debug) {
                            if ($output->isVeryVerbose()) {
                                    $output->writeLineFormatted('Result cache not used because of debug mode.');
                            }

    and analyzing without further file changes (100% result cached) results in

    Image

    -> we are dominated by shipmonks/dead-code-detector

    https://blackfire.io/profiles/2bf8483a-b63f-461b-959d-2d340a554761/graph


    after removing shipmonks/dead-code-detector

    composer remove shipmonk/dead-code-detector
    
    diff --git a/build/phpstan.neon b/build/phpstan.neon
    index 3469b8fca5..235b4f0d3b 100644
    --- a/build/phpstan.neon
    +++ b/build/phpstan.neon
    @@ -4,7 +4,6 @@ includes:
            - ../vendor/phpstan/phpstan-phpunit/extension.neon
            - ../vendor/phpstan/phpstan-phpunit/rules.neon
            - ../vendor/phpstan/phpstan-strict-rules/rules.neon
    -       - ../vendor/shipmonk/dead-code-detector/rules.neon
            - ../conf/bleedingEdge.neon
            - ../phpstan-baseline.neon
            - ../phpstan-baseline.php
    

    .. we are dominated by regex ast analysis when analyzing without further file changes (100% result cached)

    Image

    https://blackfire.io/profiles/7849920b-27d4-4688-9d54-a677ce5a7804/graph


    after a single file change (still shipmonks/dead-code-detector disabled)

    diff --git a/src/Analyser/Error.php b/src/Analyser/Error.php
    index 9af5f2b297..12114a1406 100644
    --- a/src/Analyser/Error.php
    +++ b/src/Analyser/Error.php
    @@ -337,6 +337,7 @@ final class Error implements JsonSerializable
                            $properties['metadata'] ?? [],
                            $properties['fixedErrorDiff'] ?? null,
                    );
    +               $x = 1;
            }
     
            public static function validateIdentifier(string $identifier): bool

    PHPStan\Analyser\FileAnalyserCallback::__invoke() dominates

    Image

    https://blackfire.io/profiles/8e36da86-90ba-4527-a4f8-e7a2c38121f5/graph

  2. ondrejmirtes commented on Feb 14, 2026

    @ondrejmirtes
    MemberAuthor

    Thank you, I wanted data like that.

    after removing shipmonks/dead-code-detector we are dominated by regex ast analysis when analyzing without further file changes (100% result cached)

    This worries me a bit. Is this validating ignoreErrors in neon? That should not be happening if the DIC is compiled.

    Can't think of another reason for this to happen.

  3. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    This worries me a bit. Is this validating ignoreErrors in neon?

    path is (yes its validating ignores)

    Image

    I think the root cause is that the container name changes on some phpstan invocation

  4. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    it does not happen every time, but I can see sometimes a few more variables in the array beeing used for building the container key.

    Image
  5. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    I can reproduce now. it happens after you cd between folders and run PHPStan again.

    see https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html

    OLDPWD
    The previous working directory as set by the cd builtin.

  6. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    I see another case now. the container invalidates as soon as you re-size the shell window, because a ENV var exists which defines the LINES and COLUMNS in the window

    Image
  7. ondrejmirtes commented on Feb 14, 2026

    @ondrejmirtes
    MemberAuthor

    Loo! We could unset it in ResultCacheManager like we do with _ or SHLVL.

  8. ondrejmirtes commented on Feb 14, 2026

    @ondrejmirtes
    MemberAuthor

    So what's slowing it down if dead-code-detector is not there, result cache is up to date, DIC is not regenerated?

  9. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    So what's slowing it down if dead-code-detector is not there, result cache is up to date, DIC is not regenerated?

    phpstan/phpstan-phpunit#277

  10. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    So what's slowing it down if dead-code-detector is not there, result cache is up to date, DIC is not regenerated?

    after all linked PRs are merged we bottleneck on PHPParser and ExistingNamesInUseRule::processNode:

    a)

    Image

    b)

    Image
  11. ondrejmirtes commented on Feb 14, 2026

    @ondrejmirtes
    MemberAuthor

    Be a bit careful about these assumptions, the rule might just be the first to hit something uncached, the ones after it might be at an advantage.

  12. staabm commented on Feb 14, 2026

    @staabm
    Contributor

    php-parsing of phpstorm stubs could maybe be cached. other than that I think we checked all low hanging fruits

  13. ondrejmirtes commented on Feb 14, 2026

    @ondrejmirtes
    MemberAuthor

    Yup, caching could somehow be added around $this->phpstormStubsSourceStubber in BetterReflectionSourceLocatorFactory. Similarly to what I did in OptimizedDirectorySourceLocator and OptimizedSingleFileSourceLocator.

  14. self-assigned this
    on Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions