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

Optimize Intellisense performance #1761

Merged
merged 6 commits into from
Apr 15, 2020

Conversation

SirIntruder
Copy link
Contributor

dotnet/vscode-csharp#3421

Auto complete popup always seemed to have a spotty performance and random delays, so I drilled the problem in VS profiler. Luckily, seems that a lot of it is very low hanging fruit.

2020-04-09_23-58-13

Main culprit seems to be CompletionItemExtensions, which did a complex search on recommendedSymbols times every completionItem in the dropdown. RecommendedSymbols seems like something that should be a very short list, but this still throttles the CPU.

Lesser issue was a collection of string extensions methods used for sorting the resulting competition list. VS (or Rolsynator?) immediately started yelling in red squiggles about using StringComparison everywhere, so I did. Luckily StringExtensions class was only used by Intellisense service, so there are no worries about breaking something else.

Before vs After

bad
good

"Before" gif doesn't capture the "cpu melting noise" part of the experience

@@ -60,9 +60,13 @@ public static async Task<IEnumerable<ISymbol>> GetCompletionSymbolsAsync(this Co
}

// if the completion provider encoded symbols into Properties, we can return them
if (properties.ContainsKey(SymbolName) && properties.ContainsKey(SymbolKind))
if (properties.TryGetValue(SymbolName, out string symbolNameValue)
&& properties.TryGetValue(SymbolKind, out string symbolKindValue)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Calls to the ImmutableDictionary.GetValue<> were the main CPU-hog, now they are cached outside of the loop.

@@ -51,7 +51,7 @@ public async Task<IEnumerable<AutoCompleteResponse>> Handle(AutoCompleteRequest

// get recommended symbols to match them up later with SymbolCompletionProvider
var semanticModel = await document.GetSemanticModelAsync();
var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace);
var recommendedSymbols = (await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace)).ToArray();
Copy link
Contributor Author

@SirIntruder SirIntruder Apr 10, 2020

Choose a reason for hiding this comment

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

Collecting recommendedSymbols into an array, instead of passing Rolsyn's opaque collection type, pulled a lot of weight here. Note that this gets that expensive .Where() call inside the BigN loop (number of elements in the auto complete dropdown).

Actually tried to test with this change only, and it does help a lot, but only does half of the job.

Copy link
Member

@filipw filipw left a comment

Choose a reason for hiding this comment

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

very nice, thanks!

@filipw filipw merged commit 08017b2 into OmniSharp:master Apr 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants