Merge branch 'recyclable-block-list-added'

This commit is contained in:
mlemanczyk committed 2023-06-10 12:07:53 +02:00
commit 1c8d1998f5
82 files changed
+17135 -1057

No files matched your search

@@ -0,0 +1,51 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_Add()
{
var data = TestObjects;
var dataCount = TestObjectCount;
var list = new List<long>();
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
public void PooledList_Add()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new PooledList<long>(ClearMode.Auto);
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
public void RecyclableList_Add()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new RecyclableList<long>();
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
public void RecyclableLongList_Add()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new RecyclableLongList<long>();
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
}
}
@@ -0,0 +1,35 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_AddRangeWhenSourceIsArray()
{
var data = TestObjects;
var list = new List<long>();
list.AddRange(data);
}
public void PooledList_AddRangeWhenSourceIsArray()
{
var data = TestObjects;
using var list = new PooledList<long>(capacity: TestObjectCount, ClearMode.Auto);
list.AddRange(data);
}
public void RecyclableList_AddRangeWhenSourceIsArray()
{
var data = TestObjects;
using var list = new RecyclableList<long>();
list.AddRange(data);
}
public void RecyclableLongList_AddRangeWhenSourceIsArray()
{
var data = TestObjects;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
list.AddRange(data);
}
}
}
@@ -0,0 +1,35 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_AddRangeWhenSourceIsIEnumerable()
{
var data = TestObjectsAsIEnumerable;
var list = new List<long>();
list.AddRange(data);
}
public void PooledList_AddRangeWhenSourceIsIEnumerable()
{
var data = TestObjectsAsIEnumerable;
using var list = new PooledList<long>(capacity: TestObjectCount, ClearMode.Auto);
list.AddRange(data);
}
public void RecyclableList_AddRangeWhenSourceIsIEnumerable()
{
var data = TestObjectsAsIEnumerable;
using var list = new RecyclableList<long>();
list.AddRange(data);
}
public void RecyclableLongList_AddRangeWhenSourceIsIEnumerable()
{
var data = TestObjectsAsIEnumerable;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
list.AddRange(data);
}
}
}
@@ -0,0 +1,35 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_AddRangeWhenSourceIsIList()
{
var data = (IList<long>)TestObjectsAsRecyclableLongList;
var list = new List<long>();
list.AddRange(data);
}
public void PooledList_AddRangeWhenSourceIsIList()
{
var data = (IList<long>)TestObjectsAsPooledList;
using var list = new PooledList<long>(capacity: TestObjectCount, ClearMode.Auto);
list.AddRange(data);
}
public void RecyclableList_AddRangeWhenSourceIsIList()
{
var data = (IList<long>)TestObjectsAsRecyclableLongList;
using var list = new RecyclableList<long>();
list.AddRange(data);
}
public void RecyclableLongList_AddRangeWhenSourceIsIList()
{
var data = (IList<long>)TestObjectsAsRecyclableLongList;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
list.AddRange(data);
}
}
}
@@ -0,0 +1,35 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_AddRangeWhenSourceIsList()
{
var data = TestObjectsAsList;
var list = new List<long>();
list.AddRange(data);
}
public void PooledList_AddRangeWhenSourceIsList()
{
var data = TestObjectsAsList;
using var list = new PooledList<long>(capacity: TestObjectCount, ClearMode.Auto);
list.AddRange(data);
}
public void RecyclableList_AddRangeWhenSourceIsList()
{
var data = TestObjectsAsList;
using var list = new RecyclableList<long>();
list.AddRange(data);
}
public void RecyclableLongList_AddRangeWhenSourceIsList()
{
var data = TestObjectsAsList;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
list.AddRange(data);
}
}
}
@@ -0,0 +1,28 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void PooledList_AddRangeWhenSourceIsPooledList()
{
var data = TestObjectsAsPooledList;
using var list = new PooledList<long>(capacity: TestObjectCount, ClearMode.Auto);
list.AddRange(data);
}
public void RecyclableList_AddRangeWhenSourceIsRecyclableList()
{
var data = TestObjectsAsRecyclableList;
using var list = new RecyclableList<long>();
list.AddRange(data);
}
public void RecyclableLongList_AddRangeWhenSourceIsRecyclableList()
{
var data = TestObjectsAsRecyclableList;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
list.AddRange(data);
}
}
}
@@ -0,0 +1,39 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_AddRange_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
var list = new List<long>(dataCount);
list.AddRange(data);
}
public void PooledList_AddRange_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new PooledList<long>(capacity: dataCount, ClearMode.Auto);
list.AddRange(data);
}
public void RecyclableList_AddRange_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new RecyclableList<long>(dataCount);
list.AddRange(data);
}
public void RecyclableLongList_AddRange_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: dataCount);
list.AddRange(data);
}
}
}
@@ -0,0 +1,51 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_Add_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
var list = new List<long>(dataCount);
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
public void PooledList_Add_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new PooledList<long>(capacity: dataCount, ClearMode.Auto);
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
public void RecyclableList_Add_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new RecyclableList<long>(dataCount);
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
public void RecyclableLongList_Add_WithCapacity()
{
var data = TestObjects;
var dataCount = TestObjectCount;
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: dataCount);
for (var i = 0; i < dataCount; i++)
{
list.Add(data[i]);
}
}
}
}
@@ -0,0 +1,60 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Contains_FirstItems()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[i]) >= 0);
}
}
public void List_Contains_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
}
}
public void PooledList_Contains_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
}
}
public void RecyclableList_Contains_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
}
}
public void RecyclableLongList_Contains_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
}
}
}
}
@@ -0,0 +1,60 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Contains_LastItems()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
public void List_Contains_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
public void PooledList_Contains_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
public void RecyclableList_Contains_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
public void RecyclableLongList_Contains_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
}
}
@@ -0,0 +1,35 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Count()
{
var data = TestObjects;
DoNothing(data.Length);
}
public void List_Count()
{
var data = TestObjectsAsList;
DoNothing(data.Count);
}
public void PooledList_Count()
{
var data = TestObjectsAsPooledList;
DoNothing(data.Count);
}
public void RecyclableList_Count()
{
var data = TestObjectsAsRecyclableList;
DoNothing(data.Count);
}
public void RecyclableLongList_Count()
{
var data = TestObjectsAsRecyclableLongList;
DoNothing(data.Count);
}
}
}
@@ -0,0 +1,31 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public static void List_Create()
{
var list = new List<long>();
DoNothing(list);
}
public static void PooledList_Create()
{
using var list = new PooledList<long>(ClearMode.Auto);
DoNothing(list);
}
public static void RecyclableList_Create()
{
using var list = new RecyclableList<long>();
DoNothing(list);
}
public static void RecyclableLongList_Create()
{
using var list = new RecyclableLongList<long>();
DoNothing(list);
}
}
}
@@ -0,0 +1,37 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Create_WithCapacity()
{
var data = new long[TestObjectCount];
DoNothing(data);
}
public void List_Create_WithCapacity()
{
var list = new List<long>(TestObjectCount);
DoNothing(list);
}
public void PooledList_Create_WithCapacity()
{
using var list = new PooledList<long>(capacity: TestObjectCount, ClearMode.Auto);
DoNothing(list);
}
public void RecyclableList_Create_WithCapacity()
{
using var list = new RecyclableList<long>(TestObjectCount);
DoNothing(list);
}
public void RecyclableLongList_Create_WithCapacity()
{
using var list = new RecyclableLongList<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
DoNothing(list);
}
}
}
@@ -0,0 +1,158 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_GetItem()
{
var data = TestObjects;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void List_GetItem()
{
var data = TestObjectsAsList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void PooledList_GetItem()
{
var data = TestObjectsAsPooledList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void RecyclableList_GetItem()
{
var data = TestObjectsAsRecyclableList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void RecyclableLongList_GetItem()
{
var data = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void RecyclableLongList_GetItem_AsSpan()
{
var data = TestObjectsAsRecyclableLongList;
int blockSize = data.BlockSize;
int nextItemBlockIndex = data.NextItemBlockIndex;
var memoryBlocks = new Span<long[]>(data.AsArray, 0, data.LastBlockWithData + 1);
for (var blockIndex = 0; blockIndex < nextItemBlockIndex; blockIndex++)
{
var memoryBlock = new Span<long>(memoryBlocks[blockIndex], 0, blockSize);
for (var itemIndex = 0; itemIndex < blockSize; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
}
}
if (nextItemBlockIndex == data.LastBlockWithData)
{
var memoryBlock = new Span<long>(memoryBlocks[nextItemBlockIndex], 0, data.NextItemIndex);
for (var itemIndex = 0; itemIndex < memoryBlock.Length; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
}
}
}
public void RecyclableLongList_GetItem_AsArray()
{
var data = TestObjectsAsRecyclableLongList;
int blockSize = data.BlockSize;
int nextItemBlockIndex = data.NextItemBlockIndex;
var memoryBlocks = data.AsArray;
for (var blockIndex = 0; blockIndex < nextItemBlockIndex; blockIndex++)
{
var memoryBlock = memoryBlocks[blockIndex];
for (var itemIndex = 0; itemIndex < blockSize; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
}
}
if (nextItemBlockIndex == data.LastBlockWithData)
{
var memoryBlock = memoryBlocks[nextItemBlockIndex];
blockSize = data.NextItemIndex;
for (var itemIndex = 0; itemIndex < blockSize; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
}
}
}
public void RecyclableLongList_GetItem_AsForEach()
{
var data = TestObjectsAsRecyclableLongList;
foreach (var item in data)
{
DoNothing(item);
}
}
public void RecyclableLongList_GetItem_AsWhile()
{
var data = TestObjectsAsRecyclableLongList;
long dataCount = TestObjectCount;
if (dataCount == 0)
{
return;
}
int blockSize = data.BlockSize;
int nextItemBlockIndex = data.NextItemBlockIndex;
int itemIndex = 0;
int blockIndex = 0;
var memoryBlocks = data.AsArray;
var memoryBlock = memoryBlocks[0];
while (blockIndex < nextItemBlockIndex)
{
DoNothing(memoryBlock[itemIndex]);
if (itemIndex + 1 < blockSize)
{
itemIndex++;
}
else
{
blockIndex++;
memoryBlock = memoryBlocks[blockIndex];
itemIndex = 0;
}
}
if (nextItemBlockIndex == data.LastBlockWithData)
{
memoryBlock = memoryBlocks[nextItemBlockIndex];
blockSize = data.NextItemIndex;
while (itemIndex < blockSize)
{
DoNothing(memoryBlock[itemIndex++]);
}
}
}
}
}
@@ -0,0 +1,77 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_IndexOf_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[i]));
DoNothing(Array.IndexOf(list, data[^(i + 1)]));
}
}
public void List_IndexOf_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void PooledList_IndexOf_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void RecyclableList_IndexOf_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void RecyclableLongList_IndexOf_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void RecyclableLongList_LongIndexOf_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.LongIndexOf(data[^(i + 1)]));
}
}
}
}
@@ -0,0 +1,71 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_IndexOf_FirstItems()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[i]));
}
}
public void List_IndexOf_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
}
}
public void PooledList_IndexOf_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
}
}
public void RecyclableList_IndexOf_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
}
}
public void RecyclableLongList_IndexOf_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
}
}
public void RecyclableLongList_LongIndexOf_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.LongIndexOf(data[i]));
}
}
}
}
@@ -0,0 +1,71 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_IndexOf_LastItems()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[^(i + 1)]));
}
}
public void List_IndexOf_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void PooledList_IndexOf_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void RecyclableList_IndexOf_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void RecyclableLongList_IndexOf_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
public void RecyclableLongList_LongIndexOf_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.LongIndexOf(data[^(i + 1)]));
}
}
}
}
@@ -0,0 +1,17 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_LongCount()
{
var data = TestObjects;
DoNothing(data.LongLength);
}
public void RecyclableLongList_LongCount()
{
var data = TestObjectsAsRecyclableLongList;
DoNothing(data.LongCount);
}
}
}
@@ -17,35 +17,35 @@ namespace Recyclable.Collections.Benchmarks
public RecyclableCollectionsBenchmarks() : base()
{
TestObjectCount = 1;
// BaselineBenchmarkType = RecyclableCollectionsBenchmarkSource.PooledList;
BaselineBenchmarkType = RecyclableCollectionsBenchmarkSource.List;
BenchmarkType = RecyclableCollectionsBenchmarkSource.RecyclableLongList;
}
[Params
(
//RecyclableCollectionsBenchmarkType.Add_WithCapacity,
//RecyclableCollectionsBenchmarkType.Add,
//RecyclableCollectionsBenchmarkType.AddRange_WithCapacity,
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsArray,
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIEnumerable,
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIList,
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsList,
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType,
//RecyclableCollectionsBenchmarkType.Contains_FirstItems,
//RecyclableCollectionsBenchmarkType.Contains_LastItems,
//RecyclableCollectionsBenchmarkType.Count,
//RecyclableCollectionsBenchmarkType.Create_WithCapacity,
//RecyclableCollectionsBenchmarkType.Create,
//RecyclableCollectionsBenchmarkType.GetItem,
RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases
//RecyclableCollectionsBenchmarkType.IndexOf_FirstItems,
//RecyclableCollectionsBenchmarkType.IndexOf_LastItems
//RecyclableCollectionsBenchmarkType.LongCount,
//RecyclableCollectionsBenchmarkType.Remove_FirstItems,
//RecyclableCollectionsBenchmarkType.Remove_LastItems,
//RecyclableCollectionsBenchmarkType.RemoveAt_FirstItems,
//RecyclableCollectionsBenchmarkType.RemoveAt_LastItems,
//RecyclableCollectionsBenchmarkType.SetItem
RecyclableCollectionsBenchmarkType.Add_WithCapacity,
RecyclableCollectionsBenchmarkType.Add,
RecyclableCollectionsBenchmarkType.AddRange_WithCapacity,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsArray,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIEnumerable,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIList,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsList,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType,
RecyclableCollectionsBenchmarkType.Contains_FirstItems,
RecyclableCollectionsBenchmarkType.Contains_LastItems,
RecyclableCollectionsBenchmarkType.Count,
RecyclableCollectionsBenchmarkType.Create_WithCapacity,
RecyclableCollectionsBenchmarkType.Create,
RecyclableCollectionsBenchmarkType.GetItem,
RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.IndexOf_FirstItems,
RecyclableCollectionsBenchmarkType.IndexOf_LastItems,
RecyclableCollectionsBenchmarkType.LongCount,
RecyclableCollectionsBenchmarkType.Remove_FirstItems,
RecyclableCollectionsBenchmarkType.Remove_LastItems,
RecyclableCollectionsBenchmarkType.RemoveAt_FirstItems,
RecyclableCollectionsBenchmarkType.RemoveAt_LastItems,
RecyclableCollectionsBenchmarkType.SetItem
)]
public RecyclableCollectionsBenchmarkType TestCase { get; set; } = RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases;
@@ -58,10 +58,10 @@ namespace Recyclable.Collections.Benchmarks
[Params
(
//RecyclableCollectionsBenchmarkSource.Array,
//RecyclableCollectionsBenchmarkSource.List,
//RecyclableCollectionsBenchmarkSource.PooledList
//RecyclableCollectionsBenchmarkSource.RecyclableList,
RecyclableCollectionsBenchmarkSource.Array,
RecyclableCollectionsBenchmarkSource.List,
RecyclableCollectionsBenchmarkSource.PooledList,
RecyclableCollectionsBenchmarkSource.RecyclableList,
RecyclableCollectionsBenchmarkSource.RecyclableLongList
)]
public override RecyclableCollectionsBenchmarkSource BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
@@ -0,0 +1,51 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_RemoveAt_FirstItems()
{
var data = TestObjects;
var list = new List<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
list.RemoveAt(i);
}
}
public void PooledList_RemoveAt_FirstItems()
{
var data = TestObjects;
using var list = new PooledList<long>(data, ClearMode.Auto);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
list.RemoveAt(i);
}
}
public void RecyclableList_RemoveAt_FirstItems()
{
var data = TestObjects;
using var list = new RecyclableList<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
list.RemoveAt(i);
}
}
public void RecyclableLongList_RemoveAt_FirstItems()
{
var data = TestObjects;
using var list = new RecyclableLongList<long>(data, minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
list.RemoveAt(i);
}
}
}
}
@@ -0,0 +1,51 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_RemoveAt_LastItems()
{
var data = TestObjects;
var list = new List<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
list.RemoveAt(i);
}
}
public void PooledList_RemoveAt_LastItems()
{
var data = TestObjects;
using var list = new PooledList<long>(data, ClearMode.Auto);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
list.RemoveAt(i);
}
}
public void RecyclableList_RemoveAt_LastItems()
{
var data = TestObjects;
using var list = new RecyclableList<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
list.RemoveAt(i);
}
}
public void RecyclableLongList_RemoveAt_LastItems()
{
var data = TestObjects;
using var list = new RecyclableLongList<long>(data, minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
list.RemoveAt(i);
}
}
}
}
@@ -0,0 +1,51 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_Remove_FirstItems()
{
var data = TestObjects;
var list = new List<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
}
}
public void PooledList_Remove_FirstItems()
{
var data = TestObjects;
using var list = new PooledList<long>(data, ClearMode.Auto);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
}
}
public void RecyclableList_Remove_FirstItems()
{
var data = TestObjects;
using var list = new RecyclableList<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
}
}
public void RecyclableLongList_Remove_FirstItems()
{
var data = TestObjects;
using var list = new RecyclableLongList<long>(data, minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
}
}
}
}
@@ -0,0 +1,51 @@
using Collections.Pooled;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void List_Remove_LastItems()
{
var data = TestObjects;
var list = new List<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
}
}
public void PooledList_Remove_LastItems()
{
var data = TestObjects;
using var list = new PooledList<long>(data, ClearMode.Auto);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
}
}
public void RecyclableList_Remove_LastItems()
{
var data = TestObjects;
using var list = new RecyclableList<long>(data);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
}
}
public void RecyclableLongList_Remove_LastItems()
{
var data = TestObjects;
using var list = new RecyclableLongList<long>(data, minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
}
}
}
}
@@ -0,0 +1,56 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_SetItem()
{
var data = TestObjects;
var dataCount = TestObjectCount;
long index = 0;
for (var i = 0; i < dataCount; i++)
{
data[index] = TestObjects[index++];
}
}
public void List_SetItem()
{
var data = TestObjectsAsList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
data[i] = TestObjects[i];
}
}
public void PooledList_SetItem()
{
var data = TestObjectsAsPooledList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
data[i] = TestObjects[i];
}
}
public void RecyclableList_SetItem()
{
var data = TestObjectsAsRecyclableList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
data[i] = TestObjects[i];
}
}
public void RecyclableLongList_SetItem()
{
var data = TestObjectsAsRecyclableLongList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
data[i] = TestObjects[i];
}
}
}
}
@@ -0,0 +1,19 @@
namespace Recyclable.Collections.Benchmarks.Core
{
public static class DataGenerator
{
public static long[] EnumerateTestObjects(long testObjectCount)
{
var result = new long[testObjectCount];
Console.WriteLine("******* TEST DATA ARRAY CREATED *******");
Span<long> resultSpan = result;
for (int i = 0; i < testObjectCount; i++)
{
resultSpan[i] = i;
}
return result;
}
}
}
@@ -1,253 +0,0 @@
using BenchmarkDotNet.Attributes;
using MiscUtil;
using MiscUtil.Extensions;
namespace Recyclable.Collections.Benchmarks
{
public delegate T Compare<T>(T x, T y);
public readonly struct MyComparerReadOnlyStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Operator.Subtract(x, y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
public struct MyComparerStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Operator.Subtract(x, y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
public class MyComparer : IComparer<long>
{
public int Compare(long x, long y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
[MemoryDiagnoser]
public class DelegateVsComparerBenchmark
{
private static readonly Comparer<long> _comparer = Comparer<long>.Default;
private const int _objectCount = 1_000_000;
private static readonly IEnumerable<long> _testObjects = Enumerable.Range(1, _objectCount).Select(x => (long)x);
private static readonly IEnumerable<Func<long, long, int>> _testListOfFunctions = _testObjects.Select<long, Func<long, long, int>>(static x => new MyComparer().Compare);
private static readonly IEnumerable<IComparer<long>> _testListOfComparers = _testObjects.Select(x => (IComparer<long>)new MyComparer());
private static readonly IEnumerable<Compare<long>> _testListOfDelegates = _testObjects.Select(x => new Compare<long>((x, y) => new MyComparer().Compare(x, y)));
private static readonly IEnumerable<Func<long, long, int>> _testListOfLocalFunctions = GetLocalFunctions(_testObjects);
private static readonly IEnumerable<MyComparer> _testListOfClasses = _testObjects.Select(x => new MyComparer());
private static readonly IEnumerable<MyComparerStruct<long>> _testListOfStructs = _testObjects.Select(x => new MyComparerStruct<long>());
private static readonly IEnumerable<IComparer<long>> _testListOfBoxedStructs = _testObjects.Select(x => (IComparer<long>)new MyComparerStruct<long>());
private static IEnumerable<TComparer> _testListOfUnboxedStructs<TComparer, TValue>() where TComparer : IComparer<TValue>, new()
{
foreach (var item in _testObjects)
{
yield return new TComparer();
}
}
private static IEnumerable<Func<long, long, int>> GetLocalFunctions(IEnumerable<long> testObjects)
{
static int compareFunc(long x, long y)
{
return (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
};
}
foreach (var item in testObjects)
{
yield return compareFunc;
}
}
private static void TestWithComparer(IComparer<long> comparer)
{
var testData = _testObjects.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = comparer.Compare(testData[itemIdx], testData[itemIdx + 1]);
}
}
[Benchmark(Baseline = true)]
public void Comparer()
{
TestWithComparer(_comparer);
}
private static void TestWithFunc(Func<long, long, int> compareFunc)
{
var testData = _testObjects.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
[Benchmark]
public void Func()
{
TestWithFunc((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
[Benchmark]
public void StaticFunc()
{
TestWithFunc(static (x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
private static void TestWithDelegate<T>(Compare<long> compareFunc)
{
var testData = _testObjects.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
[Benchmark]
public void Delegate()
{
TestWithDelegate<long>((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
[Benchmark]
public void ListOfFuncs()
{
const long x = 2, y = 5;
var testData = _testListOfFunctions.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(x, y);
}
}
[Benchmark]
public void ListOfLocalFuncs()
{
const long x = 2, y = 5;
var testData = _testListOfLocalFunctions.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(x, y);
}
}
[Benchmark]
public void ListOfComparers()
{
const long x = 2, y = 5;
var testData = _testListOfComparers.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
[Benchmark]
public void ListOfClasses()
{
const long x = 2, y = 5;
var testData = _testListOfClasses.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
[Benchmark]
public void ListOfStructs()
{
const long x = 2, y = 5;
var testData = _testListOfStructs.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
[Benchmark]
public void ListOfBoxedStructs()
{
const long x = 2, y = 5;
var testData = _testListOfBoxedStructs.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
[Benchmark]
public void ListOfUnboxedStructs()
{
const long x = 2, y = 5;
var testData = _testListOfUnboxedStructs<MyComparerStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
[Benchmark]
public void ListOfUnboxedReadOnlyStructs()
{
const long x = 2, y = 5;
var testData = _testListOfUnboxedStructs<MyComparerReadOnlyStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
[Benchmark]
public void ListOfDelegates()
{
const long x = 2, y = 5;
var testData = _testListOfDelegates.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareDelegate = testData[itemIdx];
_ = compareDelegate(x, y);
}
}
}
}
@@ -1,223 +0,0 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks
{
[MemoryDiagnoser]
public class ListVsLinkedListBenchmark
{
private const int _objectCount = 1_000_000;
private const int _blockSize = 100_000;
private static readonly object[] _testObjects = Enumerable.Range(1, _objectCount).Select(x => new object()).ToArray();
private static void DoNothing<T>(T obj)
{
_ = obj;
}
[Benchmark]
public void Array()
{
var list = new object[_testObjects.LongLength];
for (var i = 0; i < _testObjects.Length; i++)
{
list[i] = _testObjects[i];
}
for (var i = 0; i < list.LongLength; i++)
{
DoNothing(list[i]);
}
}
[Benchmark(Baseline = true)]
public void RecyclableList()
{
using var list = new RecyclableList<object>(_blockSize);
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Add(_testObjects[i]);
}
for (var i = 0; i < list.Count; i++)
{
DoNothing(_testObjects[i]);
}
list.Clear();
}
[Benchmark]
public void List()
{
var list = new List<object>();
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Add(_testObjects[i]);
}
for (var i = 0; i < list.Count; i++)
{
DoNothing(list[i]);
}
list.Clear();
}
//[Benchmark]
public void LinkedList()
{
var list = new LinkedList<object>();
for (var i = 0; i < _testObjects.LongLength; i++)
{
_ = list.AddLast(_testObjects[i]);
}
foreach (var node in list)
{
DoNothing(node);
}
list.Clear();
}
[Benchmark]
public void RecyclableQueue()
{
var list = new RecyclableQueue<object>(_blockSize);
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Enqueue(_testObjects[i]);
}
foreach (var node in list)
{
DoNothing(node);
}
list.Clear();
}
//[Benchmark]
public void Queue()
{
var list = new Queue<object>();
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Enqueue(_testObjects[i]);
}
foreach (var node in list)
{
DoNothing(node);
}
list.Clear();
}
//[Benchmark]
public void PriorityQueue()
{
var list = new PriorityQueue<object, long>();
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Enqueue(_testObjects[i], i);
}
while (list.Count > 0)
{
var node = list.Dequeue();
DoNothing(node);
}
list.Clear();
}
//[Benchmark]
public void RecyclableSortedList_InUpdateMode()
{
var list = new RecyclableSortedList<long, object>(_blockSize);
list.BeginUpdate();
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Add(i, _testObjects[i]);
}
list.EndUpdate();
for (var i = 0; i < list.LongCount; i++)
{
DoNothing(_testObjects[i]);
}
list.Clear();
}
//[Benchmark]
public void RecyclableSortedList()
{
var list = new RecyclableSortedList<long, object>(_blockSize);
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Add(i, _testObjects[i]);
}
for (var i = 0; i < list.LongCount; i++)
{
DoNothing(_testObjects[i]);
}
list.Clear();
}
//[Benchmark]
public void SortedList()
{
var list = new SortedList<long, object>();
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Add(i, _testObjects[i]);
}
for (var i = 0; i < list.Count; i++)
{
DoNothing(_testObjects[i]);
}
list.Clear();
}
//[Benchmark]
public void RecyclableStack()
{
var list = new RecyclableStack<object>(_blockSize);
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Push(_testObjects[i]);
}
foreach (var node in list)
{
DoNothing(node);
}
list.Clear();
}
//[Benchmark]
public void Stack()
{
var list = new Stack<object>();
for (var i = 0; i < _testObjects.LongLength; i++)
{
list.Push(_testObjects[i]);
}
foreach (var node in list)
{
DoNothing(node);
}
list.Clear();
}
}
}
@@ -0,0 +1,70 @@
using BenchmarkDotNet.Attributes;
using System.Buffers;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum ArraySizeLimitPocBenchmarkType
{
ArraySizeLimit
}
public class ArraySizeLimitPocBenchmarks : PocBenchmarkBase<ArraySizeLimitPocBenchmarkType>
{
public static void Run()
{
var benchmark = new ArraySizeLimitPocBenchmarks();
benchmark.Setup();
FindArraySizeLimit();
benchmark.Cleanup();
}
[Params(2_147_483_605)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
[Benchmark(OperationsPerInvoke = 1)]
public void Max_Allowed_Size_2_147_483_605()
{
long[] arr = ArrayPool<long>.Shared.Rent(TestObjectCount);
DoNothing(arr);
}
[Benchmark(OperationsPerInvoke = 1)]
public static void FindArraySizeLimit()
{
var pool = ArrayPool<long>.Shared;
var bufferSize = int.MaxValue / 2;
var oldValue = 0;
while (true)
{
try
{
Console.Write($"Allocating {bufferSize}...");
var arr = pool.Rent(bufferSize);
Console.WriteLine("success");
pool.Return(arr);
arr = null;
var nextValue = bufferSize - oldValue;
oldValue = bufferSize;
bufferSize = checked(bufferSize + nextValue);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
}
catch (Exception)
{
Console.WriteLine("error");
var nextValue = (bufferSize - oldValue) >> 1;
if (nextValue == 0)
{
break;
}
bufferSize = oldValue + nextValue;
}
}
Console.WriteLine("All done");
throw new Exception($"Everything was successful. You can create {oldValue} byte big arrays. Exception is logged to prevent more benchmarks.");
}
}
}
@@ -0,0 +1,63 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum BoolOrComparePocBenchmarkType
{
Bool,
Compare,
}
[MemoryDiagnoser]
public class BoolOrComparePocBenchmarks : PocBenchmarkBase<BoolOrComparePocBenchmarkType>
{
[Params(BoolOrComparePocBenchmarkType.Bool, BoolOrComparePocBenchmarkType.Compare)]
public override BoolOrComparePocBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
[Params(8)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
[Params(true)]
public bool TestBool = true;
public static void Run()
{
var benchmark = new BoolOrComparePocBenchmarks();
benchmark.Setup();
benchmark.Bool();
benchmark.Compare();
benchmark.Cleanup();
}
public void Bool()
{
if (TestBool)
{
DoNothing(TestBool);
}
else
{
DoNothing(TestBool);
}
}
public void Compare()
{
if (TestObjectCount >= RecyclableDefaults.MinPooledArrayLength)
{
DoNothing(TestBool);
}
else
{
DoNothing(TestBool);
}
}
protected override Action? GetTestMethod(BoolOrComparePocBenchmarkType benchmarkType) => benchmarkType switch
{
BoolOrComparePocBenchmarkType.Bool => Bool,
BoolOrComparePocBenchmarkType.Compare => Compare,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
}
}
@@ -0,0 +1,357 @@
using BenchmarkDotNet.Attributes;
using MiscUtil;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum DelegateVsComparerPocBenchmarkType
{
Comparer,
Delegate,
Func,
ListOfBoxedStructs,
ListOfClasses,
ListOfComparers,
ListOfDelegates,
ListOfFuncs,
ListOfLocalFuncs,
ListOfStructs,
ListOfUnboxedReadOnlyStructs,
ListOfUnboxedStructs,
StaticFunc,
}
[MemoryDiagnoser]
public class DelegateVsComparerPocBenchmarks : PocBenchmarkBase<DelegateVsComparerPocBenchmarkType>
{
[Params
(
DelegateVsComparerPocBenchmarkType.Delegate,
DelegateVsComparerPocBenchmarkType.Func,
DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs,
DelegateVsComparerPocBenchmarkType.ListOfClasses,
DelegateVsComparerPocBenchmarkType.ListOfComparers,
DelegateVsComparerPocBenchmarkType.ListOfDelegates,
DelegateVsComparerPocBenchmarkType.ListOfFuncs,
DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs,
DelegateVsComparerPocBenchmarkType.ListOfStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedReadOnlyStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedStructs,
DelegateVsComparerPocBenchmarkType.StaticFunc
)]
public override DelegateVsComparerPocBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
[Params(DelegateVsComparerPocBenchmarkType.Comparer)]
public override DelegateVsComparerPocBenchmarkType BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; }
#region Dummy classes
private delegate T Compare<T>(T x, T y);
public readonly struct MyComparerReadOnlyStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Operator.Subtract(x, y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
private struct MyComparerStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Operator.Subtract(x, y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
private class MyComparer : IComparer<long>
{
public int Compare(long x, long y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
#endregion
public static void Run()
{
var benchmark = new DelegateVsComparerPocBenchmarks();
benchmark.Setup();
benchmark.Comparer();
benchmark.Delegate();
benchmark.Func();
benchmark.ListOfBoxedStructs();
benchmark.ListOfClasses();
benchmark.ListOfComparers();
benchmark.ListOfDelegates();
benchmark.ListOfFuncs();
benchmark.ListOfLocalFuncs();
benchmark.ListOfStructs();
benchmark.ListOfUnboxedReadOnlyStructs();
benchmark.ListOfUnboxedStructs();
benchmark.StaticFunc();
benchmark.Cleanup();
}
private static readonly Comparer<long> _comparer = Comparer<long>.Default;
private IEnumerable<long>? _testObjects;
private IEnumerable<Func<long, long, int>>? _testListOfFunctions;
private IEnumerable<IComparer<long>>? _testListOfComparers;
private IEnumerable<Compare<long>>? _testListOfDelegates;
private IEnumerable<Func<long, long, int>>? _testListOfLocalFunctions;
private IEnumerable<MyComparer>? _testListOfClasses;
private IEnumerable<MyComparerStruct<long>>? _testListOfStructs;
private IEnumerable<IComparer<long>>? _testListOfBoxedStructs;
private IEnumerable<TComparer> TestListOfUnboxedStructs<TComparer, TValue>() where TComparer : IComparer<TValue>, new()
{
foreach (var _ in _testObjects!)
{
yield return new TComparer();
}
}
private static IEnumerable<Func<long, long, int>> GetLocalFunctions(IEnumerable<long> testObjects)
{
static int compareFunc(long x, long y)
{
return (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
};
}
foreach (var _ in testObjects)
{
yield return compareFunc;
}
}
private void TestWithComparer(IComparer<long> comparer)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = comparer.Compare(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithDelegate<T>(Compare<long> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithFunc(Func<long, long, int> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
public void Comparer()
{
TestWithComparer(_comparer);
}
public void Func()
{
TestWithFunc((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void StaticFunc()
{
TestWithFunc(static (x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void Delegate()
{
TestWithDelegate<long>((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void ListOfFuncs()
{
const long x = 2, y = 5;
var testData = _testListOfFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(x, y);
}
}
public void ListOfLocalFuncs()
{
const long x = 2, y = 5;
var testData = _testListOfLocalFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(x, y);
}
}
public void ListOfComparers()
{
const long x = 2, y = 5;
var testData = _testListOfComparers!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfClasses()
{
const long x = 2, y = 5;
var testData = _testListOfClasses!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfStructs()
{
const long x = 2, y = 5;
var testData = _testListOfStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfBoxedStructs()
{
const long x = 2, y = 5;
var testData = _testListOfBoxedStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfUnboxedStructs()
{
const long x = 2, y = 5;
var testData = TestListOfUnboxedStructs<MyComparerStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfUnboxedReadOnlyStructs()
{
const long x = 2, y = 5;
var testData = TestListOfUnboxedStructs<MyComparerReadOnlyStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfDelegates()
{
const long x = 2, y = 5;
var testData = _testListOfDelegates!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareDelegate = testData[itemIdx];
_ = compareDelegate(x, y);
}
}
protected override Action? GetTestMethod(DelegateVsComparerPocBenchmarkType benchmarkType) => benchmarkType switch
{
DelegateVsComparerPocBenchmarkType.Comparer => Comparer,
DelegateVsComparerPocBenchmarkType.Delegate => Delegate,
DelegateVsComparerPocBenchmarkType.Func => Func,
DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs => ListOfBoxedStructs,
DelegateVsComparerPocBenchmarkType.ListOfClasses => ListOfClasses,
DelegateVsComparerPocBenchmarkType.ListOfComparers => ListOfComparers,
DelegateVsComparerPocBenchmarkType.ListOfDelegates => ListOfDelegates,
DelegateVsComparerPocBenchmarkType.ListOfFuncs => ListOfFuncs,
DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs => ListOfLocalFuncs,
DelegateVsComparerPocBenchmarkType.ListOfStructs => ListOfStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedReadOnlyStructs => ListOfUnboxedReadOnlyStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedStructs => ListOfUnboxedStructs,
DelegateVsComparerPocBenchmarkType.StaticFunc => StaticFunc,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
public override void Setup()
{
Console.WriteLine("******* SETTING UP COMMON TEST DATA *******");
_testObjects = Enumerable.Range(1, TestObjectCount).Select(x => (long)x);
base.Setup();
}
public override void Cleanup()
{
_testObjects = null;
base.Cleanup();
}
protected override void PrepareData<T>(T benchmarkType)
{
switch (benchmarkType)
{
case DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs:
_testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer<long>)new MyComparerStruct<long>());
break;
case DelegateVsComparerPocBenchmarkType.ListOfClasses:
_testListOfClasses = _testObjects!.Select(_ => new MyComparer());
break;
case DelegateVsComparerPocBenchmarkType.ListOfComparers:
_testListOfComparers = _testObjects!.Select(_ => (IComparer<long>)new MyComparer());
break;
case DelegateVsComparerPocBenchmarkType.ListOfDelegates:
_testListOfDelegates = _testObjects!.Select(_ => new Compare<long>((x, y) => new MyComparer().Compare(x, y)));
break;
case DelegateVsComparerPocBenchmarkType.ListOfFuncs:
_testListOfFunctions = _testObjects!.Select<long, Func<long, long, int>>(static _ => new MyComparer().Compare);
break;
case DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs:
_testListOfLocalFunctions = GetLocalFunctions(_testObjects!);
break;
case DelegateVsComparerPocBenchmarkType.ListOfStructs:
_testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct<long>());
break;
}
}
}
}
@@ -0,0 +1,374 @@
using BenchmarkDotNet.Attributes;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Recyclable.Collections.Benchmarks.POC
{
[MemoryDiagnoser]
public class ModuloPocBenchmarks
{
public static void Run()
{
var benchmark = new ModuloPocBenchmarks();
benchmark.Setup();
benchmark.AddWithFor();
benchmark.AddWithForOptimized();
benchmark.DividerAndModulusWithOperator();
benchmark.MathDivRem();
benchmark.MixedApproachWithForLoopOptimized();
benchmark.MixedApproachWithSubtractWithStackalloc();
benchmark.MixedApproachWithSubtractWithWhile();
benchmark.MixedApproachWithSubtractWithWhileAsVector();
benchmark.MixedApproachWithSubtractWithWhileWithSse2();
benchmark.SubtractWithWhile();
benchmark.SubtractWithWhileWithSse2();
benchmark.XDivYMulX();
benchmark.XDivYMulXWithLocalVar();
}
private long _cutoff;
private Vector128<long> _increment;
private long _lastCaseIndex;
[GlobalSetup]
public void Setup()
{
_cutoff = BlockSize << 4;
_increment = Vector128.Create(-BlockSize, 1L);
_lastCaseIndex = 0;
}
private static void DoNothing<T>(T result, T remainder, [CallerMemberName] string? callerName = null)
{
//Console.WriteLine($"{callerName}: result = {result}, remainder = {remainder}");
}
//[Params(123, 10, 2, int.MaxValue, int.MaxValue / 2, int.MaxValue / 3, int.MaxValue / 4, int.MaxValue / 6, int.MaxValue / 10, int.MaxValue / 15, int.MaxValue / 20)]
[Params(int.MaxValue, int.MaxValue / 2, int.MaxValue / 3, int.MaxValue / 4, int.MaxValue / 6, int.MaxValue / 8, int.MaxValue / 10, int.MaxValue / 100)]
//[Params(int.MaxValue / 10, int.MaxValue / 20, int.MaxValue / 100)]
public int BlockSize { get; set; } = int.MaxValue;
[Params(int.MaxValue, int.MaxValue / 1000, int.MaxValue / 10000)]
//[Params(int.MaxValue)]
//[Params(int.MaxValue * 100L)]
public long TestNumber { get; set; } = int.MaxValue;
private void CalculateDividerAndModulusWithOperator(long i)
{
DoNothing(i / BlockSize, i % BlockSize);
}
private void CalculateWithMathDivRem(long i)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
private void CalculateWithAddWithFor(long i)
{
int result = 0;
int remainder = 0;
int blockSize = BlockSize;
for (long iteration = 0; iteration < i; iteration++)
{
if (remainder > blockSize - 1)
{
remainder = 0;
result++;
}
remainder++;
}
DoNothing(result, remainder);
}
private void CalculateWithAddWithForOptimized(long i)
{
long total = 0;
int result = 0;
int blockSize = BlockSize;
while (total + blockSize <= i)
{
total += blockSize;
result++;
}
DoNothing(result, i - total);
}
private void CalculateWithXDivYMulX(long i)
{
DoNothing(i / BlockSize, i - (i / BlockSize * BlockSize));
}
private void CalculateWithXDivYMulXWithLocalVar(long i)
{
int blockSize = BlockSize;
int result = (int)(i / blockSize);
DoNothing(result, i - (result * blockSize));
}
private void CalculateWithSubtractWithWhile(long i)
{
int result = 0;
long remainder = i;
int blockSize = BlockSize;
while (remainder >= blockSize)
{
remainder -= blockSize;
result++;
}
DoNothing(result, remainder);
}
private void CalculateWithSubractWithWhileWithSse2(long i)
{
var state = Vector128.Create(i, 0);
int blockSize = BlockSize;
var inc = _increment;
while (state.GetElement(0) >= blockSize)
{
state = Sse2.Add(state, inc);
}
DoNothing(state.GetElement(1), state.GetElement(0));
}
private void CalculateWithMixedApproachWithSubractWithWhile(long i)
{
long remainder;
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out remainder), remainder);
}
else
{
int result = 0;
int blockSize = BlockSize;
remainder = i;
while (remainder >= blockSize)
{
remainder -= blockSize;
result++;
}
DoNothing(result, remainder);
}
}
private void CalculateWithMixedApproachWithSubtractWithWhileAsVector(long i)
{
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
var state = new Vector<long>(new[] { 0L, i, 0, 0 });
var increment = new Vector<long>(new[] { 1L, -BlockSize, 0, 0 });
int blockSize = BlockSize;
while (state[1] >= blockSize)
{
state += increment;
}
DoNothing(state[0], state[1]);
}
}
private void CalculateWithMixedApproachWithSubtractWithWhileWithSse2(long i)
{
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
var increment = _increment;
var state = Vector128.Create(i, 0);
int blockSize = BlockSize;
while (state.GetElement(0) >= blockSize)
{
state = Sse2.Add(state, increment);
}
DoNothing(state.GetElement(1), state.GetElement(0));
}
}
private void CalculateWithMixedApproachWithSubtractWithStackalloc(long i)
{
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
Span<long> state = stackalloc long[2] { i, 0 };// Vector128.Create(BlockSize, 0);
int blockSize = BlockSize;
while (state[0] >= blockSize)
{
state[0] -= blockSize;
state[1]++;
}
DoNothing(state[1], state[0]);
}
}
private void CalculateWithMixedApproachWithForLoopOptimized(long i)
{
long total;
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out total), total);
}
else
{
total = 0;
int result = 0;
int blockSize = BlockSize;
while (total + blockSize <= i)
{
total += blockSize;
result++;
}
DoNothing(result, i - total);
}
}
[Benchmark(Baseline = true)]
public void DividerAndModulusWithOperator()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateDividerAndModulusWithOperator(i);
}
}
[Benchmark]
public void MathDivRem()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMathDivRem(i);
}
}
[Benchmark]
public void AddWithFor()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithAddWithFor(i);
}
}
[Benchmark(Baseline = true)]
public void AddWithForOptimized()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithAddWithForOptimized(i);
}
}
[Benchmark]
public void XDivYMulX()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithXDivYMulX(i);
}
}
[Benchmark]
public void XDivYMulXWithLocalVar()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithXDivYMulXWithLocalVar(i);
}
}
[Benchmark]
public void SubtractWithWhile()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithSubtractWithWhile(i);
}
}
[Benchmark]
public void SubtractWithWhileWithSse2()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithSubractWithWhileWithSse2(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhile()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubractWithWhile(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhileAsVector()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhileAsVector(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhileWithSse2()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhileWithSse2(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithStackalloc()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithStackalloc(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithForLoopOptimized()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithForLoopOptimized(i);
}
}
}
}
@@ -0,0 +1,121 @@
using BenchmarkDotNet.Attributes;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections.Benchmarks.POC
{
public abstract class PocBenchmarkBase<TBenchmarkType>
{
public virtual TBenchmarkType? BenchmarkType { get; set; }
public virtual TBenchmarkType? BaselineBenchmarkType { get; set; }
private Action? _testMethod;
protected Action TestMethod
{
get => _testMethod ?? throw new OperationCanceledException("Skip - Custom benchmark run in progress");
set => _testMethod = value;
}
private Action? _baselineMethod;
protected Action BaselineMethod
{
get => _baselineMethod ?? throw new OperationCanceledException("Skip - No baseline defined");
set => _baselineMethod = value;
}
[Benchmark(Baseline = true)]
public void Baseline() => BaselineMethod.Invoke();
[Benchmark]
public void Actual() => TestMethod.Invoke();
// 0 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524_288
// 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912
// 1073741824 2147483648
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 1_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 1_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 100_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 850_000 - 1, 1_000_000, RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1_000_000, 10_000_000, 100_000_000, 1_000_000_000)]
// [Params(192, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144)]
// [Params(524_288, 786_432, 1_048_576)]
// [Params(262_144, 393_216, 524_288)]
[Params(850_000)]
// [Params(RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 10_000_000, 33_554_432, 50_000_000, 100_000_000)]
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization - 1)]
//[Params(RecyclableDefaults.MinItemsCountForParallelization, 1_048_576, 2_097_152, 4_194_304, 8_388_608, 16_777_216, 33_554_432, RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization * 3)]
// [Params(1_048_576)]
public virtual int TestObjectCount { get; set; } = 1; //33_554_432; //524_288; //131_072;
public virtual int TestObjectCountForSlowMethods => (TestObjectCount / 2) + 1;// Math.Min(TestObjectCount, 131_072);
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200)]
//[Params(10, 20, 50, 100)]
//[Params(1, 10)]
public int Divider = 10;
//public int BlockSize = 1_048_576;//int.MaxValue - 1;
public int BlockSize => TestObjectCount switch
{
0 => 1,
> 0 and <= 10_240 => TestObjectCount,
_ => TestObjectCount / Divider > 0 ? TestObjectCount / Divider : TestObjectCount
};
public byte BlockSizePow2BitShift => checked((byte)(31 - BitOperations.LeadingZeroCount((uint)BlockSize)));
[MethodImpl(MethodImplOptions.NoInlining)]
protected static void DoNothing<T>(in T item)
{
_ = item;
}
protected static Exception CreateUnknownBenchmarkTypeException<T>(T benchmarkType)
{
return new InvalidOperationException($"******* UNKNOWN BENCHMARK TYPE {{{benchmarkType}}} *******");
}
protected static Exception CreateMethodNotFoundException(in string methodName, in string? className)
{
return new MethodAccessException($"******* METHOD {{{methodName}}} NOT FOUND IN CLASS {{{className}}} *******");
}
protected virtual void PrepareData<T>(T benchmarkType) { }
protected virtual Action? GetTestMethod(TBenchmarkType? benchmarkType) => null;
[GlobalCleanup]
public virtual void Cleanup()
{
_baselineMethod = null;
_testMethod = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
}
[GlobalSetup]
public virtual void Setup()
{
Console.WriteLine($"******* SETTING UP TEST CASE FOR BENCHMARK {{{BenchmarkType}}} *******");
if (!EqualityComparer<TBenchmarkType>.Default.Equals(BaselineBenchmarkType, default))
{
Console.WriteLine("******* SETTING UP BASELINE DATA *******");
PrepareData(BaselineBenchmarkType);
_baselineMethod = GetTestMethod(BaselineBenchmarkType);
}
//~ We don't want to prepare data if baseline data is the same is benchmark data.
//~ One would override another - waste of time & resources.
if (!EqualityComparer<TBenchmarkType>.Default.Equals(BaselineBenchmarkType, BenchmarkType))
{
Console.WriteLine("******* SETTING UP TEST CASE DATA *******");
//~ If BaselineBenchmarkType == null, then we'll come here only if BaselineBenchmarkType != null.
PrepareData(BenchmarkType!);
_testMethod = GetTestMethod(BenchmarkType);
}
Console.WriteLine("******* DATA PREPARED *******");
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,157 @@
using System.Reflection;
using BenchmarkDotNet.Attributes;
using Collections.Pooled;
using Recyclable.Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum RecyclableLongListPocBenchmarkType
{
IndexOfV1,
IndexOfV2,
IndexOfV3,
IndexOfV4,
IndexOf_PooledList,
IndexOf,
EnsureCapacity_ByPowOf2,
EnsureCapacityV1_ByPowOf2,
EnsureCapacityV2_ByPowOf2,
EnsureCapacityV3_ByPowOf2,
}
[MemoryDiagnoser]
public partial class RecyclableLongListPocBenchmarks : PocBenchmarkBase<RecyclableLongListPocBenchmarkType>
{
[Params(RecyclableLongListPocBenchmarkType.IndexOf)]
public override RecyclableLongListPocBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
// [Params(BenchmarkType.Array, BenchmarkType.List, BenchmarkType.RecyclableList, BenchmarkType.RecyclableLongList)]
[Params(RecyclableLongListPocBenchmarkType.IndexOf_PooledList)]
public override RecyclableLongListPocBenchmarkType BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; }
private long[]? _testArray;
public long[] TestObjects => _testArray ?? throw new NullReferenceException("Something is wrong and test objects are null");
public RecyclableLongList<long> TestObjectsAsRecyclableLongList => _testRecyclableLongList ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongList<long>)} is null");
private RecyclableLongListIndexOfV1<long>? _testRecyclableLongListIndexOfV1;
internal RecyclableLongListIndexOfV1<long> TestObjectsAsRecyclableLongListIndexOfV1 => _testRecyclableLongListIndexOfV1 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongListIndexOfV1<long>)} is null");
private RecyclableLongListIndexOfV2<long>? _testRecyclableLongListIndexOfV2;
private RecyclableLongList<long>? _testRecyclableLongList;
internal RecyclableLongListIndexOfV2<long> TestObjectsAsRecyclableLongListIndexOfV2 => _testRecyclableLongListIndexOfV2 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongListIndexOfV2<long>)} is null");
private RecyclableLongListIndexOfV3<long>? _testRecyclableLongListIndexOfV3;
internal RecyclableLongListIndexOfV3<long> TestObjectsAsRecyclableLongListIndexOfV3 => _testRecyclableLongListIndexOfV3 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongListIndexOfV3<long>)} is null");
private RecyclableLongListIndexOfV4<long>? _testRecyclableLongListIndexOfV4;
internal RecyclableLongListIndexOfV4<long> TestObjectsAsRecyclableLongListIndexOfV4 => _testRecyclableLongListIndexOfV4 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongListIndexOfV4<long>)} is null");
private PooledList<long>? _testPooledList;
internal PooledList<long> TestPooledList => _testPooledList ?? throw new NullReferenceException($"Something is wrong and {nameof(PooledList<long>)} is null");
private static readonly MethodInfo _ensureCapacityNewFunc;
private static readonly MethodInfo _ensureCapacityV1Func;
private static readonly MethodInfo _ensureCapacityV2Func;
private static readonly MethodInfo _ensureCapacityV3Func;
static RecyclableLongListPocBenchmarks()
{
_ensureCapacityNewFunc = typeof(RecyclableLongList<long>).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.NonPublic)
?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongList<long>)}");
_ensureCapacityV1Func = typeof(RecyclableLongListV1<long>).GetMethod("EnsureCapacity", BindingFlags.Instance | BindingFlags.NonPublic)
?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongListV1<long>)}");
_ensureCapacityV2Func = typeof(RecyclableLongListV2<long>).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.Public)
?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongListV2<long>)}");
_ensureCapacityV3Func = typeof(RecyclableLongListV3<long>).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.NonPublic)
?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongListV3<long>)}");
}
public static void Run()
{
var benchmark = new RecyclableLongListPocBenchmarks();
benchmark.Setup();
// benchmark.RecyclableLongList_EnsureCapacity_ByPowOf2();
// benchmark.RecyclableLongList_EnsureCapacityV1_ByPowOf2();
// benchmark.RecyclableLongList_EnsureCapacityV2_ByPowOf2();
// benchmark.RecyclableLongList_EnsureCapacityV3_ByPowOf2();
// benchmark.RecyclableLongList_EnsureCapacity_ByBlockSize();
// benchmark.RecyclableLongList_EnsureCapacityV1_ByBlockSize();
// benchmark.RecyclableLongList_EnsureCapacityV2_ByBlockSize();
// benchmark.RecyclableLongList_EnsureCapacityV3_ByBlockSize();
benchmark.RecyclableLongList_IndexOf();
benchmark.RecyclableLongList_IndexOfV1();
benchmark.RecyclableLongList_IndexOfV2();
benchmark.RecyclableLongList_IndexOfV3();
benchmark.RecyclableLongList_IndexOfV4();
benchmark.Cleanup();
}
public override void Setup()
{
Console.WriteLine("******* SETTING UP EXPECTED RESULTS DATA *******");
_testArray = DataGenerator.EnumerateTestObjects(TestObjectCount);
base.Setup();
}
public override void Cleanup()
{
_testArray = null;
_testRecyclableLongList?.Dispose();
_testRecyclableLongList = null;
_testRecyclableLongListIndexOfV1?.Dispose();
_testRecyclableLongListIndexOfV1 = null;
_testRecyclableLongListIndexOfV2?.Dispose();
_testRecyclableLongListIndexOfV2 = null;
_testRecyclableLongListIndexOfV3?.Dispose();
_testRecyclableLongListIndexOfV3 = null;
_testRecyclableLongListIndexOfV4?.Dispose();
_testRecyclableLongListIndexOfV4 = null;
_testPooledList?.Dispose();
_testPooledList = null;
base.Cleanup();
}
protected override Action? GetTestMethod(RecyclableLongListPocBenchmarkType benchmarkType) => benchmarkType switch
{
RecyclableLongListPocBenchmarkType.IndexOfV1 => () => RecyclableLongList_IndexOfV1(),
RecyclableLongListPocBenchmarkType.IndexOfV2 => () => RecyclableLongList_IndexOfV2(),
RecyclableLongListPocBenchmarkType.IndexOfV3 => () => RecyclableLongList_IndexOfV3(),
RecyclableLongListPocBenchmarkType.IndexOfV4 => () => RecyclableLongList_IndexOfV4(),
RecyclableLongListPocBenchmarkType.IndexOf_PooledList => () => PooledList_IndexOf(),
RecyclableLongListPocBenchmarkType.IndexOf => () => RecyclableLongList_IndexOf(),
RecyclableLongListPocBenchmarkType.EnsureCapacity_ByPowOf2 => () => RecyclableLongList_EnsureCapacity_ByPowOf2(),
RecyclableLongListPocBenchmarkType.EnsureCapacityV1_ByPowOf2 => () => RecyclableLongList_EnsureCapacityV1_ByPowOf2(),
RecyclableLongListPocBenchmarkType.EnsureCapacityV2_ByPowOf2 => () => RecyclableLongList_EnsureCapacityV2_ByPowOf2(),
RecyclableLongListPocBenchmarkType.EnsureCapacityV3_ByPowOf2 => () => RecyclableLongList_EnsureCapacityV3_ByPowOf2(),
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
protected override void PrepareData<T>(T benchmarkType)
{
base.PrepareData(benchmarkType);
switch (BenchmarkType)
{
case RecyclableLongListPocBenchmarkType.IndexOfV1:
_testRecyclableLongListIndexOfV1 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount);
break;
case RecyclableLongListPocBenchmarkType.IndexOfV2:
_testRecyclableLongListIndexOfV2 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount);
break;
case RecyclableLongListPocBenchmarkType.IndexOfV3:
_testRecyclableLongListIndexOfV3 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount);
break;
case RecyclableLongListPocBenchmarkType.IndexOfV4:
_testRecyclableLongListIndexOfV4 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount);
break;
case RecyclableLongListPocBenchmarkType.IndexOf_PooledList:
_testPooledList = new PooledList<long>(TestObjects, ClearMode.Auto);
break;
case RecyclableLongListPocBenchmarkType.IndexOf:
_testRecyclableLongList = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount);
break;
}
}
}
}
@@ -0,0 +1,26 @@
BenchmarkDotNet=v0.13.3, OS=ubuntu 20.04
Intel Xeon Platinum 8272CL CPU 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK=7.0.203
[Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
DefaultJob : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Ratio | RatioSD |
|------------------------- |--------:|---------:|---------:|------:|--------:|
| RecyclableLongList_IndexOfV1 | 2.274 s | 0.0447 s | 0.0894 s | 1.00 | 0.04 |
| RecyclableLongList_IndexOfV2 | 2.302 s | 0.0456 s | 0.0750 s | 1.00 | 0.00 |
| RecyclableLongList_IndexOf | 2.234 s | 0.0446 s | 0.0681 s | 0.97 | 0.05 |
// * Hints *
Outliers
RecyclableLongListPocBenchmarks.RecyclableLongList_IndexOfV2: Default -> 2 outliers were removed (2.54 s, 2.56 s)
RecyclableLongListPocBenchmarks.RecyclableLongList_IndexOf: Default -> 1 outlier was detected (2.06 s)
// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
Ratio : Mean of the ratio distribution ([Current]/[Baseline])
RatioSD : Standard deviation of the ratio distribution ([Current]/[Baseline])
1 s : 1 Second (1 sec)
@@ -0,0 +1,362 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public class RefVsInstanceMemberPocBenchmarks
{
public static void Run()
{
var benchmark = new RefVsInstanceMemberPocBenchmarks();
benchmark.ArrayInstanceMember2();
benchmark.ArrayInstanceMember3();
benchmark.ArrayInstanceMember4();
benchmark.ArrayInstanceMember5();
benchmark.ArrayInstanceMember6();
benchmark.ArrayInstanceMemberLocalVar5();
benchmark.ArrayInstanceMemberLocalVar6();
benchmark.IntInstanceMember2();
benchmark.IntInstanceMember3();
benchmark.IntInstanceMember4();
benchmark.IntInstanceMember5();
benchmark.RefToArray2();
benchmark.RefToArray3();
benchmark.RefToArray4();
benchmark.RefToArray5();
benchmark.RefToArray6();
benchmark.RefToInt2();
benchmark.RefToInt3();
}
private readonly TestCase _testCase = new();
private static void DoNothing(int count)
{
_ = count;
}
private class TestCase
{
private int[] _items = new int[123];
private int _count = 123;
private static int Add(int count)
{
return count;
}
public int Count
{
get => _count;
set => _count = value;
}
public ref int GetCountAsRefCount2()
{
ref int count = ref _count;
count = 234;
return ref count;
}
public ref int GetCountAsRefCount3()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
return ref count;
}
public ref int GetCountAsRefCount4()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
_ = TestCase.Add(count);
return ref count;
}
public ref int GetCountAsRefCount5()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
_ = TestCase.Add(count);
_ = TestCase.Add(count);
return ref count;
}
public int GetCountAsInstanceMember2()
{
_count = 234;
return _count;
}
public int GetCountAsInstanceMember3()
{
_count = 234;
_ = TestCase.Add(_count);
return _count;
}
public int GetCountAsInstanceMember4()
{
_count = 234;
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
return _count;
}
public int GetCountAsInstanceMember5()
{
_count = 234;
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
return _count;
}
public int GetLengthAsArray2()
{
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray3()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray4()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray5()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray6()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArrayLocalVar5()
{
var items = _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsArrayLocalVar6()
{
var items = _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray2()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray3()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray4()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray5()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray6()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
}
[Benchmark]
public void RefToInt2()
{
var count = _testCase.GetCountAsRefCount2();
DoNothing(count);
}
[Benchmark]
public void RefToInt3()
{
var count = _testCase.GetCountAsRefCount3();
DoNothing(count);
}
[Benchmark]
public void RefToInt4()
{
var count = _testCase.GetCountAsRefCount4();
DoNothing(count);
}
[Benchmark]
public void RefToInt5()
{
var count = _testCase.GetCountAsRefCount5();
DoNothing(count);
}
[Benchmark(Baseline = true)]
public void IntInstanceMember2()
{
var count = _testCase.GetCountAsInstanceMember2();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember3()
{
var count = _testCase.GetCountAsInstanceMember3();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember4()
{
var count = _testCase.GetCountAsInstanceMember4();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember5()
{
var count = _testCase.GetCountAsInstanceMember5();
DoNothing(count);
}
[Benchmark]
public void RefToArray2()
{
var count = _testCase.GetLengthAsRefArray2();
DoNothing(count);
}
[Benchmark]
public void RefToArray3()
{
var count = _testCase.GetLengthAsRefArray3();
DoNothing(count);
}
[Benchmark]
public void RefToArray4()
{
var count = _testCase.GetLengthAsRefArray4();
DoNothing(count);
}
[Benchmark]
public void RefToArray5()
{
var count = _testCase.GetLengthAsRefArray5();
DoNothing(count);
}
[Benchmark]
public void RefToArray6()
{
var count = _testCase.GetLengthAsRefArray6();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember2()
{
var count = _testCase.GetLengthAsArray2();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember3()
{
var count = _testCase.GetLengthAsArray3();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember4()
{
var count = _testCase.GetLengthAsArray4();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember5()
{
var count = _testCase.GetLengthAsArray5();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember6()
{
var count = _testCase.GetLengthAsArray6();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMemberLocalVar5()
{
var count = _testCase.GetLengthAsArrayLocalVar5();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMemberLocalVar6()
{
var count = _testCase.GetLengthAsArrayLocalVar6();
DoNothing(count);
}
}
}
@@ -0,0 +1,45 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum RoundBenchmarkType
{
MathFloor,
MathRound,
WithTypecasting,
}
public class RoundBenchmarks : PocBenchmarkBase<RoundBenchmarkType>
{
[Params(RoundBenchmarkType.MathFloor)]
public override RoundBenchmarkType BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; }
[Params(RoundBenchmarkType.MathRound, RoundBenchmarkType.WithTypecasting)]
public override RoundBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
private const double OptimalParallelSearchStep = 0.329;
public void RoundWithMathFloor()
{
DoNothing((long)Math.Floor(TestObjectCount * OptimalParallelSearchStep));
}
public void RoundWithMathRound()
{
DoNothing((long)Math.Round(TestObjectCount * OptimalParallelSearchStep, 0));
}
public void RoundWithTypeCasting()
{
DoNothing((long)(TestObjectCount * OptimalParallelSearchStep));
}
protected override Action GetTestMethod(RoundBenchmarkType benchmarkType) => benchmarkType switch
{
RoundBenchmarkType.MathFloor => RoundWithMathFloor,
RoundBenchmarkType.MathRound => RoundWithMathRound,
RoundBenchmarkType.WithTypecasting => RoundWithTypeCasting,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
}
}
@@ -0,0 +1,99 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum SpanVsArrayBenchmarkType
{
ArrayGetWithVar,
ArrayGetWithField,
SpanGet,
ArraySetWithVar,
ArraySetWithField,
SpanSet
}
public class SpanVsArrayBenchmarks : RecyclableBenchmarkBase<SpanVsArrayBenchmarkType>
{
// [Params(SpanVsArrayBenchmarkType.ArrayGetWithVar, SpanVsArrayBenchmarkType.SpanGet)]
// [Params(SpanVsArrayBenchmarkType.ArraySetWithVar, SpanVsArrayBenchmarkType.SpanSet)]
[Params
(
SpanVsArrayBenchmarkType.ArrayGetWithVar, SpanVsArrayBenchmarkType.SpanGet,
SpanVsArrayBenchmarkType.ArraySetWithField, SpanVsArrayBenchmarkType.ArraySetWithVar, SpanVsArrayBenchmarkType.SpanSet
)]
public override SpanVsArrayBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
[Params(SpanVsArrayBenchmarkType.ArrayGetWithField)]
// [Params(SpanVsArrayBenchmarkType.ArraySetWithField)]
public override SpanVsArrayBenchmarkType BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; }
protected override Action GetTestMethod(SpanVsArrayBenchmarkType benchmarkType) => benchmarkType switch
{
SpanVsArrayBenchmarkType.ArrayGetWithVar => ArrayGetWithVar,
SpanVsArrayBenchmarkType.ArrayGetWithField => ArrayGetWithField,
SpanVsArrayBenchmarkType.SpanGet => SpanGet,
SpanVsArrayBenchmarkType.ArraySetWithVar => ArraySetWithVar,
SpanVsArrayBenchmarkType.ArraySetWithField => ArraySetWithField,
SpanVsArrayBenchmarkType.SpanSet => SpanSet,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
public void ArrayGetWithVar()
{
var data = TestObjects;
var dataCount = TestObjectCount;
for (long i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void ArrayGetWithField()
{
var dataCount = TestObjectCount;
for (long i = 0; i < dataCount; i++)
{
DoNothing(_testObjects![i]);
}
}
public void SpanGet()
{
var dataCount = TestObjectCount;
Span<long> data = new(_testObjects, 0, dataCount);
for (int i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
public void ArraySetWithVar()
{
var data = TestObjects;
var dataCount = TestObjectCount;
for (long i = 0; i < dataCount; i++)
{
data[i] = i;
}
}
public void ArraySetWithField()
{
var dataCount = TestObjectCount;
for (long i = 0; i < dataCount; i++)
{
_testObjects![i] = i;
}
}
public void SpanSet()
{
var dataCount = TestObjectCount;
Span<long> data = new(_testObjects, 0, dataCount);
for (int i = 0; i < dataCount; i++)
{
data[i] = i;
}
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.ObjectPool;
namespace Recyclable.Collections.Benchmarks.POC
{
[MemoryDiagnoser]
public class TaskRunVsTaskFactoryStartNewBenchmarks
{
public int NumberOfTasks = 100;
private static readonly TaskFactory TaskPool = new();
[Benchmark]
public void OwnTaskFactory()
{
for (var i = 0; i < NumberOfTasks; i++)
{
_ = TaskPool.StartNew(() => {});
}
}
[Benchmark]
public void TaskRun()
{
for (var i = 0; i < NumberOfTasks; i++)
{
_ = Task.Run(() => { });
}
}
[Benchmark(Baseline = true)]
public void TaskFactoryStartNew()
{
for (var i = 0; i < NumberOfTasks; i++)
{
_ = Task.Factory.StartNew(() => { });
}
}
[Benchmark]
public void TaskConstructor()
{
for (var i = 0; i < NumberOfTasks; i++)
{
new Task(() => { }).Start();
}
}
[Benchmark]
public void TaskConstructorWithKnownScheduler()
{
TaskScheduler scheduler = TaskScheduler.Current;
for (var i = 0; i < NumberOfTasks; i++)
{
new Task(() => { }).Start(scheduler);
}
}
}
}
@@ -0,0 +1,346 @@
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.ObjectPool;
using MoreLinq;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum WhenParallelSearchBenchmarkType
{
IndexOfSequentially,
IndexOfParallel,
}
[MemoryDiagnoser]
public class WhenParallelSearchBenchmarks : PocBenchmarkBase<WhenParallelSearchBenchmarkType>
{
#region ItemRange V2
private sealed class ItemRangeV2
{
public int BlockIndex;
public long ItemsToSearchCount;
internal bool _returned;
public ItemRangeV2()
{
}
public ItemRangeV2(int blockIndex, long itemsToSearchCount)
{
BlockIndex = blockIndex;
ItemsToSearchCount = itemsToSearchCount;
}
public void Dispose()
{
if (!_returned)
{
_returned = true;
ItemRangePoolV2.Shared.Return(this);
}
}
}
#endregion
#region ItemRangePoolV2
private static class ItemRangePoolV2
{
private static readonly SpinLock _updateLock = new(false);
public static readonly ObjectPool<ItemRangeV2> Shared = new DefaultObjectPool<ItemRangeV2>(new DefaultPooledObjectPolicy<ItemRangeV2>());
public static ItemRangeV2 Create(int blockIndex, long itemsToSearchCount)
{
bool lockTaken = false;
_updateLock.Enter(ref lockTaken);
var itemRange = Shared.Get();
if (lockTaken)
{
_updateLock.Exit(false);
}
itemRange._returned = false;
itemRange.BlockIndex = blockIndex;
itemRange.ItemsToSearchCount = itemsToSearchCount;
return itemRange;
}
}
#endregion
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32)]
//public int NumberOfThreads { get; set; } = 3;
//[Params(10_000, 20_000, 35_000, 50_000, 75_000, 100_000, 125_000, 150_000, 175_000, 200_000, 225_000, 250_000, 275_000, 300_000, 325_000, 350_000, 375_000, 400_000, 500_000)]
//[Params(320_000, 321_000, 322_000, 323_000, 324_000, 325_000, 326_000, 327_000, 328_000, 329_000, 330_000)]
//[Params(329_000, 512_000, 750_000, 1_000_000, 3_290_000)]
//public int Step { get; set; } = 329_000; // This was the fastest so far
private RecyclableLongList<long>? _testData;
public object? ItemToFind { get; set; }
[Params(WhenParallelSearchBenchmarkType.IndexOfParallel)]
public override WhenParallelSearchBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; }
[Params(WhenParallelSearchBenchmarkType.IndexOfSequentially)]
public override WhenParallelSearchBenchmarkType BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; }
private long DoLongIndexOfSequentially()
{
// This won't work for TestObjectCount == 0
int index;
int blockSize = _testData!.BlockSize;
int lastBlockWithData = _testData.LastBlockWithData;
var memoryBlocks = _testData.AsArray;
var itemToFind = ItemToFind;
int blockIndex = 0;
while (true)
{
index = Array.IndexOf(memoryBlocks[blockIndex], itemToFind, 0, blockSize);
if (index >= 0)
{
return (blockIndex << _testData.BlockSizePow2BitShift) + index;
}
if (blockIndex + 1 < lastBlockWithData)
{
blockIndex++;
}
else
{
break;
}
}
index = lastBlockWithData == _testData.NextItemBlockIndex
? Array.IndexOf(memoryBlocks[lastBlockWithData], itemToFind, 0, _testData.NextItemIndex)
: Array.IndexOf(memoryBlocks[lastBlockWithData], itemToFind, 0, blockSize);
return index >= 0 ? (lastBlockWithData << _testData.BlockSizePow2BitShift) + index : -1;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static long DoLongIndexOfParallel(RecyclableLongList<long> list, in long itemToFind, ItemRangeV2 searchInfo, ManualResetEventSlim itemFoundSignal)
{
int index;
int blockSize = list.BlockSize;
int blockIndex = searchInfo.BlockIndex;
long itemsToSearchCount = searchInfo.ItemsToSearchCount;
long[][] memoryBlocks = list.AsArray;
index = Array.IndexOf(memoryBlocks[searchInfo.BlockIndex], itemToFind, 0, blockSize);
if (itemFoundSignal.IsSet)
{
return -1;
}
else if (index >= 0)
{
return (blockIndex << list.BlockSizePow2BitShift) + index;
}
itemsToSearchCount -= blockSize;
if (itemsToSearchCount < 0)
{
return -1;
}
int lastBlockWithData = blockIndex + (int)(itemsToSearchCount >> list.BlockSizePow2BitShift) + ((itemsToSearchCount & (list.BlockSize - 1)) > 0 ? 1 : 0);
blockIndex++;
while (true)
{
index = Array.IndexOf(memoryBlocks[blockIndex], itemToFind, 0, blockSize);
if (itemFoundSignal.IsSet)
{
return -1;
}
else if (index >= 0)
{
return ((long)blockIndex << list.BlockSizePow2BitShift) + index;
}
itemsToSearchCount -= blockSize;
if (blockIndex + 1 < lastBlockWithData && itemsToSearchCount < 0)
{
blockIndex++;
}
else
{
break;
}
}
index = itemsToSearchCount < 0 || itemFoundSignal.IsSet || lastBlockWithData > list.NextItemBlockIndex
? -1
: lastBlockWithData == list.NextItemBlockIndex
? Array.IndexOf(memoryBlocks[lastBlockWithData], itemToFind, 0, checked((int)Math.Min(list.NextItemIndex, itemsToSearchCount)))
: Array.IndexOf(memoryBlocks[lastBlockWithData], itemToFind, 0, checked((int)Math.Min(blockSize, itemsToSearchCount)));
return itemFoundSignal.IsSet || index < 0 ? -1 : ((long)lastBlockWithData << list.BlockSizePow2BitShift) + index;
}
private long DoIndexOfParallel()
{
using var itemFoundSignal = new ManualResetEventSlim(false);
using var allDoneSignal = new Barrier(1);
//long step = Step;// TestObjectCount / NumberOfThreads;
int blockSize = _testData!.BlockSize;
//object[][] memoryBlocks = _testData.AsArray();
//long itemsRemaining = testObjectCount;
var foundItemIndex = -1L;
var itemToFind = ItemToFind;
//ItemRangesIterator.Iterate(0, blockSize, BlockSizePow2BitShift, TestObjectCount, (long)(TestObjectCount * 0.329), (searchInfo) =>
//{
// _ = allDoneSignal.AddParticipant();
// _ = Task.Factory.StartNew((state) =>
// {
// try
// {
// var index = DoLongIndexOfParallel(_testData, itemToFind, searchInfo, itemFoundSignal);
// if (index >= 0)
// {
// itemFoundSignal.Set();
// lock (itemFoundSignal)
// {
// foundItemIndex = index;
// }
// }
// }
// finally
// {
// lock (allDoneSignal)
// {
// allDoneSignal.RemoveParticipant();
// }
// }
// }, state: searchInfo);
// return !itemFoundSignal.IsSet;
//});
//while (true)
//{
// var toGive = Math.Min(step, itemsRemaining);
// SearchInfo<object> searchInfo = new(
// blockIndex: blockIndex,
// startingItemIndex: itemIndex,
// itemsToSearchCount: toGive,
// itemToFind: ItemToFind,
// itemFoundSignal: itemFoundSignal);
// _ = Task.Factory.StartNew((state) =>
// {
// try
// {
// var index = DoLongIndexOfParallel(_testData, (SearchInfo<object>)state!);
// if (index >= 0)
// {
// itemFoundSignal.Set();
// lock (itemFoundSignal)
// {
// foundItemIndex = index;
// }
// }
// }
// finally
// {
// lock (allDoneSignal)
// {
// allDoneSignal.RemoveParticipant();
// }
// }
// }, state: searchInfo);
// //itemIndex = checked((int)((itemIndex + toGive) >> BlockSizePow2BitShift)) - 1;
// while (toGive > 0)
// {
// if (itemIndex + toGive < blockSize)
// {
// itemIndex += (int)toGive;
// break;
// }
// else
// {
// blockIndex++;
// //itemIndex += blockSize;
// //if (itemIndex > blockSize)
// //{
// // itemIndex
// //}
// //if (itemIndex + blockSize < )
// //itemIndex = (int)(toGive - blockSize + itemIndex);
// toGive -= blockSize;
// }
// //if (blockIndex == _testData.LastBlockWithData)
// //{
// // itemIndex = checked((int)toGive);
// // break;
// //}
// }
// if (threadIndex + 1 < numberOfRanges && blockIndex <= _testData.LastBlockWithData)
// {
// threadIndex++;
// }
// else
// {
// break;
// }
//}
allDoneSignal.SignalAndWait();
throw new NotImplementedException();
return foundItemIndex;
}
protected override void PrepareData<T>(T benchmarkType)
{
base.PrepareData(benchmarkType);
_testData ??= Enumerable.Range(1, TestObjectCount).Cast<long>().ToRecyclableLongList(BlockSize);
ItemToFind ??= _testData.Last();
}
protected override Action? GetTestMethod(WhenParallelSearchBenchmarkType benchmarkType) => BenchmarkType switch
{
WhenParallelSearchBenchmarkType.IndexOfSequentially => IndexOfSequentially,
WhenParallelSearchBenchmarkType.IndexOfParallel => IndexOfParallel,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
public override void Cleanup()
{
_testData = default;
base.Cleanup();
}
public void IndexOfSequentially()
{
long index = DoLongIndexOfSequentially();
if (index >= 0)
{
DoNothing(index);
}
else
{
throw new Exception("Item not found");
}
}
public void IndexOfParallel()
{
var index = DoIndexOfParallel();
if (index >= 0)
{
DoNothing(index);
}
else
{
throw new Exception("Item not found");
}
}
}
}
+53 -31
View File
@@ -1,8 +1,11 @@
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Recyclable.Collections.Benchmarks;
using Recyclable.Collections.Benchmarks.POC;
BenchmarkRunner.Run<ListVsLinkedListBenchmark>();
//BenchmarkRunner.Run<DelegateVsComparerBenchmark>();
public class Program
{
static IConfig BenchmarkConfig { get; } = ManualConfig.Create(DefaultConfig.Instance).WithOptions(ConfigOptions.DisableOptimizationsValidator | ConfigOptions.JoinSummary);
static void RunAssemblyBenchmarks()
{
@@ -19,40 +22,59 @@ BenchmarkRunner.Run<ListVsLinkedListBenchmark>();
// ****************
// *** Template ***
// ****************
var benchmark = new RecyclableCollectionsBenchmarks();
benchmark.Setup();
benchmark.RecyclableLongList_IndexOf_BestAndWorstCases();
benchmark.Cleanup();
//var benchmark = new RecyclableCollectionsBenchmarks();
//benchmark.Setup();
//foreach (var _ in Enumerable.Range(1, 1000))
//{
static void RunAssemblyBenchmarks()
{
_ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(new[] { "-f*" });
}
static void RunRecyclableCollectionsBenchmarks()
{
_ = BenchmarkRunner.Run<RecyclableCollectionsBenchmarks>(BenchmarkConfig);
}
static void RunSelectedBenchmarks()
{
// ****************
// *** Template ***
// ****************
var benchmark = new RecyclableCollectionsBenchmarks();
benchmark.Setup();
benchmark.RecyclableLongList_IndexOf_BestAndWorstCases();
benchmark.Cleanup();
//foreach (var _ in Enumerable.Range(1, 1000))
//{
// benchmark.RecyclableLongList_Remove_FirstItems();
// benchmark.RecyclableLongList_RemoveAt_LastItems();
// benchmark.List_RemoveAt_LastItems();
//}
//}
//benchmark.Cleanup();
}
//benchmark.Cleanup();
}
static void RunPocBenchmarks()
{
//_ = BenchmarkRunner.Run<BoolOrComparePocBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<DelegateVsComparerPocBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<ModuloPocBenchmarks>(BenchmarkConfig);
// _ = BenchmarkRunner.Run<RecyclableLongListPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<TaskRunVsTaskFactoryStartNewBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<RefVsInstanceMemberPocBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<WhenParallelSearchBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<RoundBenchmarks>(BenchmarkConfig);
// _ = BenchmarkRunner.Run<SpanVsArrayBenchmarks>(BenchmarkConfig);
// ArraySizeLimitPocBenchmarks>(BenchmarkConfig);
}
static void RunPocBenchmarks()
{
_ = BenchmarkRunner.Run<BoolOrComparePocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<DelegateVsComparerPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<ModuloPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<RecyclableLongListPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<TaskRunVsTaskFactoryStartNewBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<RefVsInstanceMemberPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<WhenParallelSearchBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<RoundBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<SpanVsArrayBenchmarks>(BenchmarkConfig);
// ArraySizeLimitPocBenchmarks>(BenchmarkConfig);
}
private static void Main(string[] args)
{
RunRecyclableCollectionsBenchmarks();
// RunPocBenchmarks();
// RunSelectedBenchmarks();
// RunAssemblyBenchmarks();
static void Main(string[] args)
{
RunRecyclableCollectionsBenchmarks();
// RunPocBenchmarks();
// RunSelectedBenchmarks();
// RunAssemblyBenchmarks();
}
}
}
@@ -0,0 +1,12 @@
{
"profiles": {
"WSL": {
"commandName": "WSL2",
"distributionName": ""
},
".Net": {
"commandName": "Project",
"nativeDebugging": true
}
}
}
@@ -6,10 +6,12 @@
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.3" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="Collections.Pooled" Version="1.0.82" />
<PackageReference Include="JonSkeet.MiscUtil" Version="0.2.0" />
</ItemGroup>
@@ -0,0 +1,340 @@
using BenchmarkDotNet.Attributes;
using Collections.Pooled;
using Recyclable.Collections.Benchmarks.Core;
using Recyclable.Collections.Benchmarks.POC;
namespace Recyclable.Collections.Benchmarks
{
public enum RecyclableCollectionsBenchmarkSource
{
Unknown,
Array,
List,
PooledList,
RecyclableList,
RecyclableLongList,
}
[MemoryDiagnoser]
public class RecyclableBenchmarkBase<TBenchmarkType> : PocBenchmarkBase<TBenchmarkType>
{
protected long[]? _testObjects;
protected long[] TestObjects => _testObjects ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected List<long>? _testObjectsAsList;
protected List<long> TestObjectsAsList => _testObjectsAsList ?? throw new NullReferenceException("Something went wront and the field is not initialized");
protected PooledList<long>? _testObjectsAsPooledList;
public PooledList<long> TestObjectsAsPooledList => _testObjectsAsPooledList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected RecyclableList<long>? _testObjectsAsRecyclableList;
protected RecyclableList<long> TestObjectsAsRecyclableList => _testObjectsAsRecyclableList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected RecyclableLongList<long>? _testObjectsAsRecyclableLongList;
protected RecyclableLongList<long> TestObjectsAsRecyclableLongList => _testObjectsAsRecyclableLongList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected IEnumerable<long> TestObjectsAsIEnumerable
{
get
{
for (long i = 0; i < TestObjectCount; i++)
{
yield return i;
}
}
}
public override void Setup()
{
PrepareData(RecyclableCollectionsBenchmarkSource.Array);
base.Setup();
}
protected override void PrepareData<T>(T benchmarkType)
{
Console.WriteLine($"******* PREPARING DATA FOR {benchmarkType} *******");
switch (benchmarkType)
{
case RecyclableCollectionsBenchmarkSource.Unknown:
break;
case RecyclableCollectionsBenchmarkSource.Array:
_testObjects ??= DataGenerator.EnumerateTestObjects(TestObjectCount);
break;
case RecyclableCollectionsBenchmarkSource.List:
_testObjectsAsList ??= TestObjects.ToList();
break;
case RecyclableCollectionsBenchmarkSource.PooledList:
_testObjectsAsPooledList ??= new PooledList<long>(TestObjects, ClearMode.Auto);
break;
case RecyclableCollectionsBenchmarkSource.RecyclableList:
_testObjectsAsRecyclableList ??= new(TestObjects, initialCapacity: TestObjectCount);
break;
case RecyclableCollectionsBenchmarkSource.RecyclableLongList:
_testObjectsAsRecyclableLongList ??= new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount);
break;
default:
throw CreateUnknownBenchmarkTypeException(benchmarkType);
}
base.PrepareData(benchmarkType);
}
public override void Cleanup()
{
Console.WriteLine("******* GLOBAL CLEANUP *******");
// Enable this if item type is changed to reference type
//if (_testObjects != null)
//{
// Array.Fill(_testObjects, 0);
//}
_testObjects = default;
_testObjectsAsList = default;
_testObjectsAsPooledList?.Dispose();
_testObjectsAsPooledList = default;
_testObjectsAsRecyclableList?.Dispose();
_testObjectsAsRecyclableList = default;
_testObjectsAsRecyclableLongList?.Dispose();
_testObjectsAsRecyclableLongList = default;
base.Cleanup();
}
}
//[MemoryDiagnoser]
//public class ListVsLinkedListBenchmarks
//{
// [Benchmark]
// public void RecyclableList()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// using var list = new RecyclableList<object>(initialCapacity: dataCount);
// for (long i = 0; i < dataCount; i++)
// {
// list.Add(data[i]);
// }
// for (long i = 0; i < list.LongCount; i++)
// {
// DoNothing(list[i]);
// }
// list.Clear();
// }
// [Benchmark(Baseline = true)]
// public void RecyclableLongList()
// {
// var data = TestObjects;
// long dataCount = TestObjectCount;
// using var list = new RecyclableLongList<object>(BlockSize, totalItemsCount: dataCount);
// for (long i = 0; i < dataCount; i++)
// {
// list.Add(data[i]);
// }
// for (long i = 0; i < list.LongCount; i++)
// {
// DoNothing(list[i]);
// }
// list.Clear();
// }
// //[Benchmark]
// public void List()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new List<object>(capacity: dataCount);
// for (var i = 0; i < dataCount; i++)
// {
// list.Add(data[i]);
// }
// for (var i = 0; i < list.Count; i++)
// {
// DoNothing(list[i]);
// }
// list.Clear();
// }
// //[Benchmark]
// public void LinkedList()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new LinkedList<object>();
// for (var i = 0; i < dataCount; i++)
// {
// _ = list.AddLast(data[i]);
// }
// foreach (var node in list)
// {
// DoNothing(node);
// }
// list.Clear();
// }
// //[Benchmark]
// public void RecyclableQueue()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new RecyclableQueue<object>(BlockSize);
// for (var i = 0; i < dataCount; i++)
// {
// list.Enqueue(data[i]);
// }
// while (list.LongCount > 0)
// {
// DoNothing(list.Dequeue());
// }
// list.Clear();
// }
// //[Benchmark]
// public void Queue()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new Queue<object>(capacity: dataCount);
// for (var i = 0; i < dataCount; i++)
// {
// list.Enqueue(data[i]);
// }
// while (list.Count > 0)
// {
// DoNothing(list.Dequeue());
// }
// list.Clear();
// }
// //[Benchmark]
// public void PriorityQueue()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new PriorityQueue<object, long>(initialCapacity: dataCount);
// for (var i = 0; i < dataCount; i++)
// {
// list.Enqueue(data[i], i);
// }
// while (list.Count > 0)
// {
// DoNothing(list.Dequeue());
// }
// list.Clear();
// }
// //[Benchmark]
// public void RecyclableSortedList_InUpdateMode()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new RecyclableSortedList<long, object>(BlockSize);
// list.BeginUpdate();
// for (var i = 0; i < dataCount; i++)
// {
// list.Add(i, data[i]);
// }
// list.EndUpdate();
// for (var i = 0; i < list.LongCount; i++)
// {
// DoNothing(list[i]);
// }
// list.Clear();
// }
// //[Benchmark]
// public void RecyclableSortedList()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new RecyclableSortedList<long, object>(BlockSize);
// for (var i = 0; i < dataCount; i++)
// {
// list.Add(i, data[i]);
// }
// for (var i = 0; i < list.LongCount; i++)
// {
// DoNothing(list[i]);
// }
// list.Clear();
// }
// //[Benchmark]
// public void SortedList()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new SortedList<long, object>();
// for (var i = 0; i < dataCount; i++)
// {
// list.Add(i, data[i]);
// }
// for (var i = 0; i < list.Count; i++)
// {
// DoNothing(list[i]);
// }
// list.Clear();
// }
// //[Benchmark]
// public void RecyclableStack()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new RecyclableStack<object>(BlockSize);
// for (var i = 0; i < dataCount; i++)
// {
// list.Push(data[i]);
// }
// while (list.LongCount > 0)
// {
// DoNothing(list.Pop());
// }
// list.Clear();
// }
// //[Benchmark]
// public void Stack()
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new Stack<object>();
// for (var i = 0; i < dataCount; i++)
// {
// list.Push(data[i]);
// }
// while (list.Count > 0)
// {
// DoNothing(list.Pop());
// }
// list.Clear();
// }
//}
}
@@ -0,0 +1,122 @@
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|------------------------------------------------------------ |-----------------------:|--------------------:|--------------------:|-----------------------:|-----------:|--------:|----------:|----------:|---------:|-----------:|------------:|
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|------------------------------------------------------------ |-----------:|---------:|---------:|------:|--------:|--------:|--------:|--------:|----------:|------------:|
| Array_Create_WithCapacity | 2,447.9 us | 8.35 us | 7.40 us | 1.99 | 0.02 | 58.5938 | 58.5938 | 58.5938 | 8000061 B | 137,932.09 |
| List_Create_WithCapacity | 2,377.6 us | 43.03 us | 40.25 us | 1.93 | 0.03 | 54.6875 | 54.6875 | 54.6875 | 8000451 B | 137,938.81 |
| PooledList_Create_WithCapacity | 1,229.4 us | 10.70 us | 9.48 us | 1.00 | 0.00 | - | - | - | 58 B | 1.00 |
| RecyclableList_Create_WithCapacity | 1,233.9 us | 3.93 us | 3.68 us | 1.00 | 0.01 | - | - | - | 41 B | 0.71 |
| RecyclableLongList_Create_WithCapacity | 786.5 us | 2.32 us | 1.94 us | 0.64 | 0.01 | - | - | - | 425 B | 7.33 |
| List_Create | 3.5523 ns | 0.0181 ns | 0.0141 ns | 3.5476 ns | 0.000 | 0.00 | 0.0153 | - | - | 32 B | 0.000 |
| PooledList_Create | 6.9236 ns | 0.0110 ns | 0.0098 ns | 6.9222 ns | 0.000 | 0.00 | 0.0268 | - | - | 56 B | 0.000 |
| RecyclableList_Create | 4.6451 ns | 0.0063 ns | 0.0053 ns | 4.6457 ns | 0.000 | 0.00 | 0.0191 | - | - | 40 B | 0.000 |
| RecyclableLongList_Create | 212.8164 ns | 11.9841 ns | 35.3355 ns | 213.2258 ns | 0.000 | 0.00 | 0.0381 | 0.0379 | - | 80 B | 0.000 |
Array_GetItem | 239.7 us | 0.36 us | 0.32 us | 0.66 | 0.00 | - | NA |
List_GetItem | 363.5 us | 0.67 us | 0.56 us | 1.00 | 0.00 | - | NA |
PooledList_GetItem | 365.3 us | 0.90 us | 0.75 us | 1.00 | 0.00 | - | NA |
RecyclableList_GetItem | 239.2 us | 0.07 us | 0.06 us | 0.65 | 0.00 | - | NA |
RecyclableLongList_GetItem | 538.0 us | 1.01 us | 0.89 us | 1.47 | 0.00 | 1 B | NA |
RecyclableLongList_GetItem_AsSpan | 673.5 us | 4.85 us | 4.30 us | 1.84 | 0.01 | 1 B | NA |
RecyclableLongList_GetItem_AsArray | 239.4 us | 0.22 us | 0.20 us | 0.66 | 0.00 | - | NA |
RecyclableLongList_GetItem_AsForEach | 5,514.6 us | 27.28 us | 22.78 us | 15.10 | 0.06 | 109 B | NA |
RecyclableLongList_GetItem_AsWhile | 459.3 us | 0.38 us | 0.34 us | 1.26 | 0.00 | - | NA |
| Array_SetItem | 2,576,086.8389 ns | 13,880.4584 ns | 11,590.8114 ns | 2,576,978.1250 ns | 2.194 | 0.01 | - | - | - | 2 B | 0.000 |
| List_SetItem | 3,361,745.7734 ns | 98,390.1277 ns | 290,105.5114 ns | 3,505,120.8984 ns | 2.771 | 0.29 | - | - | - | 2 B | 0.000 |
| PooledList_SetItem | 2,676,757.7524 ns | 1,228.8178 ns | 1,026.1185 ns | 2,676,991.4062 ns | 2.280 | 0.01 | - | - | - | 2 B | 0.000 |
| RecyclableList_SetItem | 2,547,059.6540 ns | 9,002.9953 ns | 7,980.9208 ns | 2,542,056.8359 ns | 2.170 | 0.01 | - | - | - | 2 B | 0.000 |
| RecyclableLongList_SetItem | 2,326,771.9866 ns | 3,186.0942 ns | 2,824.3895 ns | 2,326,636.7188 ns | 1.981 | 0.01 | - | - | - | 2 B | 0.000 |
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|------------------------------------------------------------ |----------:|----------:|----------:|------:|--------:|---------:|--------:|--------:|-----------:|------------:|
| List_Add | 11.002 ms | 0.2189 ms | 0.2996 ms | 1.36 | 0.04 | 140.6250 | 93.7500 | 93.7500 | 16778117 B | 236,311.51 |
| PooledList_Add | 8.117 ms | 0.0115 ms | 0.0102 ms | 1.00 | 0.00 | - | - | - | 71 B | 1.00 |
| RecyclableList_Add | 8.771 ms | 0.0169 ms | 0.0141 ms | 1.08 | 0.00 | - | - | - | 1233 B | 17.37 |
| RecyclableLongList_Add | 6.024 ms | 0.1101 ms | 0.1030 ms | 0.74 | 0.01 | - | - | - | 3317 B | 46.72 |
| List_Add_WithCapacity | 3,724,682.0668 ns | 88,719.4866 ns | 260,198.8962 ns | 3,717,873.0469 ns | 3.326 | 0.09 | 50.7813 | 50.7813 | 50.7813 | 4000368 B | 1.000 |
| PooledList_Add_WithCapacity | 2,575,618.8337 ns | 5,277.9410 ns | 4,678.7572 ns | 2,575,805.2734 ns | 2.194 | 0.01 | - | - | - | 60 B | 0.000 |
| RecyclableList_Add_WithCapacity | 2,785,606.2500 ns | 4,595.4354 ns | 4,073.7338 ns | 2,785,292.7734 ns | 2.372 | 0.01 | - | - | - | 42 B | 0.000 |
| RecyclableLongList_Add_WithCapacity | 2,878,685.9701 ns | 44,974.7609 ns | 35,113.3350 ns | 2,873,102.9297 ns | 2.453 | 0.03 | - | - | - | 170 B | 0.000 |
| List_AddRangeWhenSourceIsArray | 1,966,607.1581 ns | 39,075.4380 ns | 100,165.2861 ns | 1,958,457.4219 ns | 1.721 | 0.07 | 42.9688 | 42.9688 | 42.9688 | 4000364 B | 1.000 |
| PooledList_AddRangeWhenSourceIsArray | 972,973.4049 ns | 12,365.6121 ns | 11,566.8012 ns | 974,744.8242 ns | 0.829 | 0.01 | - | - | - | 57 B | 0.000 |
| RecyclableList_AddRangeWhenSourceIsArray | 1,098,651.7578 ns | 3,202.7829 ns | 2,995.8851 ns | 1,097,979.4922 ns | 0.936 | 0.00 | - | - | - | 41 B | 0.000 |
| RecyclableLongList_AddRangeWhenSourceIsArray | 1,023,799.0234 ns | 2,772.1984 ns | 2,457.4816 ns | 1,023,618.7500 ns | 0.872 | 0.00 | - | - | - | 169 B | 0.000 |
| List_AddRangeWhenSourceIsList | 1,954,805.9462 ns | 37,631.3829 ns | 71,597.6170 ns | 1,947,531.6406 ns | 1.656 | 0.06 | 42.9688 | 42.9688 | 42.9688 | 4000363 B | 1.000 |
| PooledList_AddRangeWhenSourceIsList | 963,657.7116 ns | 5,594.8195 ns | 5,233.3976 ns | 965,055.4199 ns | 0.820 | 0.01 | - | - | - | 57 B | 0.000 |
| RecyclableList_AddRangeWhenSourceIsList | 1,114,697.8385 ns | 4,015.8164 ns | 3,756.3971 ns | 1,115,863.6719 ns | 0.950 | 0.00 | - | - | - | 41 B | 0.000 |
| RecyclableLongList_AddRangeWhenSourceIsList | 1,008,424.0374 ns | 2,179.7502 ns | 1,932.2918 ns | 1,008,779.8828 ns | 0.859 | 0.00 | - | - | - | 169 B | 0.000 |
| List_AddRangeWhenSourceIsIList | 2,045,453.8895 ns | 40,653.4327 ns | 98,956.0738 ns | 2,040,041.7969 ns | 1.734 | 0.12 | 42.9688 | 42.9688 | 42.9688 | 4000366 B | 1.000 |
| PooledList_AddRangeWhenSourceIsIList | 977,402.4790 ns | 4,165.1933 ns | 3,478.1251 ns | 978,420.3125 ns | 0.832 | 0.00 | - | - | - | 58 B | 0.000 |
| RecyclableList_AddRangeWhenSourceIsIList | 1,109,563.8477 ns | 4,480.2733 ns | 4,190.8505 ns | 1,108,281.9336 ns | 0.945 | 0.00 | - | - | - | 41 B | 0.000 |
| RecyclableLongList_AddRangeWhenSourceIsIList | 2,632,797.0052 ns | 3,899.2563 ns | 3,044.2828 ns | 2,632,267.1875 ns | 2.243 | 0.01 | - | - | - | 170 B | 0.000 |
| PooledList_AddRangeWhenSourceIsIEnumerable | 28,102,425.4630 ns | 556,294.1092 ns | 779,846.6478 ns | 28,009,543.7500 ns | 24.007 | 0.74 | 2187.5000 | 1375.0000 | 218.7500 | 12000526 B | 3.000 |
| List_AddRangeWhenSourceIsIEnumerable | 47,884,030.8442 ns | 955,391.3313 ns | 1,370,193.6989 ns | 48,152,172.7273 ns | 40.578 | 1.04 | 2272.7273 | 1363.6364 | 363.6364 | 20389288 B | 5.097 |
| RecyclableList_AddRangeWhenSourceIsIEnumerable | 27,102,237.2533 ns | 535,598.7947 ns | 595,316.6412 ns | 27,248,382.8125 ns | 23.009 | 0.61 | 2250.0000 | 1406.2500 | 250.0000 | 12000305 B | 3.000 |
| RecyclableLongList_AddRangeWhenSourceIsIEnumerable | 27,206,882.1023 ns | 517,997.7196 ns | 636,147.7188 ns | 27,262,153.1250 ns | 23.049 | 0.64 | 2218.7500 | 1468.7500 | 250.0000 | 12000361 B | 3.000 |
| PooledList_AddRangeWhenSourceIsPooledList | 958,132.3033 ns | 4,444.5508 ns | 3,939.9785 ns | 957,355.9570 ns | 0.816 | 0.00 | - | - | - | 57 B | 0.000 |
| RecyclableList_AddRangeWhenSourceIsRecyclableList | 1,068,135.4492 ns | 15,036.9473 ns | 12,556.5320 ns | 1,063,337.2070 ns | 0.910 | 0.01 | - | - | - | 41 B | 0.000 |
| RecyclableLongList_AddRangeWhenSourceIsRecyclableList | 1,057,253.7249 ns | 2,697.5224 ns | 2,391.2834 ns | 1,057,475.9766 ns | 0.901 | 0.00 | - | - | - | 169 B | 0.000 |
| List_AddRange_WithCapacity | 2,022,247.3039 ns | 44,489.4467 ns | 129,071.9520 ns | 2,030,418.9453 ns | 1.767 | 0.06 | 39.0625 | 39.0625 | 39.0625 | 4000318 B | 1.000 |
| PooledList_AddRange_WithCapacity | 965,635.9570 ns | 11,740.2154 ns | 10,981.8048 ns | 968,593.2617 ns | 0.822 | 0.01 | - | - | - | 57 B | 0.000 |
| RecyclableList_AddRange_WithCapacity | 1,044,438.5517 ns | 3,047.5353 ns | 2,544.8300 ns | 1,045,038.8672 ns | 0.890 | 0.00 | - | - | - | 41 B | 0.000 |
| RecyclableLongList_AddRange_WithCapacity | 1,028,953.5156 ns | 17,735.8499 ns | 14,810.2379 ns | 1,022,104.4922 ns | 0.876 | 0.01 | - | - | - | 169 B | 0.000 |
| Array_Count | 0.0087 ns | 0.0110 ns | 0.0103 ns | 0.0024 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| List_Count | 1.2190 ns | 0.0046 ns | 0.0040 ns | 1.2173 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| PooledList_Count | 0.0037 ns | 0.0015 ns | 0.0012 ns | 0.0040 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| RecyclableList_Count | 1.2096 ns | 0.0009 ns | 0.0008 ns | 1.2092 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| RecyclableLongList_Count | 0.0103 ns | 0.0008 ns | 0.0007 ns | 0.0102 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| Array_LongCount | 0.0021 ns | 0.0005 ns | 0.0004 ns | 0.0022 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| RecyclableLongList_LongCount | 0.0030 ns | 0.0004 ns | 0.0003 ns | 0.0031 ns | 0.000 | 0.00 | - | - | - | - | 0.000 |
| List_Contains_FirstItems | 1,855,720,661.5385 ns | 16,632,292.4881 ns | 13,888,717.5079 ns | 1,850,307,400.0000 ns | 1,580.480 | 10.24 | - | - | - | 600 B | 0.000 |
| PooledList_Contains_FirstItems | 1,854,542,814.2857 ns | 3,151,361.3032 ns | 2,793,599.7119 ns | 1,855,147,650.0000 ns | 1,579.345 | 5.84 | - | - | - | 600 B | 0.000 |
| RecyclableLongList_Contains_FirstItems | 1,842,715,553.8462 ns | 5,837,438.3043 ns | 4,874,525.3630 ns | 1,840,917,300.0000 ns | 1,569.420 | 6.23 | - | - | - | 600 B | 0.000 |
| List_Contains_LastItems | 56,934,350,853.3333 ns | 257,718,254.2389 ns | 241,069,814.9149 ns | 56,884,611,800.0000 ns | 48,516.143 | 270.39 | - | - | - | 600 B | 0.000 |
| PooledList_Contains_LastItems | 57,262,565,633.3333 ns | 295,685,051.7358 ns | 276,583,980.8497 ns | 57,246,796,900.0000 ns | 48,801.131 | 237.64 | - | - | - | 600 B | 0.000 |
| RecyclableLongList_Contains_LastItems | 57,019,747,564.2857 ns | 264,241,719.1753 ns | 234,243,401.3552 ns | 57,059,345,900.0000 ns | 48,552.402 | 223.09 | - | - | - | 600 B | 0.000 |
| Array_IndexOf_FirstItems | 1,874,810,260.0000 ns | 25,774,115.5271 ns | 24,109,123.6555 ns | 1,867,388,700.0000 ns | 1,597.521 | 22.54 | - | - | - | 600 B | 0.000 |
| List_IndexOf_FirstItems | 1,864,704,725.0000 ns | 10,982,470.8154 ns | 8,574,390.8164 ns | 1,866,253,200.0000 ns | 1,588.702 | 10.94 | - | - | - | 600 B | 0.000 |
| PooledList_IndexOf_FirstItems | 1,840,856,800.0000 ns | 4,046,589.8784 ns | 3,159,311.2037 ns | 1,839,944,050.0000 ns | 1,568.374 | 6.17 | - | - | - | 600 B | 0.000 |
| RecyclableList_IndexOf_FirstItems | 1,832,934,950.0000 ns | 1,729,308.0131 ns | 1,350,129.9476 ns | 1,832,475,300.0000 ns | 1,561.625 | 5.52 | - | - | - | 600 B | 0.000 |
| RecyclableLongList_IndexOf_FirstItems | 1,844,986,792.3077 ns | 3,209,050.1952 ns | 2,679,702.2516 ns | 1,843,943,600.0000 ns | 1,571.359 | 6.49 | - | - | - | 600 B | 0.000 |
| RecyclableLongList_LongIndexOf_FirstItems | 1,878,933,500.0000 ns | 17,118,131.6171 ns | 16,012,310.9355 ns | 1,870,009,600.0000 ns | 1,601.616 | 14.82 | - | - | - | 600 B | 0.000 |
| List_IndexOf_LastItems | 57,303,575,140.0000 ns | 297,612,744.3548 ns | 278,387,145.7216 ns | 57,391,576,000.0000 ns | 48,792.865 | 303.56 | - | - | - | 600 B | 0.000 |
| PooledList_IndexOf_LastItems | 57,032,399,106.6667 ns | 281,241,865.3817 ns | 263,073,815.3730 ns | 56,895,992,200.0000 ns | 48,566.622 | 322.88 | - | - | - | 600 B | 0.000 |
| RecyclableLongList_IndexOf_LastItems | 57,308,279,713.3333 ns | 272,718,905.6589 ns | 255,101,433.5602 ns | 57,297,645,400.0000 ns | 48,767.562 | 239.96 | - | - | - | 600 B | 0.000 |
| RecyclableLongList_LongIndexOf_LastItems | 57,198,323,460.0000 ns | 282,971,632.5816 ns | 264,691,840.6850 ns | 57,198,418,300.0000 ns | 48,669.107 | 304.11 | - | - | - | 600 B | 0.000 |
| List_Remove_FirstItems | 5,023,030,012.5000 ns | 82,615,052.4052 ns | 107,422,903.9562 ns | 5,000,417,000.0000 ns | 4,295.171 | 116.37 | - | - | - | 4000656 B | 1.000 |
| PooledList_Remove_FirstItems | 4,750,601,721.4286 ns | 17,989,258.8487 ns | 15,947,009.4038 ns | 4,747,622,550.0000 ns | 4,043.997 | 21.26 | - | - | - | 992 B | 0.000 |
| RecyclableList_Remove_FirstItems | 4,950,634,900.0000 ns | 33,761,094.2570 ns | 29,928,330.6849 ns | 4,936,519,050.0000 ns | 4,218.075 | 23.90 | - | - | - | 640 B | 0.000 |
| RecyclableLongList_Remove_FirstItems | 5,020,383,250.0000 ns | 100,209,734.5497 ns | 115,401,679.3276 ns | 5,029,163,750.0000 ns | 4,306.772 | 86.95 | - | - | - | 952 B | 0.000 |
| List_Remove_LastItems | 56,593,869,333.3333 ns | 258,693,958.6041 ns | 241,982,489.3835 ns | 56,513,091,800.0000 ns | 48,189.227 | 272.02 | - | - | - | 4000656 B | 1.000 |
| PooledList_Remove_LastItems | 56,465,443,542.8571 ns | 99,443,506.1766 ns | 88,154,078.0245 ns | 56,458,364,050.0000 ns | 48,092.866 | 216.09 | - | - | - | 992 B | 0.000 |
| RecyclableList_Remove_LastItems | 57,432,405,146.6667 ns | 264,062,625.8226 ns | 247,004,344.0307 ns | 57,409,508,000.0000 ns | 48,952.707 | 234.83 | - | - | - | 640 B | 0.000 |
| RecyclableLongList_Remove_LastItems | 57,077,678,728.5714 ns | 210,992,675.8689 ns | 187,039,511.4398 ns | 57,038,290,150.0000 ns | 48,614.503 | 242.79 | - | - | - | 952 B | 0.000 |
| List_RemoveAt_FirstItems | 4,517,669,893.3333 ns | 77,360,576.7460 ns | 72,363,131.4861 ns | 4,546,302,700.0000 ns | 3,850.590 | 62.34 | - | - | - | 4000656 B | 1.000 |
| PooledList_RemoveAt_FirstItems | 4,439,417,700.0000 ns | 40,915,112.8948 ns | 38,272,021.9874 ns | 4,418,366,400.0000 ns | 3,779.751 | 38.92 | - | - | - | 992 B | 0.000 |
| RecyclableList_RemoveAt_FirstItems | 4,558,102,892.8571 ns | 25,076,973.8515 ns | 22,230,084.1404 ns | 4,559,174,800.0000 ns | 3,882.107 | 16.61 | - | - | - | 640 B | 0.000 |
| RecyclableLongList_RemoveAt_FirstItems | 4,617,033,766.6667 ns | 85,061,197.3076 ns | 79,566,296.7373 ns | 4,632,994,800.0000 ns | 3,928.768 | 72.17 | - | - | - | 952 B | 0.000 |
| List_RemoveAt_LastItems | 2,005,211.3281 ns | 40,078.0351 ns | 84,538.1787 ns | 2,010,579.1016 ns | 1.725 | 0.08 | 42.9688 | 42.9688 | 42.9688 | 4000306 B | 1.000 |
| PooledList_RemoveAt_LastItems | 1,047,436.1654 ns | 5,655.2027 ns | 5,289.8801 ns | 1,044,690.9180 ns | 0.892 | 0.01 | - | - | - | 58 B | 0.000 |
| RecyclableList_RemoveAt_LastItems | 1,256,380.8969 ns | 9,142.3285 ns | 7,634.2584 ns | 1,254,354.9805 ns | 1.070 | 0.01 | - | - | - | 41 B | 0.000 |
| RecyclableLongList_RemoveAt_LastItems | 1,621,193.5826 ns | 20,030.6198 ns | 17,756.6227 ns | 1,620,789.8438 ns | 1.379 | 0.02 | - | - | - | 353 B | 0.000 |