-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Allow ArrayPool.Shared devirtualization #20503
Conversation
@dotnet-bot test Windows_NT x64 Checked corefx_baseline |
@AndyAyersMS These changes are working around JIT optimization limitations. Do you think that these optimization limitations are not going to be fixed anytime soon, and we should merge these? |
Ubuntu x64 Checked CoreFX Tests https://github.com/dotnet/coreclr/issues/20507
|
Windows_NT x64 Checked Build and Test (Jit - CoreFx TieredCompilation=0) fail already reported https://github.com/dotnet/coreclr/issues/20373 |
@dotnet-bot test Ubuntu x64 Checked CoreFX Tests |
I'd rather fix this in the jit. I should have time to get this in for 3.0. |
@@ -19,6 +29,11 @@ namespace System.Buffers | |||
/// </remarks> | |||
public abstract class ArrayPool<T> | |||
{ | |||
// Store the shared arraypool in a field of its derived type so the Jit can "see" it when inlining Shared | |||
// and devirtualize its calls. | |||
private readonly static TlsOverPerCoreLockedStacksArrayPool<T> s_arrayPool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkotas, at one point you'd expressed concern about typing this field as anything derived from ArrayPool, as you wanted to allow developers to use reflection to set it as a workaround for the pool keeping lots of state around potentially indefinitely. Are you less concerned about that now that we cull arrays from the pool over time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct.
I have the jit side changes (based on #15783) working, but we still need to make framework changes so that the backing field for If we're willing to trust that tiering will remove the expensive dynamic static init check for frequent renters, then this can simply be something like: @@ -33,7 +33,7 @@ namespace System.Buffers
/// optimized for very fast access speeds, at the expense of more memory consumption.
/// The shared pool instance is created lazily on first access.
/// </remarks>
- public static ArrayPool<T> Shared { get; } = new TlsOverPerCoreLockedStacksArrayPool<T>();
+ public static ArrayPool<T> Shared => TlsOverPerCoreLockedStacksArrayPool<T>.SharedPool;
/// <summary>
/// Creates a new <see cref="ArrayPool{T}"/> instance using default configuration options.
@@ -52,6 +52,8 @@ namespace System.Buffers
private readonly static bool s_trimBuffers = GetTrimBuffers();
+ public static TlsOverPerCoreLockedStacksArrayPool<T> SharedPool { get; } = new TlsOverPerCoreLockedStacksArrayPool<T>(); with no other source changes. If we think it's important to always avoid the class init check we can instead cache specific cases in a non-generic static helper class like in Ben's changes. This caching can be done over in the derived class so no details of the caching spill over into the base. Thoughts? |
Yes, I think it is fine to make this assumption. We should be assuming that the tiering JIT is enabled when doing optimizations like this. |
This should be a private field and I think having it on ArrayPool directly would be better. Something like:
Does that work? |
Added PR for that #20637 Not sure if the direct use of variables in calls to Rent in this PR is still needed? |
No other framework changes are needed once I fix a bit of plumbing in the jit.... otherwise devirt will be blocked by the issue noted #15783 (and that seems to be the case). |
I need to get #20553 merged first as the new jit changes build on that. |
I'll close this one then |
Follow up to #15743
Pre
Commit 1 (crossgen coreclr)
Devirtualized virtual call to ArrayPool'1:Rent; now direct call to TlsOverPerCoreLockedStacksArrayPool'1:Rent [final class]
Devirtualized virtual call to ArrayPool'1:Return; now direct call to TlsOverPerCoreLockedStacksArrayPool'1:Return [final class]
Commit 2 (crossgen coreclr)
Devirtualized virtual call to ArrayPool'1:Rent; now direct call to TlsOverPerCoreLockedStacksArrayPool'1:Rent [final class]
Devirtualized virtual call to ArrayPool'1:Return; now direct call to TlsOverPerCoreLockedStacksArrayPool'1:Return [final class]
@stephentoub @jkotas @AndyAyersMS PTAL