Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve perf in generator cache cases #10577

Merged
merged 7 commits into from
Jul 9, 2024

Conversation

chsienki
Copy link
Contributor

@chsienki chsienki commented Jul 3, 2024

When using the generator cache feature of VBCSCompiler, the additional files and metadata references passed to the generator driver are recreated each time. While the long-term fix is to fix this in VBCSCompiler, previous attempts broke other users, and the fix is quite involved.

In order to allow users to make use of the generator cache feature as-is, this change adds some extra checks for the additional files and metadata references. When they have changed, but their content remains the same, we treat them as being cached.

On large projects this brings significant speed ups when combined with the generator cache feature.

In the IDE these items are reference equal, so these new comparisons won't be used. In compilation scenarios without the cache, nothing is cached, so they are never used. They will only be used in the cases where the user explicitly opts-in to the compiler cache feature.

@chsienki chsienki added the area-compiler Umbrella for all compiler issues label Jul 3, 2024
@chsienki chsienki requested a review from a team as a code owner July 3, 2024 18:59
@@ -74,7 +74,6 @@ private static StaticCompilationTagHelperFeature GetStaticTagHelperFeature(Compi
// the tagHelperFeature will have its Engine property set as part of adding it to the engine, which is used later when doing the actual discovery
var discoveryProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, new VirtualRazorProjectFileSystem(), b =>
{
b.Features.Add(new DefaultMetadataReferenceFeature { References = compilation.References.ToImmutableArray() });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was never actually used, but incurred cost enumerating the references.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't seem to be hooked up on the tooling side. Perhaps we can delete the feature?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, looks like its only tests using it now. Will submit a follow up to clean this up.

if (!compilationA.References.SequenceEqual(compilationB.References))
// when using the generator cache in the compiler its possible to encounter metadata references that are different instances
// but ultimately represent the same underlying assembly. We compare the module version ids to determine if the references are the same
if (!compilationA.References.SequenceEqual(compilationB.References, new LambdaComparer<MetadataReference>((old, @new) =>
Copy link
Member

Choose a reason for hiding this comment

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

new LambdaComparer<MetadataReference>

Should we cache this LambdaComparer in some static field to avoid allocating it on each call?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can't because the internal lambda is capturing the outer compilations.


var result = RunGenerator(compilation!, ref driver)
.VerifyPageOutput(
@"#pragma checksum ""Pages/Index.razor"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""6b5db227a6aa2228c777b0771108b184b1fc5df3""
Copy link
Member

@jjonescz jjonescz Jul 4, 2024

Choose a reason for hiding this comment

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

Could we save this page output which is the same across many tests in some common variable so we don't have to update so many tests when we change codegen?

Alternatively, I think we might not need to verify page output in these new tests at all since their purpose is not to verify the codegen but rather the incrementality of the source generator.

(Or we have .VerifyOutputsMatchBaseline(); that would move the baseline into an automatically-updatable file.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just removed the strings, as we aren't actually testing the codegen here. Agree we should consider moving these tests over to external baselines though.

@chsienki chsienki merged commit b24cd9c into dotnet:main Jul 9, 2024
12 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jul 9, 2024
// also break in those cases, so for now we're okay with this.
var thisHash = AdditionalText.GetText()?.GetContentHash() ?? [];
var otherHash = other?.AdditionalText.GetText()?.GetContentHash() ?? [];
return thisHash.SequenceEqual(otherHash);
Copy link
Member

Choose a reason for hiding this comment

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

i'm not a fan of non-null objects being considered equal to null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-compiler Umbrella for all compiler issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants