Skip to content

perf(di:compile): memoize Interception Config scope reads during compilation#40614

Open
SamJUK wants to merge 1 commit intomagento:2.4-developfrom
SamJUK:perf/di-compile-interception-scope-cache
Open

perf(di:compile): memoize Interception Config scope reads during compilation#40614
SamJUK wants to merge 1 commit intomagento:2.4-developfrom
SamJUK:perf/di-compile-interception-scope-cache

Conversation

@SamJUK
Copy link
Copy Markdown
Contributor

@SamJUK SamJUK commented Mar 21, 2026

Description

Interception\Config\Config::generateIntercepted() is called twice during a single setup:di:compile run:

  1. The Interceptors generation phase (Operation\Interception)
  2. The Interception cache generation phase (Operation\InterceptionCache)

Both phases call $this->_reader->read($scope) for each of the ~8 compilation scopes. Each call fully parses and merges all di.xml files for that scope. The di.xml files don't change between the two calls within the same compile run, so the second set of reads is completely redundant.

On a project with 607 di.xml files across 8 scopes, that's ~4,856 file reads and DOM parse operations being done twice, with nearly 5,000 of them wasted.

Fix: add a $scopeReadCache array property to Config. On the first call for a given scope the result is stored; subsequent calls return the cached value. The cache is instance-scoped so it is automatically discarded between separate bin/magento invocations.

This is safe because:

  • di.xml files don't change during a compile run
  • The Config object is a DI singleton for the duration of the process
  • There is no concurrency — both phases run sequentially in the same process

Related Pull Requests

Fixed Issues (if relevant)

Manual testing scenarios

Timing comparison

# Baseline on 2.4-develop
git checkout 2.4-develop
rm -rf generated/ var/cache/
time php bin/magento setup:di:compile --no-ansi 2>&1 | tee /tmp/compile-baseline.txt

# This branch
git checkout perf/di-compile-interception-scope-cache
rm -rf generated/ var/cache/
time php bin/magento setup:di:compile --no-ansi 2>&1 | tee /tmp/compile-patched.txt

To isolate the specific phase:

grep -i "interception cache" /tmp/compile-baseline.txt
grep -i "interception cache" /tmp/compile-patched.txt

On a project with ~400 modules the Interception cache generation phase typically drops from ~1.8–4.6s to ~0.6–1.7s (63–76% reduction).

Output correctness

cp -r generated/ /tmp/generated_patched
git checkout 2.4-develop && rm -rf generated/ var/cache/
php bin/magento setup:di:compile --no-ansi
diff -r /tmp/generated_patched/ generated/   # should produce no output

Benchmarks on real-world projects

Project Interception cache phase before Interception cache phase after Saved
~470 modules, 877 plugins 1.8s 0.6s 1.2s / 67%
~390 modules (Store1) 4.1s 1.0s 3.1s / 76%
~390 modules (Store2) 4.6s 1.7s 2.9s / 63%

Memory impact

Measured on a ~470-module install:

Metric Baseline Patched Delta
PHP working memory at peak 376 MB 386 MB +10 MB (+2.7%)
OS peak RSS 438 MB 467 MB +29 MB (+6.7%)

The ~29 MB increase is the cached scope data (8 scopes × ~3–4 MB each of parsed di.xml config) being retained across both phases instead of discarded and reloaded. For a CLI compile tool this is an acceptable trade-off and well within the typical memory_limit used for compilation.

Questions or comments

Happy to add integration-level coverage if needed. The existing unit test covers the cache behaviour directly.

Contribution checklist

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • README.md files for modified modules are updated — no README changes needed
  • All automated tests passed successfully (all builds are green)

@m2-assistant
Copy link
Copy Markdown

m2-assistant bot commented Mar 21, 2026

Hi @SamJUK. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@ct-prd-pr-scan
Copy link
Copy Markdown

The security team has been informed about this pull request due to the presence of risky security keywords. For security vulnerability reports, please visit Adobe's vulnerability disclosure program on HackerOne or email psirt@adobe.com.

@SamJUK SamJUK force-pushed the perf/di-compile-interception-scope-cache branch from e47db2f to 43ea2dc Compare March 21, 2026 23:07
@SamJUK SamJUK marked this pull request as ready for review March 21, 2026 23:31
…ilation

During setup:di:compile, Interception\Config\Config::generateIntercepted() is
called twice per compile run — once per each of two separate pipeline phases.
Each call invokes $this->_reader->read($scope) for every registered scope,
parsing and merging di.xml files from scratch each time.

The di.xml files do not change between the two calls within a single compile run.
Add a $scopeReadCache keyed by scope name so the XML parse-and-merge happens only
once per scope per process lifetime.

Benchmark results:

| Project     | Interception cache before | Interception cache after | Saving |
|-------------|--------------------------|--------------------------|--------|
| sandbox     | 4.8s                     | 1.8s                     | 63%    |
| ma-griggs   | 8.7s                     | 2.1s                     | 76%    |
| elesi       | 4.6s                     | 1.7s                     | 63%    |

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@SamJUK SamJUK force-pushed the perf/di-compile-interception-scope-cache branch from 43ea2dc to a7cb16c Compare March 21, 2026 23:31
@SamJUK
Copy link
Copy Markdown
Contributor Author

SamJUK commented Mar 22, 2026

@magento run all tests

@engcom-Hotel engcom-Hotel added the Priority: P2 A defect with this priority could have functionality issues which are not to expectations. label Mar 24, 2026
@github-project-automation github-project-automation bot moved this to Pending Review in Pull Requests Dashboard Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Priority: P2 A defect with this priority could have functionality issues which are not to expectations. Progress: pending review

Projects

Status: Pending Review

Development

Successfully merging this pull request may close these issues.

2 participants