Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit a3cb00f

Browse files
committed
Use stack array for pooling
1 parent 7e6d814 commit a3cb00f

File tree

2 files changed

+95
-65
lines changed

2 files changed

+95
-65
lines changed

src/System.IO.Pipelines/src/System.IO.Pipelines.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<Reference Include="System.Memory" />
4848
<Reference Include="System.Resources.ResourceManager" />
4949
<Reference Include="System.Runtime" />
50+
<Reference Include="System.Runtime.CompilerServices.Unsafe" />
5051
<Reference Include="System.Runtime.Extensions" />
5152
<Reference Include="System.Threading" />
5253
<Reference Include="System.Threading.Tasks.Extensions" />

src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs

+94-65
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ public sealed partial class Pipe
4343
private readonly PipeScheduler _writerScheduler;
4444

4545
private int _pooledSegmentCount;
46-
private readonly BufferSegment[] _bufferSegmentPool;
47-
// Temporary list to hold Segments return while being reset
48-
private readonly BufferSegment[] _bufferSegmentsToReturn;
46+
private readonly SegmentAsValue[] _bufferSegmentPool;
4947

5048
private readonly DefaultPipeReader _reader;
5149
private readonly DefaultPipeWriter _writer;
@@ -97,8 +95,7 @@ public Pipe(PipeOptions options)
9795
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.options);
9896
}
9997

100-
_bufferSegmentPool = new BufferSegment[SegmentPoolSize];
101-
_bufferSegmentsToReturn = new BufferSegment[SegmentPoolSize];
98+
_bufferSegmentPool = new SegmentAsValue[SegmentPoolSize];
10299

103100
_operationState = default;
104101
_readerCompletion = default;
@@ -297,66 +294,6 @@ private int GetSegmentSize(int sizeHint, int maxBufferSize = int.MaxValue)
297294
return adjustedToMaximumSize;
298295
}
299296

300-
private BufferSegment CreateSegmentSynchronized()
301-
{
302-
BufferSegment[] segmentPool = _bufferSegmentPool;
303-
lock (segmentPool)
304-
{
305-
int index = _pooledSegmentCount - 1;
306-
if ((uint)index < (uint)segmentPool.Length)
307-
{
308-
_pooledSegmentCount = index;
309-
return segmentPool[index];
310-
}
311-
}
312-
313-
return new BufferSegment();
314-
}
315-
316-
private void ReturnSegments(BufferSegment from, BufferSegment toExclusive)
317-
{
318-
Debug.Assert(from != null);
319-
Debug.Assert(from != toExclusive);
320-
321-
// Reset the Segments and return their data out of lock
322-
BufferSegment[] segmentToReturn = _bufferSegmentsToReturn;
323-
int count = 0;
324-
do
325-
{
326-
BufferSegment next = from.NextSegment;
327-
Debug.Assert(next != null || toExclusive == null);
328-
329-
from.ResetMemory();
330-
331-
if ((uint)count < (uint)segmentToReturn.Length)
332-
{
333-
// Store in temporary list while preforming expensive resets
334-
segmentToReturn[count] = from;
335-
count++;
336-
}
337-
338-
from = next;
339-
} while (from != toExclusive);
340-
341-
// Add the Segments back to pool from the temporary list under lock
342-
BufferSegment[] segmentPool = _bufferSegmentPool;
343-
lock (segmentPool)
344-
{
345-
int index = _pooledSegmentCount;
346-
for (int i = 0; i < count; i++)
347-
{
348-
if ((uint)index < (uint)segmentPool.Length)
349-
{
350-
segmentPool[index] = segmentToReturn[i];
351-
index++;
352-
}
353-
segmentToReturn[i] = null;
354-
}
355-
356-
_pooledSegmentCount = index;
357-
}
358-
}
359-
360297
internal bool CommitUnsynchronized()
361298
{
362299
_operationState.EndWrite();
@@ -1115,5 +1052,97 @@ public void Reset()
11151052
ResetState();
11161053
}
11171054
}
1055+
1056+
private BufferSegment CreateSegmentSynchronized()
1057+
{
1058+
SegmentAsValue[] segmentPool = _bufferSegmentPool;
1059+
lock (segmentPool)
1060+
{
1061+
int index = _pooledSegmentCount - 1;
1062+
if ((uint)index < (uint)segmentPool.Length)
1063+
{
1064+
_pooledSegmentCount = index;
1065+
return segmentPool[index];
1066+
}
1067+
}
1068+
1069+
return new BufferSegment();
1070+
}
1071+
1072+
private void ReturnSegments(BufferSegment from, BufferSegment toExclusive)
1073+
{
1074+
Debug.Assert(from != null);
1075+
Debug.Assert(from != toExclusive);
1076+
1077+
// Reset the Segments and return their data out of lock
1078+
ValueSegmentList segmentsToReturn = default;
1079+
ref var startSegment = ref segmentsToReturn.Segment00;
1080+
int count = 0;
1081+
do
1082+
{
1083+
BufferSegment next = from.NextSegment;
1084+
Debug.Assert(next != null || toExclusive == null);
1085+
1086+
from.ResetMemory();
1087+
1088+
if ((uint)count < (uint)SegmentPoolSize)
1089+
{
1090+
// Store in temporary list while preforming expensive resets
1091+
Unsafe.Add(ref startSegment, count) = from;
1092+
count++;
1093+
}
1094+
1095+
from = next;
1096+
} while (from != toExclusive);
1097+
1098+
// Add the Segments back to pool from the temporary list under lock
1099+
SegmentAsValue[] segmentPool = _bufferSegmentPool;
1100+
lock (segmentPool)
1101+
{
1102+
int index = _pooledSegmentCount;
1103+
for (int i = 0; i < count; i++)
1104+
{
1105+
if ((uint)index < (uint)segmentPool.Length)
1106+
{
1107+
segmentPool[index] = Unsafe.Add(ref startSegment, i);
1108+
index++;
1109+
}
1110+
}
1111+
1112+
_pooledSegmentCount = index;
1113+
}
1114+
}
1115+
1116+
// Used to avoid covariant checks on the array
1117+
private readonly struct SegmentAsValue
1118+
{
1119+
private readonly BufferSegment _bufferSegment;
1120+
public SegmentAsValue(BufferSegment bufferSegment) => _bufferSegment = bufferSegment;
1121+
public static implicit operator SegmentAsValue(BufferSegment b) => new SegmentAsValue(b);
1122+
public static implicit operator BufferSegment(SegmentAsValue s) => s._bufferSegment;
1123+
}
1124+
1125+
// Temporary list to hold Segments return while being reset
1126+
#pragma warning disable CS0649
1127+
private ref struct ValueSegmentList
1128+
{
1129+
public BufferSegment Segment00;
1130+
public BufferSegment Segment01;
1131+
public BufferSegment Segment02;
1132+
public BufferSegment Segment03;
1133+
public BufferSegment Segment04;
1134+
public BufferSegment Segment05;
1135+
public BufferSegment Segment06;
1136+
public BufferSegment Segment07;
1137+
public BufferSegment Segment08;
1138+
public BufferSegment Segment09;
1139+
public BufferSegment Segment10;
1140+
public BufferSegment Segment11;
1141+
public BufferSegment Segment12;
1142+
public BufferSegment Segment13;
1143+
public BufferSegment Segment14;
1144+
public BufferSegment Segment15;
1145+
}
1146+
#pragma warning enable CS0649
11181147
}
11191148
}

0 commit comments

Comments
 (0)