Repository navigation
Conversation
The main process kept all fresh collected data as arrays until the rules on CollectedDataNode had run. On a full analysis that is all the collected data of the project. ParallelAnalyser now writes each batch from a worker to a spool file in the tmpDir and keeps only where each value list is, with its hash. LazyCollectedData reads the spooled part like the cached part, one collector and one file at a time. save() reads the spooled files one at a time. The spool file is deleted when nothing refers to it. The data of a trait is stored under the trait's file and can come in more than one job, so the spool merges those value lists at the end. The order of the files and the hashes are the same as in memory. Editor mode and the single-process analysis keep the data in memory. When the spool cannot be written, the data goes back to memory. Co-Authored-By: Claude Code
…llectors save() opened the spool once for each spooled file. It now opens it once for the whole collected data section. finish() sorted the files of every collector into the order they came in. Only a collector that got a file from an earlier job can be out of that order, so only such a collector is sorted now. Co-Authored-By: Claude Code
save() unserialized every spooled value list and serialized it again. The spool holds the same bytes as the result cache for every collector without paths in its values, so those lists are now copied as they are, with the hash from the spool. Only a collector with paths is serialized again, with the paths made relative. Co-Authored-By: Claude Code
A spool with a random name stayed in the tmpDir for good when the run was killed, for example by a CI timeout. The name now has the process ID, as the temporary file of the result cache has, and a counter for a process that runs more than one analysis. Co-Authored-By: Claude Code
The source is linted on PHP 7.4. Co-Authored-By: Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #6963. That PR streams the cached collected data to the rules on
CollectedDataNode. The fresh data from the workers still stayed in the main process as arrays. On a full analysis, that is all collected data of the project.Main gains
tmpDir. It keeps only where each value list is, with its hash.offloadCollectorDataany more. With this PR,trueandfalseuse the same memory in every scenario.Measurements
A large private codebase (~30k analysed files) with Dead Code Detector, whose rule reads its data with
iterate()(shipmonk-rnd/dead-code-detector#489). Peak memory of the main process:offloadCollectorData: true)offloadCollectorData: falsetruefalseThe time does not change.
All scenarios, times and the setup
Linux CI with 14 CPUs, Dead Code Detector 1.4.2 with its
get()calls replaced byiterate(). Both PHARs are built in the same job from 2.3.x at bcca2b0, without and with this PR. All runs report the same errors.A PHAR built this way does not match the version of the
phpstan_turboextension, so turbo is off in both. That is why a full analysis takes ~170 s here, not ~105 s as with the release PHAR.Peak memory of the main process and wall time:
truetruefalsefalseThe full analysis ran 3–4 times in each mode, alternating the modes. The first full run of each job took ~181 s, in one job with 2.3.x, in the other with this PR. The step after the analysis (the rules on
CollectedDataNodeand the save) took 22.3–23.1 s with this PR and 23.1–23.2 s without it withfalse. Withtrueit varied between 24 and 32 s in both.What changes
CollectedDataSpool(new, internal) writes each value list to the spool file when a worker sends it, and keeps its offset, length and hash. The file is deleted when nothing refers to it.SpooledCollectedData(new, internal) is the index of the spool: collector type → file → offset, length, hash.LazyCollectedDatagets the spooled part next to the cached part and the fresh arrays.iterate(),hashCollector()andtoArray()read it like the cached part.ParallelAnalyserwrites to the spool instead of the arrays.ResultCacheManager::save()copies the spooled value lists into the result cache as they are, one file at a time. Only a collector with paths in its values (CollectorWithPaths) is serialized again, with relative paths. The saved file is the same, byte for byte, as with the arrays.Details:
Known trade-offs
tmpDirfor the duration of the run: about the size of the collected data section of the result cache.Co-Authored-By: Claude Code