Skip to content

Fetch the exported nodes of non-analysed files only when the result cache is saved - #6988

Merged
ondrejmirtes merged 1 commit into
2.3.xfrom
editor-mode-startup
Nov 7, 2026
Merged

ondrejmirtes merged 1 commit into
2.3.xfrom
editor-mode-startup

Conversation

@ondrejmirtes

@ondrejmirtes ondrejmirtes commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Since 2.2.13, single-file and editor-mode runs got slower, partly because of 3eb12b6. Its full-analysis save callback in ResultCacheManager::process() called addNonAnalysedExportedNodes() before doSave() checked whether the cache is saved at all. A run on files passed on the command line, or in editor mode (--tmp-file/--instead-of), never saves the result cache. So such a run parsed every non-analysed file the analysed code depends on (scanned files, files reached through the autoloader) for nothing.

doSave() now receives the exported nodes as a callback and calls it only after the checks that decide the cache isn't saved: only files passed, editor mode, errors in the dependencies, internal errors. A run that saves the cache gets exactly the same nodes as before.

Wall time, best of 10 (two rounds of 5, one warm-up each)

2.1.34 2.3.0 2.3.x-dev this PR
wordpress-develop analyse src/index.php 1.41 s 2.54 s 2.56 s 2.32 s
wordpress-develop analyse --debug src/index.php 0.84 s 1.72 s 1.78 s 1.50 s
trivial file analyse -l 5 test.php 0.77 s 1.66 s 1.79 s 1.80 s

src/index.php requires 4 files, and their exported nodes are no longer fetched. The trivial file depends on nothing, so it doesn't change. This PR doesn't fix the rest of the gap to 2.1.34. Most of it is OPcache: the restart activates it, and compiling PHPStan into it costs about 0.45 s per process (main process and spawned worker), which a one-file run never earns back.

Setup: PHP 8.4.27 NTS on Linux x86_64, 16 cores, OPcache loaded but off for CLI (the default). 2.1.34 and 2.3.0 are the release PHARs. 2.3.x-dev (ec1df78) and this PR were built the same way (compiler/bin/prepare + box + resign.php, as in phar.yml), without a turbo binary next to them. wordpress-develop uses its own phpstan.neon.dist (level 5). For 2.1.34 it ran in a copy with phpstan-phpunit 2.0.12 / phpstan-strict-rules 2.0.7 and phpVersion.max: 80599, because the current versions of those require 2.3.

Locally: make phpstan, and tests/PHPStan/{Analyser/ResultCache,Command,Parallel}.

…ache is saved

The full-analysis save callback fetched them before doSave() decided not to
save at all - a run on files passed on the command line or in editor mode
never saves - so every such run parsed each file the analysed code depends on
for nothing. doSave() now receives them as a callback and calls it only once
the cache is known to be saved.

WordPress src/index.php, which requires four files: 0.98 s -> 0.70 s with
--debug and PHPSTAN_RESTART=none.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1b250-30d4-72bb-8d3e-b0687619f435
@ondrejmirtes ondrejmirtes changed the title Speed up single-file and editor-mode runs: skip unsaved exported nodes and OPcache that can't pay off Fetch the exported nodes of non-analysed files only when the result cache is saved Nov 7, 2026
@ondrejmirtes
ondrejmirtes merged commit 543dd29 into 2.3.x Nov 7, 2026
568 checks passed
@ondrejmirtes
ondrejmirtes deleted the editor-mode-startup branch November 7, 2026 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant