Skip to content

Socket.Unix: stackalloc IoVector/GCHandle for multi-buffer send/receives.#37583

Merged
stephentoub merged 4 commits intodotnet:masterfrom
tmds:iov_stackalloc
Jun 11, 2020
Merged

Socket.Unix: stackalloc IoVector/GCHandle for multi-buffer send/receives.#37583
stephentoub merged 4 commits intodotnet:masterfrom
tmds:iov_stackalloc

Conversation

@tmds
Copy link
Member

@tmds tmds commented Jun 8, 2020

@ghost
Copy link

ghost commented Jun 8, 2020

Tagging subscribers to this area: @dotnet/ncl
Notify danmosemsft if you want to be subscribed.

@tmds
Copy link
Member Author

tmds commented Jun 8, 2020

@EgorBo @stephentoub @bbartels thanks for reviewing!

int maxBuffers = buffers.Count;
var handles = new GCHandle[maxBuffers];
var iovecs = new Interop.Sys.IOVector[maxBuffers];
Span<GCHandle> handles = allocOnStack ? stackalloc GCHandle[IovStackThreshold] : new GCHandle[maxBuffers];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since IovStackThreshold is so small, I wonder if it would be worth it to have a dedicated path for a small number of buffers and rather than using pinned GCHandles using fixed. The latter would necessitate writing out a fixed statement for each input, which is why it would need to be a small number, but it generally also has less overhead, in particular it's close to free when a GC doesn't occur, whereas there's always overhead to creating and free'ing GCHandles.

We can start with what you have and subsequently experiment with that if it's deemed a good idea, e.g. if we think two or three buffers for example is the most common case. Then again, this is all the synchronous code path, so maybe we needn't invest a ton in optimizing it further.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like an interesting idea to try. The relative gain will be small due to the high cost of the syscall. Are there some cases where this optimization is performed already in corefx?

Copy link
Member

@stephentoub stephentoub Jun 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there some cases where this optimization is performed already in corefx?

This one's pretty close:

fixed (void* pinnedToken0 = inSecBuffers._item0.Token)
fixed (void* pinnedToken1 = inSecBuffers._item1.Token)
fixed (void* pinnedToken2 = inSecBuffers._item2.Token)
{
// Fix Descriptor pointer that points to unmanaged SecurityBuffers.
inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
// Updated pvBuffer with pinned address. UnmanagedToken takes precedence.
if (inSecBuffers.Count > 2)
{
inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type;
inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length;
inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ?
(IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() :
(IntPtr)pinnedToken2;
}
if (inSecBuffers.Count > 1)
{
inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type;
inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length;
inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ?
(IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() :
(IntPtr)pinnedToken1;
}
if (inSecBuffers.Count > 0)
{
inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type;
inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length;
inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ?
(IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() :
(IntPtr)pinnedToken0;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could have sworn we did something like this for WSABuffers on Windows, but I can't find it now. Likely it was an experiment that never got checked in.

@tmds
Copy link
Member Author

tmds commented Jun 9, 2020

CI shows System.Net.Sockets.Tests Work Item failed, so probably something is wrong with this PR. I'll investigate.

@stephentoub stephentoub reopened this Jun 10, 2020
@stephentoub stephentoub merged commit ab39f23 into dotnet:master Jun 11, 2020
jozkee added a commit that referenced this pull request Aug 15, 2020
…#37583") (#40753)

* Revert " Use clonefile for CopyFile, if available (dotnet/corefx#37583)"

This reverts commit 02ba75a.

* Add unit test

* Disable tests failing in browser-wasm
@karelz karelz added this to the 5.0.0 milestone Aug 18, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 8, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants