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

ArrayPool does not resize based on user request #69641

Open
FrediKats opened this issue May 21, 2022 · 3 comments
Open

ArrayPool does not resize based on user request #69641

FrediKats opened this issue May 21, 2022 · 3 comments
Labels
Milestone

Comments

@FrediKats
Copy link

ArrayPool

Description

ArrayPool (TlsOverPerCoreLockedStacksArrayPool) does not resize based on user request. TlsOverPerCoreLockedStacksArrayPool has constant value for arrays buckets. If those number of arrays is not enough then we get GC.AllocateUninitializedArray call:

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs#L24

This approach is good enough if we can take and return array with low delay but can lead to issues in case when we need many arrays for a long time. I compare ArrayPool<T>.Shared and ArrayPool<T>.Create. We ran into a problem while checking solution with genetic algorithm. In our case it needs to allocate about 3000 arrays (with constant size) for one iteration then we return it back to array pool and want to reuse in next iterations.

Repository with reproduce is available here - https://github.com/FrediKats/ArrayPoolAllocationReproduce. You can just run this project as-is and check allocations.

  • .Benchmark contains benchmark source code
  • .MemoryTest contains code that was run under dotMemory

Configuration

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
AMD Ryzen 7 5800H with Radeon Graphics, 1 CPU, 16 logical and 8 physical cores
.NET SDK=7.0.100-preview.4.22252.9
  [Host]     : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
Method UseShared Mean Error StdDev Gen 0 Gen 1 Allocated
Read False 274.1 ms 4.16 ms 5.96 ms - - 5 MB
Read True 292.4 ms 4.52 ms 3.78 ms 4000.0000 2000.0000 39 MB

dotMemory traces

DotMemory trace with changing allocation mode:

image

Allocated objects while we using ArrayPool<Vector2>.Shared:

image

Allocated objects while we using pool form ArrayPool<Vector2>.Create:

image

Analysis

Same issue was mentioned in #52098 (comment).

@FrediKats FrediKats added the tenet-performance Performance related issue label May 21, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label May 21, 2022
@ghost
Copy link

ghost commented May 21, 2022

Tagging subscribers to this area: @dotnet/area-system-buffers
See info in area-owners.md if you want to be subscribed.

Issue Details

ArrayPool

Description

ArrayPool (TlsOverPerCoreLockedStacksArrayPool) does not resize based on user request. TlsOverPerCoreLockedStacksArrayPool has constant value for arrays buckets. If those number of arrays is not enough then we get GC.AllocateUninitializedArray call:

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs#L24

This approach is good enough if we can take and return array with low delay but can lead to issues in case when we need many arrays for a long time. I compare ArrayPool<T>.Shared and ArrayPool<T>.Create. We ran into a problem while checking solution with genetic algorithm. In our case it needs to allocate about 3000 arrays (with constant size) for one iteration then we return it back to array pool and want to reuse in next iterations.

Repository with reproduce is available here - https://github.com/FrediKats/ArrayPoolAllocationReproduce. You can just run this project as-is and check allocations.

  • .Benchmark contains benchmark source code
  • .MemoryTest contains code that was run under dotMemory

Configuration

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
AMD Ryzen 7 5800H with Radeon Graphics, 1 CPU, 16 logical and 8 physical cores
.NET SDK=7.0.100-preview.4.22252.9
  [Host]     : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
Method UseShared Mean Error StdDev Gen 0 Gen 1 Allocated
Read False 274.1 ms 4.16 ms 5.96 ms - - 5 MB
Read True 292.4 ms 4.52 ms 3.78 ms 4000.0000 2000.0000 39 MB

dotMemory traces

DotMemory trace with changing allocation mode:

image

Allocated objects while we using ArrayPool<Vector2>.Shared:

image

Allocated objects while we using pool form ArrayPool<Vector2>.Create:

image

Analysis

Same issue was mentioned in #52098 (comment).

Author: FrediKats
Assignees: -
Labels:

area-System.Buffers, tenet-performance, untriaged

Milestone: -

@En3Tho
Copy link
Contributor

En3Tho commented May 21, 2022

This is specifically why custom Array pool creation api was made, isn't it? Shared array pool is used across whole runtime and is used specifically with quick take-give back in mind.

I doubt that tuning Shared for such a specific use case makes sense.

@AaronRobinsonMSFT
Copy link
Member

/cc @Maoni0 in relation to #52098.

@tannergooding tannergooding removed the untriaged New issue has not been triaged by the area owner label Jul 15, 2022
@tannergooding tannergooding added this to the Future milestone Jul 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants