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 performance of SourceText.LineInfo indexer. #74267

Merged

Conversation

ToddGrun
Copy link
Contributor

@ToddGrun ToddGrun commented Jul 3, 2024

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.

image

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.
@ToddGrun ToddGrun requested a review from a team as a code owner July 3, 2024 23:57
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Jul 3, 2024
// 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)
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, will do!

Copy link
Member

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?

Copy link
Contributor Author

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.

ToddGrun added a commit to ToddGrun/roslyn that referenced this pull request Jul 4, 2024
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).
@ToddGrun
Copy link
Contributor Author

ToddGrun commented Jul 5, 2024

@dotnet/roslyn-compiler -- ptal

Copy link
Member

@333fred 333fred left a 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.

@ToddGrun
Copy link
Contributor Author

@jaredpar -- any remaining concerns / requests?

@ToddGrun
Copy link
Contributor Author

@dotnet/roslyn-compiler for 2nd review

@ToddGrun ToddGrun merged commit 4909767 into dotnet:main Jul 17, 2024
24 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jul 17, 2024
ToddGrun added a commit that referenced this pull request Jul 25, 2024
* 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).
@RikkiGibson RikkiGibson modified the milestones: Next, 17.12 P1 Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants