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

Reduce allocations in TextDocumentStates.AddRange #75640

Conversation

ToddGrun
Copy link
Contributor

This method was calling ImmutableList.AddRange giving it the result of a Select linq expression. The underlying ImmutableList code doesn't end up special casing that collection type, and thus creates a FallbackWrapper around the enumeration. The FallbackWrapper.Count method uses Enumerable.ToArray to cache a collection object, which ends up

  1. doing the double resize allocation dance pass until done
  2. resizing that final array

This essentially means we've allocated around 3x the amount of memory needed to hold our documentids. Instead, if we use a pooled list, we can generally avoid the allocations completely (the ImmutableList code instead creates a ListOfTWrapper around our List which doesn't need to allocate)

This method is showing up as around 0.8% of allocations in the typing section of the csharp editing speedometer test.

*** allocations that should be removed by this change ***
image

This method was calling ImmutableList.AddRange giving it the result of a Select linq expression. The underlying ImmutableList code doesn't end up special casing that collection type, and thus creates a FallbackWrapper around the enumeration. The FallbackWrapper.Count method uses Enumerable.ToArray to cache a collection object, which ends up

1) doing the double resize allocation dance pass until done
2) resizing that final array

This essentially means we've allocated around 3x the amount of memory needed to hold our documentids. Instead, if we use a pooled list, we can generally avoid the allocations completely (the ImmutableList code instead creates a ListOfTWrapper around our List which doesn't need to allocate)

This method is showing up as around 0.8% of allocations in the typing section of the csharp editing speedometer test.
@ToddGrun ToddGrun requested a review from a team as a code owner October 26, 2024 02:11
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 26, 2024
filePathToDocumentIds: null);
{
using var pooledIds = SharedPools.Default<List<DocumentId>>().GetPooledObject();
var ids = pooledIds.Object;
Copy link
Member

Choose a reason for hiding this comment

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

Worth setting the capacity of this list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I'd rather not unless it shows up. The reasons:

  1. Looks like it would need to ensure the desired size exceeds the existing capacity before setting the capacity, otherwise it may throw
  2. Setting the capacity explicitly avoids the double resizing code in EnsureCapacity. So, without doing that ourselves here, we'd potentially be allocating quite a bit more often.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Going to go ahead and merge, let me know if you would like followup on this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead VSCode
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants