From 85fcf69c755e84210f7132c9397d02d3895a11eb Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Sun, 29 Jan 2023 21:34:14 +0100 Subject: [PATCH] Local int vars converted to stackalloc'ed array for performance measures. Recyclable.Add benchmarks yield 0.42 - 0.45 vs List.Add --- Recyclable.Collections/RecyclableList.cs | 37 ++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/Recyclable.Collections/RecyclableList.cs b/Recyclable.Collections/RecyclableList.cs index 74721a5..d0b8e28 100644 --- a/Recyclable.Collections/RecyclableList.cs +++ b/Recyclable.Collections/RecyclableList.cs @@ -78,28 +78,35 @@ namespace Recyclable.Collections [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static T[][] SetNewLength(in T[][]? source, int minBlockSize, in long newCapacity, ArrayPool memoryBlocksPool, ArrayPool blockArrayPool) { - var sourceBlockCount = source?.Length ?? 0; - int requiredBlockCount = (int)(newCapacity / minBlockSize) + (newCapacity % minBlockSize > 0 ? 1 : 0); + const int sourceBlockCount = 0, requiredBlockCount = 1, uninitializedBlocksCount = 2, i = 3; - T[][] newMemoryBlocks = requiredBlockCount < RecyclableDefaults.MinPooledArrayLength - ? new T[requiredBlockCount][] - : memoryBlocksPool.Rent(requiredBlockCount); + Span localInts = stackalloc int[4] + { + 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(newMemoryBlocks); - if (sourceBlockCount > 0) + if (localInts[sourceBlockCount] > 0) { var sourceSpan = new Span(source); sourceSpan.CopyTo(newMemoryBlocksSpan); - if (sourceSpan.Length >= RecyclableDefaults.MinPooledArrayLength) + if (localInts[sourceBlockCount] >= RecyclableDefaults.MinPooledArrayLength) { memoryBlocksPool.Return(source!); } - newMemoryBlocksSpan = newMemoryBlocksSpan[sourceBlockCount..]; + newMemoryBlocksSpan = newMemoryBlocksSpan[localInts[sourceBlockCount]..]; } - int uninitializedBlocksCount = newMemoryBlocksSpan.Length; - if (uninitializedBlocksCount == requiredBlockCount) + localInts[uninitializedBlocksCount] = newMemoryBlocksSpan.Length; + if (localInts[uninitializedBlocksCount] == localInts[requiredBlockCount]) { if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength) { @@ -112,21 +119,21 @@ namespace Recyclable.Collections } newMemoryBlocksSpan = newMemoryBlocksSpan[1..]; - uninitializedBlocksCount--; + localInts[uninitializedBlocksCount]--; } 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 { - 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]; } }