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

Use TemporaryArray<T> instead of ArrayBuilder<T> #48976

Merged
merged 5 commits into from
Nov 30, 2020

Conversation

sharwell
Copy link
Member

@sharwell sharwell commented Oct 28, 2020

This pull requests converts a few uses of ArrayBuilder<T> to TemporaryArray<T> where it is reasonably likely to be beneficial. It is primarily intended for reviewing the overall usability of the new type.

@sharwell sharwell force-pushed the use-temporaryarray branch 2 times, most recently from 24cdec1 to 0725634 Compare October 28, 2020 16:04
@sharwell sharwell marked this pull request as ready for review October 28, 2020 17:32
@sharwell sharwell requested a review from a team as a code owner October 28, 2020 17:32
@@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure
Inherits AbstractSyntaxNodeStructureProvider(Of WhileBlockSyntax)

Protected Overrides Sub CollectBlockSpans(node As WhileBlockSyntax,
spans As ArrayBuilder(Of BlockSpan),
ByRef spans As TemporaryArray(Of BlockSpan),
Copy link
Member

Choose a reason for hiding this comment

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

so, tbh, block structure is theplace i would not expect to see wins. in other words, we're almost always going to be +4 elemetns rights?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm guessing it's going to be perf-neutral for this case, but I like it because it's hit often and helps exercise the non-copyable analyzer we're relying on.

Copy link
Member

Choose a reason for hiding this comment

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

sgtm.

BlockSpanCollector.CollectBlockSpans(
context.Document, syntaxRoot, _nodeProviderMap, _triviaProviderMap, spans, context.CancellationToken);
context.Document, syntaxRoot, _nodeProviderMap, _triviaProviderMap, ref Unsafe.AsRef(in spans), context.CancellationToken);
Copy link
Member

Choose a reason for hiding this comment

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

so i'm not opposed to this. but this feels like it would not actually be an perf improvement. the reason being that near all files will have +4 elements in them. as such, we'll always spill to the builder, so we'll only be adding overhead here.

That said, i'm ok with this due to consistency if we just want to use this almost anywhere, accepting that in some cases we'll have a little extra perf hit. One thing that i would think could be interesting (outside of the scope of this pr) is if we ended up having thread-local pools for our underlying builders. That way we would never have a single problem colliding when we returned the builders.

Copy link
Member Author

Choose a reason for hiding this comment

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

if we ended up having thread-local pools

Once we switch to .NET Core, I plan to rewrite the pool to have processor core-specific first elements hinted by Thread.GetCurrentProcessorId. This will have performance similar to thread local storage but without the corresponding working set increase. TemporaryArray<T> would still be better for small storage since the pool efficiency is reduced as the number of active leases increases.

@sharwell sharwell requested a review from a team as a code owner October 29, 2020 13:29
@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@jaredpar
Copy link
Member

Where can we get a concise description of where TemporaryArray<T> is believed to be better than our traditional builder?

@CyrusNajmabadi
Copy link
Member

Where can we get a concise description of where TemporaryArray is believed to be better than our traditional builder?

@jaredpar it should always be better when the array will have to store 4 or less items. This is for two reasons:

  1. the values are just stored on the stack, and no part of the TempArray will hit the heap.
  2. there is no contention/garbage possibility around pooling. this is because nothing is pulled (or returned) to a pool until you hit 5 elements. This avoids those costs, as well as the (real) garbage cost that arises with pooling when concurrent returns happen and one returned item it overwritten by another returned item.

You can practically think about it as if this gives you a small stackalloc'ed scratch area for lots of small-collection scenarios. Only once you go past that scratch area do you have the same perf costs that you'd have today with normal ArrayBuilder.

@sharwell
Copy link
Member Author

@jaredpar The ArrayBuilder<T> pooling can be really bad on highly multi-core machines. In addition to avoiding data races between cores in the object pool (which improves performance), this change reduces the miss rate for the object pools which improves performance even in cases where TemporaryArray<T> is not used. My guess is TemporaryArray<T> is better for cases where a reasonable percentage of calls have at most 4 elements in the array.

This change does not address the fact that a new builder mutable value type could be created for known fixed-size allocations, which would be ideal for cases following the pattern ImmutableArray.CreateBuilder<T>(int) followed by builder.MoveToImmutable().

@@ -27,7 +27,7 @@
</PropertyGroup>
<PropertyGroup>
<!-- Versions used by several individual references below -->
<RoslynDiagnosticsNugetPackageVersion>3.3.2-beta1.20528.2</RoslynDiagnosticsNugetPackageVersion>
<RoslynDiagnosticsNugetPackageVersion>3.3.2-beta1.20562.1</RoslynDiagnosticsNugetPackageVersion>
Copy link
Member

Choose a reason for hiding this comment

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

What is this update bringing in?

Copy link
Member Author

Choose a reason for hiding this comment

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

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.

Compiler changes LGTM (commit 5)

@sharwell sharwell merged commit 9b50a03 into dotnet:master Nov 30, 2020
@ghost ghost added this to the Next milestone Nov 30, 2020
@sharwell sharwell deleted the use-temporaryarray branch November 30, 2020 19:59
@dibarbet dibarbet modified the milestones: Next, 16.9.P3 Dec 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants