Skip to content

Avoid recomputing generated sources for the same input#50172

Merged
sharwell merged 5 commits intodotnet:masterfrom
sharwell:cache-sourcetext
Jan 25, 2021
Merged

Avoid recomputing generated sources for the same input#50172
sharwell merged 5 commits intodotnet:masterfrom
sharwell:cache-sourcetext

Conversation

@sharwell
Copy link
Copy Markdown
Contributor

@sharwell sharwell commented Dec 30, 2020

Update CSharpSyntaxGenerator to return the same SourceText instance when Execute is called but the input definition has not changed.

This is immediately beneficial as a standalone change, but produces larger wins in combination with #50171.

For the source generator in Roslyn.sln, this change addresses ~35% of the overhead for repeated invocations of the source generator.

Copy link
Copy Markdown
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

Seems there's some cleanup opportunity; I admit I'm also hesitant that the cache here is a static because it means unloading the generator is a memory leak where we're leaking the rest of the documents, and since the SourceText is held strongly it's not a trivial leak either. I was expecting we'd just do a ConditionalWeakTable keyed on the AdditionalFile or something similar, since I think we had reasonable identity currently working in the system?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can this either have some documentation or use a named tuple to explain what the ImmutableArray<byte> is here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Think we need at least a doc comment explaining that this value is expected to be used from multiple threads

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added comment

Comment on lines 80 to 97
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It looks like each place is being used exactly once; do we need this enum and all the fancy switching? Seems like this would greatly simplify the code. "we'll use it later" doesn't pass muster for me here since we're currently working on API proposals to eliminate the need to do this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(and there's still other writing happening directly in on line 59. Just inlining the cache updating would greatly simplify this code.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Inlined/simplified

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Think we need at least a doc comment explaining that this value is expected to be used from multiple threads

Copy link
Copy Markdown
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

On second thought we should address the leak problem before this goes in -- if the user unloads a solution and then loads something else, the static is going to root megabytes of stuff...forever. If nothing else, that's not going to make leak analysis any easier.

@sharwell
Copy link
Copy Markdown
Contributor Author

sharwell commented Jan 5, 2021

On second thought we should address the leak problem before this goes in

Since this is an opportunistic cache, how about just switching to WeakReference<SyntaxTree>?

@sharwell
Copy link
Copy Markdown
Contributor Author

@jasonmalinowski this is now updated

Copy link
Copy Markdown
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

So change looks good other than that comment that says SetTarget is probably thread-safe. I'm not seeing that supported in documentation. The implementation does look like it's taking a lock here:

https://github.com/dotnet/runtime/blob/e63969dba515a40d35a7a2f993b7d3434cf56a06/src/coreclr/vm/weakreferencenative.cpp#L856

But that's an explicit lock which means the comment is wrong for the reason it's safe.

Comment on lines 63 to 64
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would assume we can find a stronger statement about the thread-safety here? Given my understanding is the WeakReference type creates a GC Handle and has a finalizer to free said handle, that this isn't just a simple pointer assignment.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also, the SetTarget acts a memory barrier which ensures all writes are complete first?

Copy link
Copy Markdown
Contributor Author

@sharwell sharwell Jan 23, 2021

Choose a reason for hiding this comment

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

Also, the SetTarget acts a memory barrier which ensures all writes are complete first?

This doesn't matter. The only safety we need is atomicity.

I verified with @stephentoub that the type is thread safe and am opening a doc bug for it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

➡️ Updated the comment, and filed dotnet/dotnet-api-docs#5276 for the documentation bug

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

@sharwell sharwell merged commit 4345acc into dotnet:master Jan 25, 2021
@ghost ghost added this to the Next milestone Jan 25, 2021
@sharwell sharwell deleted the cache-sourcetext branch January 25, 2021 22:09
@Cosifne Cosifne modified the milestones: Next, 16.9 Jan 27, 2021
@JoeRobich JoeRobich modified the milestones: 16.9, 16.9.P4 Jan 27, 2021
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.

8 participants