Skip to content

feat: add incremental caching#113

Merged
martinothamar merged 6 commits intomartinothamar:mainfrom
TimothyMakkison:incre
Feb 20, 2024
Merged

feat: add incremental caching#113
martinothamar merged 6 commits intomartinothamar:mainfrom
TimothyMakkison:incre

Conversation

@TimothyMakkison
Copy link
Copy Markdown
Contributor

@TimothyMakkison TimothyMakkison commented Sep 22, 2023

Modify CompilationAnalyzer to return an equatable model, skipping the final build and emit stage, improving performance and making the IDE more responsive.

  • Removed public properties from CompilationAnalyzer.
  • State is stored in CompilationModel converting types into equivalent structurally equatable types.
  • Incremental pipeline can cache CompilationModel and skip the emit stage in the future if nothing changes.
  • Added incremental generator tests.

Note that I had to add Mediator.SourceGenerator.Roslyn41 to use WithTrackingName for the tests. This is pretty fragile as changes to Mediator.SourceGenerator.Roslyn40 will not be detected by the tests. This could be solved with compile constant preproccessor sections, although I'm not confident I can add this.

@TimothyMakkison TimothyMakkison marked this pull request as draft September 22, 2023 22:42
@TimothyMakkison TimothyMakkison marked this pull request as ready for review October 28, 2023 20:33
@martinothamar
Copy link
Copy Markdown
Owner

Awesome work! In my experimental branch I think I removed the Roslyn38 project, was trying to simplify. Do you know what version of the SDK is needed for 4.1?

Copy link
Copy Markdown
Owner

@martinothamar martinothamar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience, sorry about the delay here!

A couple of comments, otherwise this looks awesome 🥇
I must admit I don't understand all these Roslyn APIs related to incremental compilation, but you bring benchmarks (which I ran) and tests so LGTM 😄

BenchmarkDotNet=v0.13.1, OS=pop 22.04
AMD Ryzen 5 5600X, 1 CPU, 12 logical and 6 physical cores
.NET SDK=6.0.417
  [Host] : .NET 6.0.25 (6.0.2523.51912), X64 RyuJIT

Job=InProcess  Toolchain=InProcessEmitToolchain  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Cached 13.69 ms 0.053 ms 0.047 ms 265.6250 78.1250 22 MB
Compile 14.89 ms 0.056 ms 0.049 ms 265.6250 265.6250 23 MB
LargeCached 87.59 ms 0.327 ms 0.290 ms 333.3333 166.6667 38 MB
LargeCompile 154.20 ms 0.807 ms 0.755 ms 750.0000 250.0000 77 MB

@TimothyMakkison
Copy link
Copy Markdown
Contributor Author

Thanks for the review, I'll resolve the issues when I have more time over the weekend 👍

I must admit I don't understand all these Roslyn APIs related to incremental compilation

TLDR, each step in a incremental generator (Select, Where, SelectMany), caches the input and output of the previous runs step. By using a custom comparer or object implementing IEquality we can use this behaviour to skip a section of the pipeline if the input object is the same as the last run.

In roslyn equivalent syntax (ie SyntaxNode, InvocationExpressionSyntax) is the same between runs whereas each compilation object will always be different between runs (ITypeSymbol, ISymbol, Compilation) and should not be cached for both performance and logic reasons.

In our case I created a parse step that produces a cacheable object, this lets us skip the output stage.

@martinothamar
Copy link
Copy Markdown
Owner

Thanks! Makes sense

@TimothyMakkison
Copy link
Copy Markdown
Contributor Author

TimothyMakkison commented Jan 1, 2024

Happy new years and thanks for the review, I think I've made all the relevant changes 👍

  • I wen with your suggestion and moved TryParseConfiguration to before the array declaration
  • Added support for Use correct accessibility modifer based on message implementing IRequest etc #131
  • RequestMessageHandlerWrapper is still a little janky. My ide doesn't show linting if the file is in the Models folder, but will lint and show references when moved out. Still no idea why this is happening. It still occurs on a different computer with a fresh install 😩
  • I'm a little concerned that the tests didn't fail when I broke diagnostics or namespace configuration. I'm planning on adding some tests to SnapshotTests. Should I add them in this pr or a different one? This pr is getting a little bloated. See feat: add namespace and diagnostics test #135

Edit: just ran the benchmarks and got drastically different results to yours. Moving TryParseConfiguration doesn't cause this as I get the same results when they are moved back.

Method Mean Error StdDev Median Gen 0 Gen 1 Allocated
Cached 5.296 ms 0.0548 ms 0.0512 ms 5.299 ms 507.8125 156.2500 5 MB
Compile 7.333 ms 0.3460 ms 0.9982 ms 6.686 ms 593.7500 203.1250 6 MB
LargeCached 70.923 ms 0.4671 ms 0.4141 ms 70.743 ms 3875.0000 1500.0000 36 MB
LargeCompile 134.006 ms 0.8707 ms 0.8144 ms 134.052 ms 7500.0000 2500.0000 83 MB

Copy link
Copy Markdown
Owner

@martinothamar martinothamar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finally merging this, thanks for the great work! 😄

@martinothamar martinothamar merged commit 3cfb7be into martinothamar:main Feb 20, 2024
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.

2 participants