-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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 performance of SourceText.LineInfo indexer. #74267
Improve performance of SourceText.LineInfo indexer. #74267
Conversation
Saw something new in a customer performance profile, a *ton* of time spent in the LSP DidChangeHandler. It's uncertain, but my guess is the customer did a Find/Replace that ended up doing a huge number of edits within the current file. The way the Roslyn didChange handler currently works, it takes each of those edits and creates a new SourceText. (This is something I'm going to pursue in a separate PR). Each of those new source texts ends up calling into ChangedText.GetLinesCore, and subsequently the LineInfo indexer, during the didChangeHandler. This is the method that ends up showing in the profile (23.5 seconds of CPU time in the trace, which was 40% of CPU time in the VS process) The change here is to allow SourceText a way to create TextLine's with a known extent, avoiding the overhead involved with calling the LineInfo indexer.
// Do not use unless you are certain the span you are passing in is valid! | ||
// This was added to allow SourceText's indexer to directly create TextLines | ||
// without the performance implications of calling FromSpan. | ||
internal static TextLine FromKnownSpan(SourceText text, TextSpan span) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add an assert to verify the span in debug mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, will do!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider say FromSpanUnsafe
as a name? Basically and indicator to the caller that they're playing with fire with this method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good idea, changed.
I'm currently investigating a customer profile where didChange notifications are showing very prevalently in CPU time. I've create this PR (dotnet#74267) to help with the underlying performance of creating the SourceText, however, there would still be potentially many source texts created for a single operation. This PR attempts to alleviate that situation by changing the DidChange handler to create a single source text on the input TextDocumentContentChangeEvent array. This array can be quite large, such as when the user does a replace-all or multi-line edit in VS. Roughly 50% of CPU time in the customer profile was spent in our DidChange handler (about 29 seconds of CPU time).
@dotnet/roslyn-compiler -- ptal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM, but I do also like Jared's suggestion of adding Unsafe
to convey the danger of misusing the method.
@jaredpar -- any remaining concerns / requests? |
@dotnet/roslyn-compiler for 2nd review |
* Merge changes from a single DidChange notification I'm currently investigating a customer profile where didChange notifications are showing very prevalently in CPU time. I've create this PR (#74267) to help with the underlying performance of creating the SourceText, however, there would still be potentially many source texts created for a single operation. This PR attempts to alleviate that situation by changing the DidChange handler to create a single source text on the input TextDocumentContentChangeEvent array. This array can be quite large, such as when the user does a replace-all or multi-line edit in VS. Roughly 50% of CPU time in the customer profile was spent in our DidChange handler (about 29 seconds of CPU time).
Saw something new in a customer performance profile, a ton of time spent in the LSP DidChangeHandler. It's uncertain, but my guess is the customer did a Find/Replace that ended up doing a huge number of edits within the current file. The way the Roslyn didChange handler currently works, it takes each of those edits and creates a new SourceText. (This is something I'm going to pursue in a separate PR).
Each of those new source texts ends up calling into ChangedText.GetLinesCore, and subsequently the LineInfo indexer, during the didChangeHandler. This is the method that ends up showing in the profile (23.5 seconds of CPU time in the trace, which was 40% of CPU time in the VS process)
The change here is to allow SourceText a way to create TextLine's with a known extent, avoiding the overhead involved with calling the LineInfo indexer.