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

Fix generator caching in compiler server #57177

Merged
merged 11 commits into from
Dec 9, 2021

Conversation

chsienki
Copy link
Contributor

  • Correctly restore additional files and config providers
  • Enables driver inputs to supply comparers
  • Adds an additional text comparer that allows the driver to determine if two texts are equal
  • Adds tests for the cache inputs

Note We're not comparing the config provider: this means every invocation we'll think it was modified even when it wasn't. I'm thinking about putting in a separate cache for the configs anyway, which would actually fix this, but for now it doesn't matter too much. Although the config provider has changed, the values that come out of it will be the same, so downstream nodes will likely be considered cached as it just produces strings.

@chsienki chsienki requested a review from a team as a code owner October 15, 2021 18:24
@chsienki
Copy link
Contributor Author

@dotnet/roslyn-compiler for review please

@chsienki
Copy link
Contributor Author

@dotnet/roslyn-compiler for a second review please :)

@chsienki
Copy link
Contributor Author

chsienki commented Nov 2, 2021

Rebased onto latest main

@@ -1448,14 +1448,18 @@ private bool WriteTouchedFiles(DiagnosticBag diagnostics, TouchedFileLogger? tou

protected virtual ImmutableArray<AdditionalTextFile> ResolveAdditionalFilesFromArguments(List<DiagnosticInfo> diagnostics, CommonMessageProvider messageProvider, TouchedFileLogger? touchedFilesLogger)
{
var builder = ImmutableArray.CreateBuilder<AdditionalTextFile>();
var builder = ArrayBuilder<AdditionalTextFile>.GetInstance();
var filePaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
Copy link
Member

Choose a reason for hiding this comment

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

Assuming this is the fix for the correctness issue you were debugging. Can you elaborate a bit on this? Does this mean we were seeing the same additional file multiple times?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jaredpar Yeah, specifically the PublicAPI.[Un]Shipped.txt files. They are bought in via our build and also added via the analyzer package. We were failing in our assertion that we succeed when adding to the set here

var added = itemsSet.Add(item);
Debug.Assert(added);
because we're trying to add the same item twice. Previously we didn't catch it because we were doing reference equality rather than content based.

This is obviously a correctness issue: if we don't dedupe then a generator could end up generating the same tree twice for a given additional file.

Copy link
Member

Choose a reason for hiding this comment

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

Where in the command line do we filter out the duplicate files?

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 was about to say you're commenting on it, then I looked at it and also wondered how it was working. Turns out I had a test bug too :(

Now fixed. We expand the paths using the same logic added in #56588 and then compare if they are the same.

@@ -19,17 +19,19 @@ internal sealed class InputNode<T> : IIncrementalGeneratorNode<T>
{
private readonly Func<DriverStateTable.Builder, ImmutableArray<T>> _getInput;
private readonly Action<IIncrementalGeneratorOutputNode> _registerOutput;
private readonly IEqualityComparer<T> _inputComparer;
Copy link
Member

Choose a reason for hiding this comment

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

_inputComparer

When is _inputComparer needed? Isn't CommonCompiler.ResolveAdditionalFilesFromArguments() responsible for dropping duplicates?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ResolveAdditionalFilesFromArguments drops duplicates that are passed in for a single compilation request. The _inputComparer compares between the de-duplicated inputs from this run compared with those from the previous one.

In general we used reference equality to compare additional texts in the compiler, as they are only created once at the start of the compilation request. That's no longer true, because we create a file per-request and have to actually compare content to determine if the file has changed between invocations.

}

[Fact]
public void Compiler_DoesNotCache_Compilation()
Copy link
Member

Choose a reason for hiding this comment

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

DoesNotCache_Compilation

Why isn't the compilation cached?

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 don't even try and compare one compilation to another as its such a deep comparison. Generally the author will select out the parts of interest which will be comparable so the pipeline is likely to cache out fairly early.

@jaredpar's work on compilation determinism may allow us to easily compare the compilation and start caching it.

@chsienki
Copy link
Contributor Author

@cston Any further feedback on this?

@chsienki chsienki force-pushed the source-generators/fix-generator-cache branch from 3b3a155 to 9bb56d7 Compare December 8, 2021 18:54
@chsienki chsienki merged commit e91fd74 into dotnet:main Dec 9, 2021
@ghost ghost added this to the Next milestone Dec 9, 2021
@chsienki chsienki deleted the source-generators/fix-generator-cache branch December 9, 2021 00:04
333fred added a commit to 333fred/roslyn that referenced this pull request Dec 10, 2021
…rations

* upstream/main: (396 commits)
  Update several ExpressionCompiler unit tests for inferred delegate types (dotnet#58203)
  Avoid calculating inferred delegate type unnecessarily in conversions and type inference (dotnet#58115)
  OmniSharp options (dotnet#58208)
  Fix generator caching in compiler server (dotnet#57177)
  Clarify use of null as an initialized value
  BoundDecisionDag.Rewrite - Avoid capturing the replacement map (dotnet#58137)
  Address feedback
  Add regex parser tests
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  Add missing delegate casts (dotnet#58170)
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  Add additional test for another bug report
  ...
@Cosifne Cosifne modified the milestones: Next, 17.1.P3 Jan 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants