Additional, optimized constructors & AddRange variants added to RecyclableArrayList. Benchmarks extended.

This commit is contained in:
mlemanczyk committed 2023-01-15 12:23:46 +01:00
1 parent 878ec4924a
commit 8984a3fac0
11 files changed
+484 -75

No files matched your search

@@ -14,6 +14,12 @@
protected object[]? _testObjects;
protected object[] TestObjects => _testObjects ??= Enumerable.Range(1, TestObjectCount).Select(x => new object()).ToArray();
private List<object>? _testObjectsAsList;
protected List<object> TestObjectsAsList => _testObjectsAsList ??= TestObjects.ToList();
private RecyclableArrayList<object>? _testObjectsAsRecyclableArrayList;
protected RecyclableArrayList<object> TestObjectsAsRecyclableArrayList => _testObjectsAsRecyclableArrayList ??= TestObjects.ToRecyclableArrayList();
protected static void DoNothing<T>(T obj)
{
_ = obj;
+2 -2
View File
@@ -3,8 +3,8 @@ using Recyclable.Collections.Benchmarks;
//BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(new[] { "-f*" });
BenchmarkRunner.Run<RecyclableCollectionsBenchmarks>();
//BenchmarkRunner.Run<RefVsInstanceMemberBenchmarks>();
//BenchmarkRunner.Run<RecyclableCollectionsBenchmarks>();
BenchmarkRunner.Run<RefVsInstanceMemberBenchmarks>();
//var benchmark = new RecyclableCollectionsBenchmarks();
//benchmark.RecyclableArrayList_AddRange_WithCapacity();
@@ -7,27 +7,17 @@ namespace Recyclable.Collections.Benchmarks
{
private readonly object[] _testArray;
//[Benchmark(Baseline = true)]
[Benchmark(Baseline = false)]
public void Array_Create_WithCapacity()
{
DoNothing(new object[TestObjectCount]);
var data = new object[TestObjectCount];
DoNothing(data);
}
//[Benchmark]
public void Array_GetItem()
{
var data = _testArray;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
//[Benchmark]
[Benchmark(Baseline = true)]
public void Array_SetItem()
{
var data = _testArray;
var data = TestObjects;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
@@ -35,14 +25,25 @@ namespace Recyclable.Collections.Benchmarks
}
}
//[Benchmark]
[Benchmark]
public void Array_GetItem()
{
var data = TestObjects;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
[Benchmark]
public void Array_Count()
{
var data = _testArray;
DoNothing(data.Length);
}
//[Benchmark]
[Benchmark]
public void Array_LongCount()
{
var data = _testArray;
@@ -6,7 +6,7 @@ namespace Recyclable.Collections.Benchmarks
{
private readonly List<object> _testList;
//[Benchmark(Baseline = true)]
//[Benchmark(Baseline = false)]
public void List_Create()
{
var list = new List<object>();
@@ -27,7 +27,7 @@ namespace Recyclable.Collections.Benchmarks
DoNothing(list);
}
//[Benchmark]
[Benchmark]
public void List_Add()
{
var data = TestObjects;
@@ -39,7 +39,7 @@ namespace Recyclable.Collections.Benchmarks
}
}
//[Benchmark(Baseline = true)]
[Benchmark(Baseline = false)]
public void List_Add_WithCapacity()
{
var data = TestObjects;
@@ -52,14 +52,38 @@ namespace Recyclable.Collections.Benchmarks
}
[Benchmark]
public void List_AddRange()
public void List_AddRangeWhenSourceIsArray()
{
var data = TestObjects;
var list = new List<object>();
list.AddRange(data);
}
[Benchmark(Baseline = true)]
[Benchmark]
public void List_AddRangeWhenSourceIsList()
{
var data = TestObjectsAsList;
var list = new List<object>();
list.AddRange(data);
}
[Benchmark]
public void List_AddRangeWhenSourceIsIList()
{
var data = (IList<object>)TestObjectsAsList;
var list = new List<object>();
list.AddRange(data);
}
[Benchmark]
public void List_AddRangeWhenSourceIsIEnumerable()
{
var data = (IEnumerable<object>)TestObjects;
var list = new List<object>();
list.AddRange(data);
}
[Benchmark(Baseline = false)]
public void List_AddRange_WithCapacity()
{
var data = TestObjects;
@@ -68,21 +92,10 @@ namespace Recyclable.Collections.Benchmarks
list.AddRange(data);
}
//[Benchmark]
public void List_GetItem()
{
var data = _testList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
//[Benchmark]
[Benchmark]
public void List_SetItem()
{
var data = _testList;
var data = TestObjectsAsList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
@@ -90,7 +103,18 @@ namespace Recyclable.Collections.Benchmarks
}
}
//[Benchmark]
[Benchmark]
public void List_GetItem()
{
var data = TestObjectsAsList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
}
}
[Benchmark]
public void List_Count()
{
var data = _testList;
@@ -41,7 +41,7 @@ namespace Recyclable.Collections.Benchmarks
DoNothing(list);
}
//[Benchmark]
[Benchmark]
public void RecyclableArrayList_Add()
{
var data = TestObjects;
@@ -53,7 +53,7 @@ namespace Recyclable.Collections.Benchmarks
}
}
//[Benchmark]
[Benchmark]
public void RecyclableArrayList_Add_WithCapacity()
{
var data = TestObjects;
@@ -66,13 +66,45 @@ namespace Recyclable.Collections.Benchmarks
}
[Benchmark]
public void RecyclableArrayList_AddRange()
public void RecyclableArrayList_AddRangeWhenSourceIsArray()
{
var data = TestObjects;
using var list = new RecyclableArrayList<object>();
list.AddRange(data);
}
[Benchmark]
public void RecyclableArrayList_AddRangeWhenSourceIsList()
{
var data = TestObjectsAsList;
using var list = new RecyclableArrayList<object>();
list.AddRange(data);
}
[Benchmark]
public void RecyclableArrayList_AddRangeWhenSourceIsIList()
{
var data = (IList<object>)TestObjectsAsList;
using var list = new RecyclableArrayList<object>();
list.AddRange(data);
}
[Benchmark]
public void RecyclableArrayList_AddRangeWhenSourceIsIEnumerable()
{
var data = (IEnumerable<object>)TestObjects;
using var list = new RecyclableArrayList<object>();
list.AddRange(data);
}
[Benchmark]
public void RecyclableArrayList_AddRangeWhenSourceIsRecyclableArrayList()
{
var data = TestObjectsAsRecyclableArrayList;
using var list = new RecyclableArrayList<object>();
list.AddRange(data);
}
[Benchmark]
public void RecyclableArrayList_AddRange_WithCapacity()
{
@@ -82,10 +114,23 @@ namespace Recyclable.Collections.Benchmarks
list.AddRange(data);
}
//[Benchmark]
[Benchmark]
public void RecyclableArrayList_SetItem()
{
var data = TestObjectsAsRecyclableArrayList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
data[i] = TestObjects[i];
}
data.Count = dataCount;
}
[Benchmark]
public void RecyclableArrayList_GetItem()
{
var data = _testRecyclableArrayList;
var data = TestObjectsAsRecyclableArrayList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
@@ -93,18 +138,7 @@ namespace Recyclable.Collections.Benchmarks
}
}
//[Benchmark]
public void RecyclableArrayList_SetItem()
{
var data = _testRecyclableArrayList;
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
data[i] = TestObjects[i];
}
}
//[Benchmark]
[Benchmark]
public void RecyclableArrayList_Count()
{
var data = _testRecyclableArrayList;
@@ -27,7 +27,7 @@ namespace Recyclable.Collections.Benchmarks
DoNothing(list);
}
[Benchmark]
//[Benchmark]
public void RecyclableList_Add()
{
var data = TestObjects;
@@ -39,7 +39,7 @@ namespace Recyclable.Collections.Benchmarks
}
}
[Benchmark]
//[Benchmark]
public void RecyclableList_Add_WithCapacity()
{
var data = TestObjects;
@@ -18,14 +18,27 @@ namespace Recyclable.Collections.Benchmarks
private class TestCase
{
private int[] _items = new int[123];
private int _count = 123;
private int Add(int count)
{
return count;
}
public int Count
{
get => _count;
set => _count = value;
}
public ref int GetRefCount()
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;
@@ -33,30 +46,299 @@ namespace Recyclable.Collections.Benchmarks
return ref count;
}
private int Add(int count)
public ref int GetCountAsRefCount4()
{
return count;
ref int count = ref _count;
count = 234;
_ = Add(count);
_ = Add(count);
return ref count;
}
public int GetCount()
public ref int GetCountAsRefCount5()
{
ref int count = ref _count;
count = 234;
_ = Add(count);
_ = Add(count);
_ = Add(count);
return ref count;
}
public int GetCountAsInstanceMember2()
{
_count = 234;
return _count;
}
public int GetCountAsInstanceMember3()
{
_count = 234;
_ = Add(_count);
return _count;
}
public int GetCountAsInstanceMember4()
{
_count = 234;
_ = Add(_count);
_ = Add(_count);
return _count;
}
public int GetCountAsInstanceMember5()
{
_count = 234;
_ = Add(_count);
_ = Add(_count);
_ = Add(_count);
return _count;
}
public int GetLengthAsArray2()
{
_ = Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray3()
{
_ = Add(_items.Length);
_ = Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray4()
{
_ = Add(_items.Length);
_ = Add(_items.Length);
_ = Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray5()
{
_ = Add(_items.Length);
_ = Add(_items.Length);
_ = Add(_items.Length);
_ = Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray6()
{
_ = Add(_items.Length);
_ = Add(_items.Length);
_ = Add(_items.Length);
_ = Add(_items.Length);
_ = Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArrayLocalVar5()
{
var items = _items;
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
return items.Length;
}
public int GetLengthAsArrayLocalVar6()
{
var items = _items;
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray2()
{
ref int[] items = ref _items;
_ = Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray3()
{
ref int[] items = ref _items;
_ = Add(items.Length);
_ = Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray4()
{
ref int[] items = ref _items;
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray5()
{
ref int[] items = ref _items;
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray6()
{
ref int[] items = ref _items;
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
_ = Add(items.Length);
return items.Length;
}
}
[Benchmark]
public void Ref()
public void RefToInt2()
{
var count = _testCase.GetRefCount();
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 InstanceMember()
public void IntInstanceMember2()
{
var count = _testCase.GetCount();
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);
}
}
+52 -5
View File
@@ -82,7 +82,6 @@ namespace Recyclable.Collections
public RecyclableArrayList(int initialCapacity)
#pragma warning restore CS8618
{
// _memory will be initialized when the 1st item is added
if (initialCapacity > 0)
{
_memory = SetNewLength(_memory, initialCapacity);
@@ -90,6 +89,34 @@ namespace Recyclable.Collections
}
}
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
public RecyclableArrayList(RecyclableArrayList<T> source)
#pragma warning restore CS8618
{
AddRange(source);
}
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
public RecyclableArrayList(in T[] source)
#pragma warning restore CS8618
{
AddRange(source);
}
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
public RecyclableArrayList(List<T> source)
#pragma warning restore CS8618
{
AddRange(source);
}
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
public RecyclableArrayList(IList<T> source)
#pragma warning restore CS8618
{
AddRange(source);
}
public RecyclableArrayList(IEnumerable<T> source, int initialCapacity = RecyclableDefaults.Capacity)
{
_memory = SetNewLength(_memory, initialCapacity);
@@ -126,7 +153,7 @@ namespace Recyclable.Collections
public bool IsReadOnly { get; } = false;
public void Add(in T item)
public void Add(T item)
{
int requestedCapacity = _count + 1;
if (_capacity < requestedCapacity)
@@ -152,7 +179,7 @@ namespace Recyclable.Collections
_count = targetCapacity;
}
public void AddRange(in List<T> items)
public void AddRange(List<T> items)
{
var sourceItemsCount = items.Count;
var targetCapacity = _count + sourceItemsCount;
@@ -165,7 +192,20 @@ namespace Recyclable.Collections
_count = targetCapacity;
}
public void AddRange(in RecyclableArrayList<T> items)
public void AddRange(IList<T> items)
{
var sourceItemsCount = items.Count;
var targetCapacity = _count + sourceItemsCount;
if (_capacity < targetCapacity)
{
_ = EnsureCapacity(targetCapacity);
}
items.CopyTo(_memory, _count);
_count = targetCapacity;
}
public void AddRange(RecyclableArrayList<T> items)
{
var sourceItemsCount = items._count;
var targetCapacity = _count + sourceItemsCount;
@@ -180,10 +220,17 @@ namespace Recyclable.Collections
_count = targetCapacity;
}
public void AddRange(IEnumerable<T> source)
public void AddRange(IEnumerable<T> source, int growByCount = 100)
{
ref int capacity = ref _capacity;
ref int count = ref _count;
foreach (var item in source)
{
if (capacity == count)
{
_ = EnsureCapacity(capacity * growByCount);
}
Add(item);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 22 KiB

+1 -1
View File
@@ -3,7 +3,7 @@
public class RecyclableDefaults
{
public const int BlockSize = 10_240;
public const int Capacity = 8;
public const int Capacity = 1;
public const int MinPooledArrayLength = 100;
}
}
@@ -121,11 +121,26 @@ namespace Recyclable.Collections
return -1;
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static RecyclableList<T> ToRecyclableList<T>(this IList<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this IList<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static RecyclableList<T> ToRecyclableList<T>(this IEnumerable<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this List<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableArrayList<T> ToRecyclableArrayList<T>(this IEnumerable<T> values) => new(values, values.TryGetNonEnumeratedCount(out int count) ? count : RecyclableDefaults.Capacity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableArrayList<T> ToRecyclableArrayList<T>(this T[] values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableArrayList<T> ToRecyclableArrayList<T>(this List<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableArrayList<T> ToRecyclableArrayList<T>(this RecyclableArrayList<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this IEnumerable<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] RentArrayFromPool<T>(this int minSize, ArrayPool<T> arrayPool) => (minSize >= _minPooledArraySize)