Remove noop pin+unpin w/ memory blocks

+ Only use pooled blocks in tests
This commit is contained in:
Ben Adams 2016-04-30 10:01:39 +01:00
parent a31d847719
commit 2aa10a64a2
5 changed files with 10 additions and 76 deletions

View File

@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
var result = _rawSocketInput.IncomingStart(); var result = _rawSocketInput.IncomingStart();
return handle.Libuv.buf_init( return handle.Libuv.buf_init(
result.Pin() + result.End, result.DataArrayPtr + result.End,
result.Data.Offset + result.Data.Count - result.End); result.Data.Offset + result.Data.Count - result.End);
} }

View File

@ -684,14 +684,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
var end = _lockedEnd.Block; var end = _lockedEnd.Block;
if (block == end) if (block == end)
{ {
end.Unpin();
return; return;
} }
while (block.Next != end) while (block.Next != end)
{ {
block = block.Next; block = block.Next;
block.Unpin();
} }
block.Next = null; block.Next = null;
@ -705,7 +703,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
var returnBlock = block; var returnBlock = block;
block = block.Next; block = block.Next;
returnBlock.Unpin();
returnBlock.Pool.Return(returnBlock); returnBlock.Pool.Return(returnBlock);
} }
} }

View File

@ -63,24 +63,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
/// <summary> /// <summary>
/// Called to take a block from the pool. /// Called to take a block from the pool.
/// </summary> /// </summary>
/// <param name="minimumSize">The block returned must be at least this size. It may be larger than this minimum size, and if so,
/// the caller may write to the block's entire size rather than being limited to the minumumSize requested.</param>
/// <returns>The block that is reserved for the called. It must be passed to Return when it is no longer being used.</returns> /// <returns>The block that is reserved for the called. It must be passed to Return when it is no longer being used.</returns>
public MemoryPoolBlock Lease(int minimumSize = MaxPooledBlockLength) public MemoryPoolBlock Lease()
{ {
if (minimumSize > _blockLength)
{
// The requested minimumSize is actually larger then the usable memory of a single block.
// Because this is the degenerate case, a one-time-use byte[] array and tracking object are allocated.
// When this block tracking object is returned it is not added to the pool - instead it will be
// allowed to be garbage collected normally.
return MemoryPoolBlock.Create(
new ArraySegment<byte>(new byte[minimumSize]),
dataPtr: IntPtr.Zero,
pool: this,
slab: null);
}
MemoryPoolBlock block; MemoryPoolBlock block;
if (_blocks.TryDequeue(out block)) if (_blocks.TryDequeue(out block))
{ {

View File

@ -11,18 +11,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
/// </summary> /// </summary>
public class MemoryPoolBlock public class MemoryPoolBlock
{ {
/// <summary>
/// If this block represents a one-time-use memory object, this GCHandle will hold that memory object at a fixed address
/// so it can be used in native operations.
/// </summary>
private GCHandle _pinHandle;
/// <summary> /// <summary>
/// Native address of the first byte of this block's Data memory. It is null for one-time-use memory, or copied from /// Native address of the first byte of this block's Data memory. It is null for one-time-use memory, or copied from
/// the Slab's ArrayPtr for a slab-block segment. The byte it points to corresponds to Data.Array[0], and in practice you will always /// the Slab's ArrayPtr for a slab-block segment. The byte it points to corresponds to Data.Array[0], and in practice you will always
/// use the _dataArrayPtr + Start or _dataArrayPtr + End, which point to the start of "active" bytes, or point to just after the "active" bytes. /// use the DataArrayPtr + Start or DataArrayPtr + End, which point to the start of "active" bytes, or point to just after the "active" bytes.
/// </summary> /// </summary>
private IntPtr _dataArrayPtr; public readonly IntPtr DataArrayPtr;
/// <summary> /// <summary>
/// The array segment describing the range of memory this block is tracking. The caller which has leased this block may only read and /// The array segment describing the range of memory this block is tracking. The caller which has leased this block may only read and
@ -33,8 +27,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
/// <summary> /// <summary>
/// This object cannot be instantiated outside of the static Create method /// This object cannot be instantiated outside of the static Create method
/// </summary> /// </summary>
protected MemoryPoolBlock() protected MemoryPoolBlock(IntPtr dataArrayPtr)
{ {
DataArrayPtr = dataArrayPtr;
} }
/// <summary> /// <summary>
@ -76,20 +71,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
~MemoryPoolBlock() ~MemoryPoolBlock()
{ {
Debug.Assert(!_pinHandle.IsAllocated, "Ad-hoc memory block wasn't unpinned");
Debug.Assert(Slab == null || !Slab.IsActive, "Block being garbage collected instead of returned to pool"); Debug.Assert(Slab == null || !Slab.IsActive, "Block being garbage collected instead of returned to pool");
if (_pinHandle.IsAllocated)
{
// if this is a one-time-use block, ensure that the GCHandle does not leak
_pinHandle.Free();
}
if (Slab != null && Slab.IsActive) if (Slab != null && Slab.IsActive)
{ {
Pool.Return(new MemoryPoolBlock Pool.Return(new MemoryPoolBlock(DataArrayPtr)
{ {
_dataArrayPtr = _dataArrayPtr,
Data = Data, Data = Data,
Pool = Pool, Pool = Pool,
Slab = Slab, Slab = Slab,
@ -97,49 +84,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
} }
} }
/// <summary> internal static MemoryPoolBlock Create(
/// Called to ensure that a block is pinned, and return the pointer to the native address
/// of the first byte of this block's Data memory. Arriving data is read into Pin() + End.
/// Outgoing data is read from Pin() + Start.
/// </summary>
/// <returns></returns>
public IntPtr Pin()
{
Debug.Assert(!_pinHandle.IsAllocated);
if (_dataArrayPtr != IntPtr.Zero)
{
// this is a slab managed block - use the native address of the slab which is always locked
return _dataArrayPtr;
}
else
{
// this is one-time-use memory - lock the managed memory until Unpin is called
_pinHandle = GCHandle.Alloc(Data.Array, GCHandleType.Pinned);
return _pinHandle.AddrOfPinnedObject();
}
}
public void Unpin()
{
if (_dataArrayPtr == IntPtr.Zero)
{
// this is one-time-use memory - unlock the managed memory
Debug.Assert(_pinHandle.IsAllocated);
_pinHandle.Free();
}
}
public static MemoryPoolBlock Create(
ArraySegment<byte> data, ArraySegment<byte> data,
IntPtr dataPtr, IntPtr dataPtr,
MemoryPool pool, MemoryPool pool,
MemoryPoolSlab slab) MemoryPoolSlab slab)
{ {
return new MemoryPoolBlock return new MemoryPoolBlock(dataPtr)
{ {
Data = data, Data = data,
_dataArrayPtr = dataPtr,
Pool = pool, Pool = pool,
Slab = slab, Slab = slab,
Start = data.Offset, Start = data.Offset,

View File

@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
// create and pin each segment being written // create and pin each segment being written
pBuffers[index] = Libuv.buf_init( pBuffers[index] = Libuv.buf_init(
block.Pin() + blockStart, block.DataArrayPtr + blockStart,
blockEnd - blockStart); blockEnd - blockStart);
block = block.Next; block = block.Next;
@ -89,7 +89,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
var block = start.Block; var block = start.Block;
for (var index = 0; index < nBuffers; index++) for (var index = 0; index < nBuffers; index++)
{ {
block.Unpin();
block = block.Next; block = block.Next;
} }