perf: reuse argument-free attribute initializer text - #6788
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe source generator now caches initializers for argument-free attributes by attribute type. Tests verify reuse, preservation of explicit arguments, and separation of constructed generic attribute types. ChangesAttribute initializer cache
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~10 minutes Change: Refactor Merge Risk: ⚪ Minimal · up to The initializer cache preserves per-use caller information and the covered argument and generic-type behaviors remain intact. No actionable merge risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. A rabbit finds a cache in bloom Comment |
Greptile SummaryThis PR reduces source-generator allocations by caching argument-free attribute initializer text per constructed attribute type within a compilation.
Confidence Score: 5/5The PR appears safe to merge; no actionable correctness, security, or repository-rule issues were identified. The cached argument-free initializer is determined entirely by its constructed attribute-type key, while all syntax carrying per-application values bypasses the new cache.
|
| Filename | Overview |
|---|---|
| src/TUnit.Core.SourceGenerator/CodeGenerators/Writers/AttributeWriter.cs | Adds a compilation-scoped cache for initializer text whose output is determined solely by the constructed attribute type. |
| tests/TUnit.Core.SourceGenerator.Tests/AttributeInitializerCacheTests.cs | Verifies that argument-free reuse does not affect explicit or named arguments and keeps constructed generic types distinct. |
Reviews (1): Last reviewed commit: "perf: reuse argument-free attribute init..." | Re-trigger Greptile
Review: perf: reuse argument-free attribute initializer text (#6788)Small, well-targeted change. Verified the core correctness question directly against Correctness of the new cache is sound. The new Named/explicit arguments correctly bypass the cache. Constructed generic attribute types are distinguished correctly. Minor, non-blocking observation: Tests: the two new tests ( Nit: the diff drops the UTF-8 BOM at the top of No blocking issues found. The benchmark methodology described in the PR body (byte-identical output validation across cold/edited compilation runs, plus regression tests for constructor-overload/type-argument behavior) is solid support for the allocation-reduction claim. |
Large test suites repeatedly format identical argument-free attribute applications such as
[Test]. Cache the emitted initializer text by constructed attribute type within each compilation, while keeping explicit arguments and named properties on the existing per-application path. Optional caller-info parameters retain the same generated syntax as before.The complete TestMetadataGenerator benchmark (10,000 tests, 100 classes of 100 methods) allocates 12.87 MB less per generation, a 7.8% reduction. Mean elapsed time decreased from 112.5 ms to 107.5 ms, but the timing distributions overlap: this PR claims the allocation improvement, not a statistically established whole-build speedup.
Validation: generator snapshot suite on net10.0 passed (150 passed, one existing skip). Added regression checks for omitted versus explicit/named arguments and different constructed generic attribute types. The benchmark also compares all 100 generated files byte-for-byte between baseline and candidate for both original and edited compilations; output is identical. A separate executable compiled and passed all 10,000 generated tests.
Baseline:
656b66e723. Candidate:706200fd2c(final local-variable rename only after measurement). Generator assemblies built with repository-selected SDK 11.0.100-preview.7.26381.103. Benchmark host uses .NET 10.0.12, Roslyn 4.14.0 and BenchmarkDotNet 0.15.8 on Windows 11 / Intel i7-12700K. Runs are sequential, with no other builds or tests launched by this task during measurement. The separate-process BDN build stalled, so both versions use InProcessEmitToolchain and isolated AssemblyLoadContexts. Compilation construction is outside measurement; each operation runs the full generator from an unrun immutable driver. This measures generator work, not process startup or end-to-end MSBuild time.Reproduce the comparison
Create separate checkouts of the baseline and this PR. In an external working directory, save the project and Program.cs below as GeneratorBench. Use these commands (replace checkout paths):
GeneratorBench.csproj:
Program.cs:
Summary by CodeRabbit