-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Avoid NativeOverlapped pinning by allocating unmanaged memory for it #18360
Conversation
| { | ||
| private OverlappedData m_overlappedData; | ||
| private static PinnableBufferCache s_overlappedDataCache = new PinnableBufferCache("System.Threading.OverlappedData", () => new OverlappedData()); | ||
| private OverlappedData _overlappedData; |
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.
The split between Overlapped and OvelappedData is not necessary either anymore. I may be able to eliminate the split as well.
|
Perf results: Synchronous alloc/free is 1.5x faster: for (int i = 0; i < 10000000; i++)
{
var o = new Overlapped();
var p = o.UnsafePack(callback, data);
Overlapped.Free(p);
}Asynchronous alloc/free is 1.1x faster: for (int i = 0; i < 10000000; i++)
{
var o = new Overlapped();
var p = o.UnsafePack(callback, data);
Task.Run(() => { Overlapped.Free(p); });
} |
| Object **pRef = (Object **)pObjRef; | ||
| _ASSERTE(lp2); | ||
| promote_func* callback = (promote_func*)lp2; | ||
| callback(pRef, (ScanContext *)lp1, GC_CALL_PINNED); |
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.
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 don't see how this affects LocalGC... it's just making a callback that's implemented internally by the GC.
sorry I haven't had time to look at the rest of the changes - do you mind explaining why you are not passing the GC_CALL_PINNED flag anymore? if the object is now a native obj, it wouldn't need to call the callback at all - GC is not going to do anything with the object. do we still have Overlapped managed objects at all anymore (or did you split up the native part so the managed part doesn't need to be pinned)? if not then do we still need this async pinned handle type?
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.
We still have Overlapped managed objects with this change, but the ASYNC handles do not pin them anymore - only the data arrays that they are pointing to are pinned by the ASYNC handles with this change.
It is the change in the GC contract: the ASYNC handles were pinning the overlapped objects before this change and they are not pinning the overlapped objects after this change.
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.
ok then if you run with this version of clrgc.dll with an older version of clr.dll it wouldn't work. but this doesn't have to be a breaking change - we could communicate the version of the clr.dll to clrgc.dll and have async pinned handles do different things based on the minor version. but of course this requires some changes in LocalGC. what do you think, @davmason? otherwise you'd need to change the major version (GC_INTERFACE_MAJOR_VERSION) which is probably ok at this point if we think not many people will be using the 2.1 LocalGC anyway.
I know you see a big improvement in a microbenchmark - in real world scenarios the perf problem that these overlapped structures introduce is always about fragmentation and a lot of the fragmentation comes from the data that gets pinned so I am not sure how much improvement you'd see there.
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.
We probably need to rev the major version for 2.2 anyways, so I think we can just accept that and make the 2.2 local gc incompatible with 2.1. There are some other changes too that likely need an api change for 2.2 (like the debugger notifications in #17769). If this were the only issue it might make sense to talk about ways to avoid it, but it seems inevitable at this point.
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.
My primary motivation for this change has been code simplification. I have done the performance measurements just to ensure I am not regressing performance. The improvement was a nice surprise.
I have reved the GC interface version.
| lpOverlapped->Internal = 0; | ||
|
|
||
| if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadPoolIOEnqueue)) | ||
| FireEtwThreadPoolIOEnqueue(lpOverlapped, OBJECTREFToObject(overlapped), false, GetClrInstanceId()); |
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.
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 am not aware of any tooling that would be affected by moving the overlapped structure from the managed to native heap. Thanks for checking.
I suspect that in addition to improved throughput on alloc/free, this will also have a positive impact on the heap in cases where PinnableBufferCache wasn't able to do as well as we would have liked.
|
-2000 lines of code. Perf improvement. Awesome. |
|
@dotnet-bot test Windows_NT x64 Checked corefx_baseline |
|
@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test please ("java.nio.channels.ClosedChannelException") |
|
@dotnet-bot test Windows_NT x64 Checked corefx_baseline |
It makes PinnableBufferCache unnecessary
|
@dotnet-bot test Windows_NT x64 Checked corefx_baseline |
Port dotnet/coreclr#18360 to CoreRT
Port #18360 to CoreRT Signed-off-by: dotnet-bot <[email protected]>
Port #18360 to CoreRT Signed-off-by: dotnet-bot <[email protected]>
Port #18360 to CoreRT Signed-off-by: dotnet-bot <[email protected]>
Port dotnet/coreclr#18360 to CoreRT Signed-off-by: dotnet-bot <[email protected]> Signed-off-by: dotnet-bot-corefx-mirror <[email protected]>
Port dotnet/coreclr#18360 to CoreRT Signed-off-by: dotnet-bot <[email protected]> Signed-off-by: dotnet-bot-corefx-mirror <[email protected]>
| // The split between Overlapped and OverlappedData should not be needed. It is required by the implementation of | ||
| // async GC handles currently. It expects OverlappedData to be a sealed type. | ||
| _overlappedData = new OverlappedData(); | ||
| _overlappedData._overlapped = this; |
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, I'm annotating this for nullability... any reason I can't make OverlappedData's ctor take the Overlapped as an argument? It would allow for the _overlapped field to then be readonly rather than nullable.
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.
OverlappedData's ctor take the Overlapped as an argument
This should be fine. I do not see any issues with it.
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.
Thanks.
…otnet/coreclr#18360) It makes PinnableBufferCache unnecessary Commit migrated from dotnet/coreclr@911d332
Port dotnet/coreclr#18360 to CoreRT Signed-off-by: dotnet-bot <[email protected]> Commit migrated from dotnet/coreclr@108ead4
Fixes #17909