Local int vars converted to stackalloc'ed array for performance measures. Recyclable.Add benchmarks yield 0.42 - 0.45 vs List.Add

This commit is contained in:
mlemanczyk committed 2023-01-29 21:34:14 +01:00
1 parent 7f90fcc969
commit 85fcf69c75
1 file changed
+22 -15
+22 -15
View File
@@ -78,28 +78,35 @@ namespace Recyclable.Collections
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static T[][] SetNewLength(in T[][]? source, int minBlockSize, in long newCapacity, ArrayPool<T[]> memoryBlocksPool, ArrayPool<T> blockArrayPool) protected static T[][] SetNewLength(in T[][]? source, int minBlockSize, in long newCapacity, ArrayPool<T[]> memoryBlocksPool, ArrayPool<T> blockArrayPool)
{ {
var sourceBlockCount = source?.Length ?? 0; const int sourceBlockCount = 0, requiredBlockCount = 1, uninitializedBlocksCount = 2, i = 3;
int requiredBlockCount = (int)(newCapacity / minBlockSize) + (newCapacity % minBlockSize > 0 ? 1 : 0);
T[][] newMemoryBlocks = requiredBlockCount < RecyclableDefaults.MinPooledArrayLength Span<int> localInts = stackalloc int[4]
? new T[requiredBlockCount][] {
: memoryBlocksPool.Rent(requiredBlockCount); source?.Length ?? 0, // sourceBlockCount
(int)(newCapacity / minBlockSize) + (newCapacity % minBlockSize > 0 ? 1 : 0), // requiredBlockCount
0, // uninitializedBlocksCount
0, // i
};
T[][] newMemoryBlocks = localInts[requiredBlockCount] < RecyclableDefaults.MinPooledArrayLength
? new T[localInts[requiredBlockCount]][]
: memoryBlocksPool.Rent(localInts[requiredBlockCount]);
var newMemoryBlocksSpan = new Span<T[]>(newMemoryBlocks); var newMemoryBlocksSpan = new Span<T[]>(newMemoryBlocks);
if (sourceBlockCount > 0) if (localInts[sourceBlockCount] > 0)
{ {
var sourceSpan = new Span<T[]>(source); var sourceSpan = new Span<T[]>(source);
sourceSpan.CopyTo(newMemoryBlocksSpan); sourceSpan.CopyTo(newMemoryBlocksSpan);
if (sourceSpan.Length >= RecyclableDefaults.MinPooledArrayLength) if (localInts[sourceBlockCount] >= RecyclableDefaults.MinPooledArrayLength)
{ {
memoryBlocksPool.Return(source!); memoryBlocksPool.Return(source!);
} }
newMemoryBlocksSpan = newMemoryBlocksSpan[sourceBlockCount..]; newMemoryBlocksSpan = newMemoryBlocksSpan[localInts[sourceBlockCount]..];
} }
int uninitializedBlocksCount = newMemoryBlocksSpan.Length; localInts[uninitializedBlocksCount] = newMemoryBlocksSpan.Length;
if (uninitializedBlocksCount == requiredBlockCount) if (localInts[uninitializedBlocksCount] == localInts[requiredBlockCount])
{ {
if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength) if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength)
{ {
@@ -112,21 +119,21 @@ namespace Recyclable.Collections
} }
newMemoryBlocksSpan = newMemoryBlocksSpan[1..]; newMemoryBlocksSpan = newMemoryBlocksSpan[1..];
uninitializedBlocksCount--; localInts[uninitializedBlocksCount]--;
} }
if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength) if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength)
{ {
for (int i = 0; i < uninitializedBlocksCount; i++) for (localInts[i] = 0; localInts[i] < localInts[uninitializedBlocksCount]; localInts[i]++)
{ {
newMemoryBlocksSpan[i] = blockArrayPool.Rent(minBlockSize); newMemoryBlocksSpan[localInts[i]] = blockArrayPool.Rent(minBlockSize);
} }
} }
else else
{ {
for (int i = 0; i < uninitializedBlocksCount; i++) for (localInts[i] = 0; localInts[i] < localInts[uninitializedBlocksCount]; localInts[i]++)
{ {
newMemoryBlocksSpan[i] = new T[minBlockSize]; newMemoryBlocksSpan[localInts[i]] = new T[minBlockSize];
} }
} }