Add CreateFromPinnedArray to System.Memory ref and add tests#28992
Conversation
| GC.Collect(2); | ||
|
|
||
| Assert.Equal((int)pinnedPtr, (int)Unsafe.AsPointer(ref MemoryMarshal.GetReference(pinnedMemory.Span))); | ||
| Assert.NotEqual((int)ptr, (int)Unsafe.AsPointer(ref MemoryMarshal.GetReference(memory.Span))); |
There was a problem hiding this comment.
Is this test appropriate (i.e. it will always pass due to the GC.Collect)? cc @jkotas
| int[] pinnedArray = { 90, 91, 92, 93, 94, 95, 96, 97, 98 }; | ||
| GCHandle handle = GCHandle.Alloc(pinnedArray, GCHandleType.Pinned); | ||
|
|
||
| var memory = new Memory<int>(unpinnedArray, 0, 2); |
There was a problem hiding this comment.
Can you call it unpinnedMemory?
| { | ||
| int[] unpinnedArray = { 90, 91, 92, 93, 94, 95, 96, 97, 98 }; | ||
| int[] pinnedArray = { 90, 91, 92, 93, 94, 95, 96, 97, 98 }; | ||
| GCHandle handle = GCHandle.Alloc(pinnedArray, GCHandleType.Pinned); |
There was a problem hiding this comment.
Can you call it pinnedHandle?
| void* memoryHandlePinnedPtr = pinnedMemory.Pin().Pointer; | ||
|
|
||
| GC.Collect(); | ||
| GC.Collect(2); |
There was a problem hiding this comment.
I don't think this is absolutely guaranteeing that the GC will move the array, and so the test might fail from time to time.
There was a problem hiding this comment.
That's what I thought. In which case, I will remove this Assert (but I will keep the "pinned" components).
| Assert.NotEqual((int)ptr, (int)Unsafe.AsPointer(ref MemoryMarshal.GetReference(memory.Span))); | ||
|
|
||
| Assert.Equal((int)memoryHandlePinnedPtr, (int)handle.AddrOfPinnedObject().ToPointer()); | ||
| Assert.NotEqual((int)memoryHandlePtr, (int)memory.Pin().Pointer); |
There was a problem hiding this comment.
Would it make sense to unpin the arrays (both of them) after the test?
There was a problem hiding this comment.
Do we need to explicitly call Free on the GCHandle? It won't automatically get disposed after the method returns?
It looks like we do:
This GCHandle must be released with Free when it is no longer needed.
| Assert.NotEqual((int)memoryHandlePtr, (int)memory.Pin().Pointer); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
It would be good to have a test that verifies that when memory is created from a prepinned array, it does not cause additional GCHandles to be created during Memory.Pin calls. I am not sure how to write such test, but maybe somebody on the runtime team would know. @jkotas?
There was a problem hiding this comment.
E.g. you would need to start the test in separate process, enable tracing for it, and verify via trace that there was no GC handle allocated. I do not think it is worth the effort with what we have available today. Writing similar tests may become more viable once we have the ability for processes to self-trace.
There was a problem hiding this comment.
Writing similar tests may become more viable once we have the ability for processes to self-trace.
FWIW, we do something similar in a variety of corefx test suites for EventSource-based tracing, e.g.
https://github.com/dotnet/corefx/blob/master/src/System.Net.Security/tests/FunctionalTests/LoggingTest.cs#L31
but assuming GC handle-related tracing doesn't come from an EventSource, as Jan suggests that's going to be a lot more involved.
| public static System.Memory<T> AsMemory<T>(System.ReadOnlyMemory<T> memory) { throw null; } | ||
| public static System.ReadOnlySpan<TTo> Cast<TFrom, TTo>(System.ReadOnlySpan<TFrom> span) where TFrom : struct where TTo : struct { throw null; } | ||
| public static System.Span<TTo> Cast<TFrom, TTo>(System.Span<TFrom> span) where TFrom : struct where TTo : struct { throw null; } | ||
| public static System.Memory<T> CreateFromPinnedArray<T>(T[] array, int start, int length) { throw null; } |
There was a problem hiding this comment.
You're not also removing it from Memory? Are you doing that separately?
There was a problem hiding this comment.
I was thinking of staging the change and removing it after asp.net updates its use. Depending on how quickly they can consume new corefx packages, I might remove it earlier. dotnet/extensions#335
There was a problem hiding this comment.
I wouldn't block (stage) the change this close to the RC deadline. They can make the update as part of the dotnet-maestro-bot PR. /c @pakrym
* Add CreateFromPinnedArray to MemoryMarshal * Address PR feedback: Add a warning remark to CreateFromPinnedArray Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
|
Cherry-picked from mirror PR: #29012 |
| if (_length < 0) | ||
| { | ||
| #if FEATURE_PORTABLE_SPAN | ||
| void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index); |
There was a problem hiding this comment.
I want to highlight a fix for a bug here in Memory.Pin where handle could be null (for portable span, for pre-pinned arrays). Please review.
Tests from this PR caught the bug:
https://mc.dot.net/#/user/ahsonkhan/pr~2Fjenkins~2Fdotnet~2Fcorefx~2Fmaster~2F/test~2Ffunctional~2Fcli~2F/f4b9ba1fd81623c838cc27647936c3569e83aa22/workItem/System.Memory.Tests/analysis/xunit/System.SpanTests.MemoryMarshalTests~2FCreateFromPinnedArrayVerifyPinning
System.SpanTests.MemoryMarshalTests/CreateFromPinnedArrayVerifyPinning
System.InvalidOperationException : Handle is not initialized.
Stack Trace :
at System.Runtime.InteropServices.GCHandle.AddrOfPinnedObject()
at System.Memory`1.Pin() in D:\j\workspace\windows-TGrou---2a8f9c29\src\Common\src\CoreLib\System\Memory.cs:line 358
at System.SpanTests.MemoryMarshalTests.CreateFromPinnedArrayVerifyPinning() in D:\j\workspace\windows-TGrou---2a8f9c29\src\System.Memory\tests\MemoryMarshal\CreateFromPinnedArray.cs:line 140
cc @stephentoub, @KrzysztofCwalina, @jkotas, @GrabYourPitchforks
|
@dotnet-bot test OSX x64 Debug Build |
…corefx#28992) * Add CreateFromPinnedArray to System.Memory ref and add tests * Update CreateFromPinnedArray tests * Removing asserts on unpinned array since there is no guarantee that GC will move it. * Add CreateFromPinnedArray to MemoryMarshal (dotnet/coreclrdotnet/corefx#17500) * Add CreateFromPinnedArray to MemoryMarshal * Address PR feedback: Add a warning remark to CreateFromPinnedArray Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com> * Fixing bug in Memory.Pin and adding API to uapaot baseline Commit migrated from dotnet/corefx@b4d701a
Part of https://github.com/dotnet/corefx/issues/28954
Depends on: dotnet/coreclr#17500
TODO: Update newly added tests to use MemoryMarshal.CreateFromPinnedArraycc @KrzysztofCwalina, @stephentoub, @GrabYourPitchforks, @davidfowl, @pakrym