Skip to content

Commit

Permalink
Reduce allocations in AbstractRecommendationServiceBasedCompletionPro…
Browse files Browse the repository at this point in the history
…vider.GetSymbolsAsync (#72157)

This method was individually adding items to an ArrayBuilder without it's size configured. Potential issues with the current approach:

1) There could be multiple resizes during the Add calls to get the array to it's final size
2) Very likely the final capacity will exceed the array size, causing an allocation in generating the immutablearray.
3) I was seeing a large number of items in these arrays, causing the array that does get created not to get freed back into the pool.

Instead, if we use the SelectAsArray method, we shouldn't have any extra allocations other than the resultant ImmutableArray.
  • Loading branch information
ToddGrun authored Feb 19, 2024
1 parent 449a170 commit 25aa74d
Showing 1 changed file with 10 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Recommendations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
Expand Down Expand Up @@ -63,18 +62,16 @@ protected sealed override async Task<ImmutableArray<SymbolAndSelectionInfo>> Get

var inferredTypes = context.InferredTypes.Where(t => t.SpecialType != SpecialType.System_Void).ToSet();

using var _ = ArrayBuilder<SymbolAndSelectionInfo>.GetInstance(out var result);

foreach (var symbol in recommendedSymbols.NamedSymbols)
{
// Don't preselect intrinsic type symbols so we can preselect their keywords instead. We will also
// ignore nullability for purposes of preselection -- if a method is returning a string? but we've
// inferred we're assigning to a string or vice versa we'll still count those as the same.
var preselect = inferredTypes.Contains(GetSymbolType(symbol), SymbolEqualityComparer.Default) && !IsInstrinsic(symbol);
result.Add(new SymbolAndSelectionInfo(symbol, preselect));
}

return result.ToImmutable();
return recommendedSymbols.NamedSymbols.SelectAsArray(
static (symbol, args) =>
{
// Don't preselect intrinsic type symbols so we can preselect their keywords instead. We will also
// ignore nullability for purposes of preselection -- if a method is returning a string? but we've
// inferred we're assigning to a string or vice versa we'll still count those as the same.
var preselect = args.inferredTypes.Contains(GetSymbolType(symbol), SymbolEqualityComparer.Default) && !args.self.IsInstrinsic(symbol);
return new SymbolAndSelectionInfo(symbol, preselect);
},
(inferredTypes, self: this));
}
}

Expand Down

0 comments on commit 25aa74d

Please sign in to comment.