-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Use Pinned Object Heap for MemoryPool #21614
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
Conversation
/// <summary> | ||
/// This handle pins the managed array in memory until the slab is disposed. This prevents it from being | ||
/// relocated and enables any subsections of the array to be used as native memory pointers to P/Invoked API calls. | ||
/// </summary> |
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.
Nice to see that all this code can be removed.
/// </summary> | ||
public bool IsActive => !_isDisposed; | ||
public bool IsActive => PinnedArray != null; | ||
|
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.
I think IDisposable is no longer needed and PinnedArray can be a readonly field.
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.
Is needed to switch off the Slab; which then means its blocks are thrown away rather than returned to the pool (i.e. to take them out of circulation)
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.
Well sorta... since the pool doesn't really shrink; but if it did... 😉
{ | ||
fixed(byte* ptr = slab.PinnedArray) | ||
{ | ||
basePtr = (IntPtr)ptr; |
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.
Perhaps Marshal.UnsafeAddrOfPinnedArrayElement
could be simpler here?
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.
TIL :)
Done.
The alignment
parameter of the pinned allocated doesn't look to be exposed? Otherwise could skip most of the following code also (which 4096 aligns the blocks)
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.
That would be amazing
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.
Hmm. Since pinned objects do not move, alignment would be fairly simple to arrange internally. (compacting would be tricky but that is not an issue)
I could just get objSize + 4096 bytes from the heap and then format that as 2 or 3 objects, with one being the actual result with aligned payload, which I would return, and others immediately becoming garbage, up for reuse.
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.
That would be an API addition though, with all the process attached, as usual.
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.
Can you drive that addition @VSadov ?
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.
I will try. Alignment was already a part of the original "cadillac" proposal for AllocateArray
. Having actual use case would make it easier to argue for the usefullness.
The challenge could be to scope this to just pinned allocations. More general support for aligned allocations is possible, but that is completely different cost.
Squashed to retrigger CI |
Some diagnostics (like SOS stuff) is not yet aware of POH. |
POH is logically in Gen2, so most everything should just work. The only part that exposes SOH/LOH/POH distinction seems to be You can get that data though via |
I already have a work item assigned to me to add POH counters: dotnet/runtime#35424 |
great to see this getting used. do you have a workload you could run and show some before vs after results? |
All of them. We'll see the graphs change but it would be good to get a sense for what metrics would potentially get better so we can monitor those. |
Would be good to expose it in a separate manner so it is can be exposed and monitored (as per page 6 on https://aka.ms/aspnet/benchmarks ) |
POH like LOH is collected as a part of Gen2 (and generally in the background) thus no separate POH or LOH collection counts. (technically POH has no references to other generations and could collect less frequently than Gen2, but not a lot of reasons for doing that) For the size - yes, you can get a POH size chart next to the LOH size chart and would be nice to have. I assume once the counter is added. |
even without separate POH stats you can detect perf changes (if there's any diff that is) and they would show up as % time in GC and/or heap size (reduction in them is the goal of this feature; POH data is just there to help with perf investigation). the idea is if you used to basically allocate all your pinned objects at the beginning of the process with other long lived objects, using this should show virtually no difference. if you have the scenarios described at the beginning of the design doc those are what we expect to see benefits. |
@aspnet-hello benchmark |
Starting 'Default' pipelined plaintext benchmark with session ID '01ed222c5a184bfab34a72897ffb6611'. This could take up to 30 minutes... |
Baseline
PR
|
@aspnet-hello benchmark json |
Can it run an mvc test or something with higher allocations? |
@aspnet-hello benchmark http2 |
Starting 'http2' pipelined plaintext benchmark with session ID '0dff5b4ef5ed4d1280b72bd92bba6a91'. This could take up to 30 minutes... |
Baseline
PR
|
Starting 'json' pipelined plaintext benchmark with session ID '8bc6fb7cd8304755bbf9152ba5892e24'. This could take up to 30 minutes... |
Baseline
PR
|
Thanks! |
what does "Build Time" mean? |
The benchmarking infrastructure builds the PR. |
Allocate in the Pinned Object Heap (new for .NET 5.0) rather than pushing to LOH
Also means Finalizer and
GCHandle
can be dropped fromMemoryPoolSlab
/cc @halter73 @VSadov @Maoni0