Added fast path for single memory ReadableBuffer (#1512)

* Special case single buffer
* Added fast path for single span buffers in UvWriteReq
This commit is contained in:
David Fowler 2017-03-20 00:11:41 -07:00 committed by GitHub
parent 2ed456fd68
commit 39819d6708
2 changed files with 42 additions and 14 deletions

View File

@ -109,12 +109,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
await _outputStream.FlushAsync(); await _outputStream.FlushAsync();
} }
if (buffer.IsSingleSpan)
{
var array = buffer.First.GetArray();
await _outputStream.WriteAsync(array.Array, array.Offset, array.Count);
}
else
{
foreach (var memory in buffer) foreach (var memory in buffer)
{ {
var array = memory.GetArray(); var array = memory.GetArray();
await _outputStream.WriteAsync(array.Array, array.Offset, array.Count); await _outputStream.WriteAsync(array.Array, array.Offset, array.Count);
} }
} }
}
finally finally
{ {
_pipe.Reader.Advance(readResult.Buffer.End); _pipe.Reader.Advance(readResult.Buffer.End);

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
@ -68,10 +67,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Networking
_pins.Add(GCHandle.Alloc(this, GCHandleType.Normal)); _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal));
var nBuffers = 0; var nBuffers = 0;
if (buffer.IsSingleSpan)
{
nBuffers = 1;
}
else
{
foreach (var _ in buffer) foreach (var _ in buffer)
{ {
nBuffers++; nBuffers++;
} }
}
var pBuffers = (Libuv.uv_buf_t*)_bufs; var pBuffers = (Libuv.uv_buf_t*)_bufs;
if (nBuffers > BUFFER_COUNT) if (nBuffers > BUFFER_COUNT)
@ -82,11 +88,24 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Networking
_pins.Add(gcHandle); _pins.Add(gcHandle);
pBuffers = (Libuv.uv_buf_t*)gcHandle.AddrOfPinnedObject(); pBuffers = (Libuv.uv_buf_t*)gcHandle.AddrOfPinnedObject();
} }
if (nBuffers == 1)
{
var memory = buffer.First;
var memoryHandle = memory.Pin();
_handles.Add(memoryHandle);
// Fast path for single buffer
pBuffers[0] = Libuv.buf_init(
(IntPtr)memoryHandle.PinnedPointer,
memory.Length);
}
else
{
var index = 0; var index = 0;
foreach (var memory in buffer) foreach (var memory in buffer)
{ {
// REVIEW: This isn't necessary for our default pool since the memory is // This won't actually pin the buffer since we're already using pinned memory
// already pinned but it also makes tests pass
var memoryHandle = memory.Pin(); var memoryHandle = memory.Pin();
_handles.Add(memoryHandle); _handles.Add(memoryHandle);
@ -96,6 +115,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Networking
memory.Length); memory.Length);
index++; index++;
} }
}
_callback = callback; _callback = callback;
_state = state; _state = state;