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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.

&& int.Parse(symbolKindValue) is int symbolKindInt)
{
return recommendedSymbols.Where(x => x.Name == properties[SymbolName] && (int)x.Kind == int.Parse(properties[SymbolKind])).Distinct();
return recommendedSymbols
.Where(x => (int)x.Kind == symbolKindInt && x.Name.Equals(symbolNameValue, StringComparison.OrdinalIgnoreCase))
.Distinct();
}

return Enumerable.Empty<ISymbol>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.


var isSuggestionMode = completionList.SuggestionModeItem != null;
foreach (var item in completionList.Items)
Expand Down
9 changes: 5 additions & 4 deletions src/OmniSharp.Roslyn/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Linq;

namespace OmniSharp.Extensions
Expand All @@ -16,12 +17,12 @@ public static bool IsValidCompletionStartsWithExactCase(this string completion,

public static bool IsValidCompletionStartsWithIgnoreCase(this string completion, string partial)
{
return completion.ToLower().StartsWith(partial.ToLower());
return completion.StartsWith(partial, StringComparison.OrdinalIgnoreCase);
}

public static bool IsCamelCaseMatch(this string completion, string partial)
{
return new string(completion.Where(c => c >= 'A' && c <= 'Z').ToArray()).StartsWith(partial.ToUpper());
return new string(completion.Where(c => c >= 'A' && c <= 'Z').ToArray()).StartsWith(partial, StringComparison.OrdinalIgnoreCase);
}

public static bool IsSubsequenceMatch(this string completion, string partial)
Expand All @@ -31,7 +32,7 @@ public static bool IsSubsequenceMatch(this string completion, string partial)
return true;
}

if (partial.Length > 1 && completion.ToLowerInvariant().Contains(partial.ToLowerInvariant()))
if (partial.Length > 1 && completion.IndexOf(partial, StringComparison.InvariantCultureIgnoreCase) >= 0)
{
return true;
}
Expand All @@ -54,7 +55,7 @@ private static bool FirstLetterMatches(string word, string match)
return false;
}

return char.ToLowerInvariant(word.First()) == char.ToLowerInvariant(match.First());
return char.ToLowerInvariant(word[0]) == char.ToLowerInvariant(match[0]);
}
}
}