From bb878caa394af31dc761d939249a926cd3585feb Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Sun, 7 May 2023 14:52:37 +0200 Subject: [PATCH] Benchmarks reworked to save time on test data creation & have more comparable results against baseline. --- .../Benchmarks/Add.cs | 7 +- .../Benchmarks/AddRangeWhenSourceIsArray.cs | 7 +- .../AddRangeWhenSourceIsIEnumerable.cs | 7 +- .../Benchmarks/AddRangeWhenSourceIsIList.cs | 7 +- .../Benchmarks/AddRangeWhenSourceIsList.cs | 7 +- .../AddRangeWhenSourceIsSameType.cs | 6 +- .../Benchmarks/AddRange_WithCapacity.cs | 7 +- .../Benchmarks/Add_WithCapacity.cs | 7 +- .../Benchmarks/Contains_FirstItems.cs | 9 +- .../Benchmarks/Contains_LastItems.cs | 9 +- .../Benchmarks/Count.cs | 10 +- .../Benchmarks/Create.cs | 7 +- .../Benchmarks/Create_WithCapacity.cs | 8 +- .../Benchmarks/GetItem..cs | 13 +- .../Benchmarks/IndexOf_AllItems.cs | 10 +- .../Benchmarks/IndexOf_FirstItems.cs | 10 +- .../Benchmarks/IndexOf_LastItems.cs | 10 +- .../Benchmarks/LongCount.cs | 6 +- .../RecyclableCollections.Benchmarks.cs | 88 +++++--- .../Benchmarks/RemoveAt_FirstItems.cs | 7 +- .../Benchmarks/RemoveAt_LastItems.cs | 7 +- .../Benchmarks/Remove_FirstItems.cs | 7 +- .../Benchmarks/Remove_LastItems.cs | 7 +- .../Benchmarks/SetItem.cs | 10 +- .../POC/ArraySizeLimitPoc.Benchmarks.cs | 19 +- .../POC/BoolOrComparePoc.Benchmarks.cs | 53 +++-- .../POC/DelegateVsComparerPoc.Benchmarks.cs | 191 +++++++++++++----- .../POC/PocBenchmarkBase.cs | 75 ++++++- ...clableListPoc.Benchmarks.EnsureCapacity.cs | 3 +- .../RecyclableListPoc.Benchmarks.IndexOf.cs | 5 +- .../POC/RecyclableListPoc.Benchmarks.cs | 138 ++++++------- .../POC/RoundBenchmarks.cs | 26 ++- .../POC/SpanVsArrayBenchmarks.cs | 44 +++- .../POC/WhenParallelSearchBenchmarks.cs | 110 +++++----- ...markBase.cs => RecyclableBenchmarkBase.cs} | 67 +++++- 35 files changed, 586 insertions(+), 418 deletions(-) rename Recyclable.Collections.Benchmarks/{BenchmarkBase.cs => RecyclableBenchmarkBase.cs} (75%) diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Add.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Add.cs index e881a81..32173a2 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Add.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Add.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_Add() { var data = TestObjects; @@ -17,7 +15,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_Add() { var data = TestObjects; @@ -29,7 +26,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Add() { var data = TestObjects; @@ -41,7 +37,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_Add() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsArray.cs b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsArray.cs index f0ea17a..5bc8b09 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsArray.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsArray.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_AddRangeWhenSourceIsArray() { var data = TestObjects; @@ -13,7 +11,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = true)] public void PooledList_AddRangeWhenSourceIsArray() { var data = TestObjects; @@ -21,7 +18,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_AddRangeWhenSourceIsArray() { var data = TestObjects; @@ -29,7 +25,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableList_AddRangeWhenSourceIsArray() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIEnumerable.cs b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIEnumerable.cs index aebf532..51866dd 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIEnumerable.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIEnumerable.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_AddRangeWhenSourceIsIEnumerable() { var data = TestObjectsAsIEnumerable; @@ -13,7 +11,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = true)] public void PooledList_AddRangeWhenSourceIsIEnumerable() { var data = TestObjectsAsIEnumerable; @@ -21,7 +18,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_AddRangeWhenSourceIsIEnumerable() { var data = TestObjectsAsIEnumerable; @@ -29,7 +25,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableList_AddRangeWhenSourceIsIEnumerable() { var data = TestObjectsAsIEnumerable; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIList.cs b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIList.cs index a7bff76..15ea875 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIList.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsIList.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_AddRangeWhenSourceIsIList() { var data = (IList)TestObjectsAsRecyclableList; @@ -13,7 +11,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = true)] public void PooledList_AddRangeWhenSourceIsIList() { var data = (IList)TestObjectsAsPooledList; @@ -21,7 +18,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_AddRangeWhenSourceIsIList() { var data = (IList)TestObjectsAsRecyclableList; @@ -29,7 +25,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableList_AddRangeWhenSourceIsIList() { var data = (IList)TestObjectsAsRecyclableList; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsList.cs b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsList.cs index 92178ec..f1c07d2 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsList.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsList.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_AddRangeWhenSourceIsList() { var data = TestObjectsAsList; @@ -13,7 +11,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = true)] public void PooledList_AddRangeWhenSourceIsList() { var data = TestObjectsAsList; @@ -21,7 +18,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_AddRangeWhenSourceIsList() { var data = TestObjectsAsList; @@ -29,7 +25,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableList_AddRangeWhenSourceIsList() { var data = TestObjectsAsList; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsSameType.cs b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsSameType.cs index 6133b30..3eed14a 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsSameType.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/AddRangeWhenSourceIsSameType.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = true)] public void PooledList_AddRangeWhenSourceIsPooledList() { var data = TestObjectsAsPooledList; @@ -13,7 +11,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_AddRangeWhenSourceIsRecyclableArrayList() { var data = TestObjectsAsRecyclableArrayList; @@ -21,7 +18,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableList_AddRangeWhenSourceIsRecyclableArrayList() { var data = TestObjectsAsRecyclableArrayList; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/AddRange_WithCapacity.cs b/Recyclable.Collections.Benchmarks/Benchmarks/AddRange_WithCapacity.cs index 70c2080..1694833 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/AddRange_WithCapacity.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/AddRange_WithCapacity.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_AddRange_WithCapacity() { var data = TestObjects; @@ -14,7 +12,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = true)] public void PooledList_AddRange_WithCapacity() { var data = TestObjects; @@ -23,7 +20,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_AddRange_WithCapacity() { var data = TestObjects; @@ -32,7 +28,6 @@ namespace Recyclable.Collections.Benchmarks list.AddRange(data); } - //[Benchmark(Baseline = false)] public void RecyclableList_AddRange_WithCapacity() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Add_WithCapacity.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Add_WithCapacity.cs index 1509649..d727255 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Add_WithCapacity.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Add_WithCapacity.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_Add_WithCapacity() { var data = TestObjects; @@ -17,7 +15,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_Add_WithCapacity() { var data = TestObjects; @@ -29,7 +26,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Add_WithCapacity() { var data = TestObjects; @@ -41,7 +37,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_Add_WithCapacity() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs index 98e7362..bdfa8dc 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs @@ -1,10 +1,7 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_Contains_FirstItems() { var data = TestObjects; @@ -16,7 +13,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void List_Contains_FirstItems() { var data = TestObjects; @@ -28,7 +24,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_Contains_FirstItems() { var data = TestObjects; @@ -40,7 +35,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Contains_FirstItems() { var data = TestObjects; @@ -52,7 +46,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_Contains_FirstItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs index d0b50c9..68b9e3a 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs @@ -1,10 +1,7 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_Contains_LastItems() { var data = TestObjects; @@ -16,7 +13,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void List_Contains_LastItems() { var data = TestObjects; @@ -28,7 +24,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_Contains_LastItems() { var data = TestObjects; @@ -40,7 +35,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Contains_LastItems() { var data = TestObjects; @@ -52,7 +46,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_Contains_LastItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs index 1803de3..0a45e1b 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs @@ -1,39 +1,31 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_Count() { var data = TestObjects; DoNothing(data.Length); } - //[Benchmark(Baseline = false)] public void List_Count() { var data = TestObjectsAsList; DoNothing(data.Count); } - //[Benchmark(Baseline = true)] public void PooledList_Count() { var data = TestObjectsAsPooledList; DoNothing(data.Count); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Count() { var data = TestObjectsAsRecyclableArrayList; DoNothing(data.Count); } - //[Benchmark(Baseline = false)] public void RecyclableList_Count() { var data = TestObjectsAsRecyclableList; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs index 6574f42..6c8e98b 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs @@ -1,32 +1,27 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_Create() { var list = new List(); DoNothing(list); } - //[Benchmark(Baseline = true)] public void PooledList_Create() { using var list = new PooledList(ClearMode.Auto); DoNothing(list); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Create() { using var list = new RecyclableArrayList(); DoNothing(list); } - //[Benchmark(Baseline = false)] public void RecyclableList_Create() { using var list = new RecyclableList(); diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs index 7d43835..ba87e09 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs @@ -1,39 +1,33 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_Create_WithCapacity() { var data = new long[TestObjectCount]; DoNothing(data); } - //[Benchmark(Baseline = false)] public void List_Create_WithCapacity() { var list = new List(TestObjectCount); DoNothing(list); } - //[Benchmark(Baseline = true)] public void PooledList_Create_WithCapacity() { using var list = new PooledList(capacity: TestObjectCount, ClearMode.Auto); DoNothing(list); } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Create_WithCapacity() { using var list = new RecyclableArrayList(TestObjectCount); DoNothing(list); } - //[Benchmark(Baseline = false)] public void RecyclableList_Create_WithCapacity() { using var list = new RecyclableList(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount); diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs b/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs index 374abbd..26c5828 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs @@ -1,10 +1,7 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - [Benchmark(Baseline = false)] public void Array_GetItem() { var data = TestObjects; @@ -15,7 +12,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void List_GetItem() { var data = TestObjectsAsList; @@ -26,7 +22,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = true)] public void PooledList_GetItem() { var data = TestObjectsAsPooledList; @@ -37,7 +32,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableArrayList_GetItem() { var data = TestObjectsAsRecyclableArrayList; @@ -48,7 +42,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_GetItem() { var data = TestObjectsAsRecyclableList; @@ -59,7 +52,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_GetItem_AsSpan() { var data = TestObjectsAsRecyclableList; @@ -86,7 +78,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_GetItem_AsArray() { var data = TestObjectsAsRecyclableList; @@ -114,7 +105,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_GetItem_AsForEach() { var data = TestObjectsAsRecyclableList; @@ -124,7 +114,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_GetItem_AsWhile() { var data = TestObjectsAsRecyclableList; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_AllItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_AllItems.cs index 1df873c..2e9dd95 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_AllItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_AllItems.cs @@ -1,10 +1,7 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - [Benchmark(Baseline = false)] public void Array_IndexOf_AllItems() { var data = TestObjects; @@ -16,7 +13,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void List_IndexOf_AllItems() { var data = TestObjects; @@ -28,7 +24,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = true)] public void PooledList_IndexOf_AllItems() { var data = TestObjects; @@ -40,7 +35,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableArrayList_IndexOf_AllItems() { var data = TestObjects; @@ -52,7 +46,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_IndexOf_AllItems() { var data = TestObjects; @@ -64,7 +57,6 @@ namespace Recyclable.Collections.Benchmarks } } - [Benchmark(Baseline = false)] public void RecyclableList_LongIndexOf_AllItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs index a7bbe76..15e5443 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs @@ -1,10 +1,7 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_IndexOf_FirstItems() { var data = TestObjects; @@ -16,7 +13,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void List_IndexOf_FirstItems() { var data = TestObjects; @@ -28,7 +24,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_IndexOf_FirstItems() { var data = TestObjects; @@ -40,7 +35,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_IndexOf_FirstItems() { var data = TestObjects; @@ -52,7 +46,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_IndexOf_FirstItems() { var data = TestObjects; @@ -64,7 +57,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_LongIndexOf_FirstItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs index 22910c4..e0661ad 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs @@ -1,10 +1,7 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_IndexOf_LastItems() { var data = TestObjects; @@ -16,7 +13,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void List_IndexOf_LastItems() { var data = TestObjects; @@ -28,7 +24,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_IndexOf_LastItems() { var data = TestObjects; @@ -40,7 +35,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_IndexOf_LastItems() { var data = TestObjects; @@ -52,7 +46,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_IndexOf_LastItems() { var data = TestObjects; @@ -64,7 +57,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_LongIndexOf_LastItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs b/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs index 426cf3e..2870f4d 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs @@ -1,17 +1,13 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_LongCount() { var data = TestObjects; DoNothing(data.LongLength); } - //[Benchmark(Baseline = false)] public void RecyclableList_LongCount() { var data = TestObjectsAsRecyclableList; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs b/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs index a927053..b0b78a5 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs @@ -1,40 +1,66 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using System.Reflection; +using BenchmarkDotNet.Attributes; namespace Recyclable.Collections.Benchmarks { - [MemoryDiagnoser] - public partial class RecyclableCollectionsBenchmarks : BenchmarkBase + public enum RecyclableCollectionsBenchmarkType { - private long[]? _testArray; - private RecyclableArrayList? _testRecyclableArrayList; - private RecyclableList? _testRecyclableList; - private PooledList? _testPooledList; + Add_WithCapacity, Add, AddRange_WithCapacity, AddRangeWhenSourceIsArray, AddRangeWhenSourceIsIEnumerable, + AddRangeWhenSourceIsIList, AddRangeWhenSourceIsList, AddRangeWhenSourceIsSameType, Contains_FirstItems, + Contains_LastItems, Count, Create_WithCapacity, Create, GetItem, IndexOf_AllItems, IndexOf_FirstItems, + IndexOf_LastItems, LongCount, Remove_FirstItems, Remove_LastItems, RemoveAt_FirstItems, RemoveAt_LastItems, + SetItem, + } - public PooledList TestObjectsAsPooledList => _testPooledList ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); + public partial class RecyclableCollectionsBenchmarks : RecyclableBenchmarkBase + { + [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_AllItems, + RecyclableCollectionsBenchmarkType.IndexOf_FirstItems, + RecyclableCollectionsBenchmarkType.IndexOf_LastItems, + RecyclableCollectionsBenchmarkType.LongCount, + RecyclableCollectionsBenchmarkType.Remove_FirstItems, + RecyclableCollectionsBenchmarkType.Remove_LastItems, + RecyclableCollectionsBenchmarkType.RemoveAt_FirstItems, + RecyclableCollectionsBenchmarkType.RemoveAt_LastItems, + RecyclableCollectionsBenchmarkType.SetItem + )] - public override void Setup() - { - base.Setup(); - _testRecyclableArrayList = new(TestObjects, initialCapacity: TestObjectCount); - _testRecyclableList = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); - _testArray = TestObjects.ToArray(); - _testObjectsAsList = TestObjects.ToList(); - _testObjectsAsRecyclableArrayList = TestObjects.ToRecyclableArrayList(); - _testObjectsAsRecyclableList = TestObjects.ToRecyclableList(); - _testPooledList = new PooledList(TestObjects, ClearMode.Always); - } + public RecyclableCollectionsBenchmarkType TestCase { get; set; } = RecyclableCollectionsBenchmarkType.IndexOf_AllItems; - public override void Cleanup() - { - _testRecyclableArrayList?.Dispose(); - _testRecyclableList?.Dispose(); - _testPooledList?.Dispose(); - TestObjectsAsRecyclableArrayList?.Dispose(); - _testObjectsAsRecyclableArrayList = default; - _testObjectsAsRecyclableList = default; - _testObjectsAsList = default; - base.Cleanup(); - } + [Params + ( + RecyclableCollectionsBenchmarkSource.Array, + RecyclableCollectionsBenchmarkSource.List, + RecyclableCollectionsBenchmarkSource.PooledList, + RecyclableCollectionsBenchmarkSource.RecyclableArrayList, + RecyclableCollectionsBenchmarkSource.RecyclableList + )] + public override RecyclableCollectionsBenchmarkSource BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; } + + [Params + ( + RecyclableCollectionsBenchmarkSource.PooledList + )] + public override RecyclableCollectionsBenchmarkSource BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; } + + protected override Action GetTestMethod(RecyclableCollectionsBenchmarkSource benchmarkType) + => (Action?) GetType().GetMethod($"{benchmarkType}_{TestCase}", BindingFlags.Instance | BindingFlags.Public)?.CreateDelegate(typeof(Action), this) + ?? throw CreateMethodNotFoundException($"{benchmarkType}_{TestCase}", GetType().FullName); } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_FirstItems.cs index ddb0f98..5bb65cb 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_FirstItems.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_RemoveAt_FirstItems() { var data = TestObjects; @@ -17,7 +15,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_RemoveAt_FirstItems() { var data = TestObjects; @@ -29,7 +26,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_RemoveAt_FirstItems() { var data = TestObjects; @@ -41,7 +37,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_RemoveAt_FirstItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_LastItems.cs index 9d84783..f4b808e 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/RemoveAt_LastItems.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_RemoveAt_LastItems() { var data = TestObjects; @@ -17,7 +15,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_RemoveAt_LastItems() { var data = TestObjects; @@ -29,7 +26,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_RemoveAt_LastItems() { var data = TestObjects; @@ -41,7 +37,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_RemoveAt_LastItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs index c0e77b0..3d61a1c 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_Remove_FirstItems() { var data = TestObjects; @@ -17,7 +15,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_Remove_FirstItems() { var data = TestObjects; @@ -29,7 +26,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Remove_FirstItems() { var data = TestObjects; @@ -41,7 +37,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_Remove_FirstItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs index aeb7207..374a722 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs @@ -1,11 +1,9 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; +using Collections.Pooled; namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void List_Remove_LastItems() { var data = TestObjects; @@ -17,7 +15,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_Remove_LastItems() { var data = TestObjects; @@ -29,7 +26,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_Remove_LastItems() { var data = TestObjects; @@ -41,7 +37,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_Remove_LastItems() { var data = TestObjects; diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/SetItem.cs b/Recyclable.Collections.Benchmarks/Benchmarks/SetItem.cs index ce4eaef..689a5e1 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/SetItem.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/SetItem.cs @@ -1,11 +1,7 @@ -using BenchmarkDotNet.Attributes; -using Collections.Pooled; - -namespace Recyclable.Collections.Benchmarks +namespace Recyclable.Collections.Benchmarks { public partial class RecyclableCollectionsBenchmarks { - //[Benchmark(Baseline = false)] public void Array_SetItem() { var data = TestObjects; @@ -17,7 +13,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void List_SetItem() { var data = TestObjectsAsList; @@ -28,7 +23,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = true)] public void PooledList_SetItem() { var data = TestObjectsAsPooledList; @@ -39,7 +33,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableArrayList_SetItem() { var data = TestObjectsAsRecyclableArrayList; @@ -50,7 +43,6 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark(Baseline = false)] public void RecyclableList_SetItem() { var data = TestObjectsAsRecyclableList; diff --git a/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs index 222a4a9..960456e 100644 --- a/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs @@ -3,20 +3,29 @@ using System.Buffers; namespace Recyclable.Collections.Benchmarks.POC { - public class ArraySizeLimitPocBenchmarks : PocBenchmarkBase + public enum ArraySizeLimitPocBenchmarkType + { + ArraySizeLimit + } + + public class ArraySizeLimitPocBenchmarks : PocBenchmarkBase { public static void Run() { var benchmark = new ArraySizeLimitPocBenchmarks(); + benchmark.Setup(); benchmark.FindArraySizeLimit(); + benchmark.Cleanup(); } - private const int _maxArraySize = 2_147_483_605; + [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() { - var arr = ArrayPool.Shared.Rent(_maxArraySize); + long[] arr = ArrayPool.Shared.Rent(TestObjectCount); + DoNothing(arr); } [Benchmark(OperationsPerInvoke = 1)] @@ -43,7 +52,7 @@ namespace Recyclable.Collections.Benchmarks.POC } catch (Exception) { - Console.WriteLine($"error"); + Console.WriteLine("error"); var nextValue = (bufferSize - oldValue) >> 1; if (nextValue == 0) { @@ -57,5 +66,5 @@ namespace Recyclable.Collections.Benchmarks.POC Console.WriteLine("All done"); throw new Exception($"Everything was successful. You can create {oldValue} byte big arrays. Exception is logged to prevent more benchmarks."); } - } + } } diff --git a/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs index 51e002c..ea60943 100644 --- a/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs @@ -1,50 +1,63 @@ using BenchmarkDotNet.Attributes; -using System.Runtime.CompilerServices; namespace Recyclable.Collections.Benchmarks.POC { - [MemoryDiagnoser] - public class BoolOrComparePocBenchmarks + public enum BoolOrComparePocBenchmarkType { + Bool, + Compare, + } + + [MemoryDiagnoser] + public class BoolOrComparePocBenchmarks : PocBenchmarkBase + { + [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(); } - private static void DoNothing(T result, [CallerMemberName] string? callerName = null) - { - //Console.WriteLine($"{callerName}: result = {result}"); - } - - private readonly bool _testBool = true; - private readonly int _blockSize = 8; - - [Benchmark(Baseline = false)] public void Bool() { - if (_testBool) + if (TestBool) { - DoNothing(_testBool); + DoNothing(TestBool); } else { - DoNothing(_testBool); + DoNothing(TestBool); } } - [Benchmark(Baseline = false)] public void Compare() { - if (_blockSize >= RecyclableDefaults.MinPooledArrayLength) + if (TestObjectCount >= RecyclableDefaults.MinPooledArrayLength) { - DoNothing(_testBool); + DoNothing(TestBool); } else { - DoNothing(_testBool); + DoNothing(TestBool); } } - } + + protected override Action? GetTestMethod(BoolOrComparePocBenchmarkType benchmarkType) => benchmarkType switch + { + BoolOrComparePocBenchmarkType.Bool => Bool, + BoolOrComparePocBenchmarkType.Compare => Compare, + _ => throw CreateUnknownBenchmarkTypeException(benchmarkType), + }; + } } \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs index 5b7e462..c926998 100644 --- a/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs @@ -3,9 +3,46 @@ 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 + public class DelegateVsComparerPocBenchmarks : PocBenchmarkBase { + [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 x, T y); @@ -45,6 +82,7 @@ namespace Recyclable.Collections.Benchmarks.POC public static void Run() { var benchmark = new DelegateVsComparerPocBenchmarks(); + benchmark.Setup(); benchmark.Comparer(); benchmark.Delegate(); benchmark.Func(); @@ -58,22 +96,21 @@ namespace Recyclable.Collections.Benchmarks.POC benchmark.ListOfUnboxedReadOnlyStructs(); benchmark.ListOfUnboxedStructs(); benchmark.StaticFunc(); + benchmark.Cleanup(); } private static readonly Comparer _comparer = Comparer.Default; - - private const int _objectCount = 1_000_000; - private static readonly IEnumerable _testObjects = Enumerable.Range(1, _objectCount).Select(x => (long)x); - private static readonly IEnumerable> _testListOfFunctions = _testObjects.Select>(static _ => new MyComparer().Compare); - private static readonly IEnumerable> _testListOfComparers = _testObjects.Select(_ => (IComparer)new MyComparer()); - private static readonly IEnumerable> _testListOfDelegates = _testObjects.Select(_ => new Compare((x, y) => new MyComparer().Compare(x, y))); - private static readonly IEnumerable> _testListOfLocalFunctions = GetLocalFunctions(_testObjects); - private static readonly IEnumerable _testListOfClasses = _testObjects.Select(_ => new MyComparer()); - private static readonly IEnumerable> _testListOfStructs = _testObjects.Select(_ => new MyComparerStruct()); - private static readonly IEnumerable> _testListOfBoxedStructs = _testObjects.Select(_ => (IComparer)new MyComparerStruct()); - private static IEnumerable _testListOfUnboxedStructs() where TComparer : IComparer, new() + private IEnumerable? _testObjects; + private IEnumerable>? _testListOfFunctions; + private IEnumerable>? _testListOfComparers; + private IEnumerable>? _testListOfDelegates; + private IEnumerable>? _testListOfLocalFunctions; + private IEnumerable? _testListOfClasses; + private IEnumerable>? _testListOfStructs; + private IEnumerable>? _testListOfBoxedStructs; + private IEnumerable TestListOfUnboxedStructs() where TComparer : IComparer, new() { - foreach (var item in _testObjects) + foreach (var _ in _testObjects!) { yield return new TComparer(); } @@ -91,37 +128,44 @@ namespace Recyclable.Collections.Benchmarks.POC }; } - foreach (var item in testObjects) + foreach (var _ in testObjects) { yield return compareFunc; } } - private static void TestWithComparer(IComparer comparer) + private void TestWithComparer(IComparer comparer) { - var testData = _testObjects.ToArray(); + 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() + private void TestWithDelegate(Compare compareFunc) { - TestWithComparer(_comparer); - } - - private static void TestWithFunc(Func compareFunc) - { - var testData = _testObjects.ToArray(); + var testData = _testObjects!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++) { _ = compareFunc(testData[itemIdx], testData[itemIdx + 1]); } } - [Benchmark] + private void TestWithFunc(Func 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 @@ -132,7 +176,6 @@ namespace Recyclable.Collections.Benchmarks.POC }); } - [Benchmark] public void StaticFunc() { TestWithFunc(static (x, y) => (x - y) switch @@ -143,16 +186,6 @@ namespace Recyclable.Collections.Benchmarks.POC }); } - private static void TestWithDelegate(Compare 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((x, y) => (x - y) switch @@ -163,11 +196,10 @@ namespace Recyclable.Collections.Benchmarks.POC }); } - [Benchmark] public void ListOfFuncs() { const long x = 2, y = 5; - var testData = _testListOfFunctions.ToArray(); + var testData = _testListOfFunctions!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var compareFunc = testData[itemIdx]; @@ -175,11 +207,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfLocalFuncs() { const long x = 2, y = 5; - var testData = _testListOfLocalFunctions.ToArray(); + var testData = _testListOfLocalFunctions!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var compareFunc = testData[itemIdx]; @@ -187,11 +218,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfComparers() { const long x = 2, y = 5; - var testData = _testListOfComparers.ToArray(); + var testData = _testListOfComparers!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var comparer = testData[itemIdx]; @@ -199,11 +229,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfClasses() { const long x = 2, y = 5; - var testData = _testListOfClasses.ToArray(); + var testData = _testListOfClasses!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var comparer = testData[itemIdx]; @@ -211,11 +240,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfStructs() { const long x = 2, y = 5; - var testData = _testListOfStructs.ToArray(); + var testData = _testListOfStructs!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var comparer = testData[itemIdx]; @@ -223,11 +251,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfBoxedStructs() { const long x = 2, y = 5; - var testData = _testListOfBoxedStructs.ToArray(); + var testData = _testListOfBoxedStructs!.ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var comparer = testData[itemIdx]; @@ -235,11 +262,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfUnboxedStructs() { const long x = 2, y = 5; - var testData = _testListOfUnboxedStructs, long>().ToArray(); + var testData = TestListOfUnboxedStructs, long>().ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var comparer = testData[itemIdx]; @@ -247,11 +273,10 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfUnboxedReadOnlyStructs() { const long x = 2, y = 5; - var testData = _testListOfUnboxedStructs, long>().ToArray(); + var testData = TestListOfUnboxedStructs, long>().ToArray(); for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++) { var comparer = testData[itemIdx]; @@ -259,16 +284,74 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ListOfDelegates() { const long x = 2, y = 5; - var testData = _testListOfDelegates.ToArray(); + 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 benchmarkType) + { + switch (benchmarkType) + { + case DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs: + _testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer)new MyComparerStruct()); + break; + case DelegateVsComparerPocBenchmarkType.ListOfClasses: + _testListOfClasses = _testObjects!.Select(_ => new MyComparer()); + break; + case DelegateVsComparerPocBenchmarkType.ListOfComparers: + _testListOfComparers = _testObjects!.Select(_ => (IComparer)new MyComparer()); + break; + case DelegateVsComparerPocBenchmarkType.ListOfDelegates: + _testListOfDelegates = _testObjects!.Select(_ => new Compare((x, y) => new MyComparer().Compare(x, y))); + break; + case DelegateVsComparerPocBenchmarkType.ListOfFuncs: + _testListOfFunctions = _testObjects!.Select>(static _ => new MyComparer().Compare); + break; + case DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs: + _testListOfLocalFunctions = GetLocalFunctions(_testObjects!); + break; + case DelegateVsComparerPocBenchmarkType.ListOfStructs: + _testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct()); + break; + } + } } } diff --git a/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs b/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs index 254f92d..97d4c77 100644 --- a/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs +++ b/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs @@ -4,9 +4,32 @@ using System.Runtime.CompilerServices; namespace Recyclable.Collections.Benchmarks.POC { - public class PocBenchmarkBase + public abstract class PocBenchmarkBase { - // 0 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 + 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] + public void RunWhen() => TestMethod.Invoke(); + + [Benchmark(Baseline = true)] + public void Baseline() => BaselineMethod.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 @@ -17,7 +40,7 @@ namespace Recyclable.Collections.Benchmarks.POC //[Params(1_000_000, 10_000_000, 100_000_000, 1_000_000_000)] //[Params(1, 8, 16, 128, 192, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 10_000_000)] //[Params(RecyclableDefaults.MaxPooledBlockSize)] - public int TestObjectCount = 1_000_000; + public virtual int TestObjectCount { get; set; }= 524_288; //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)] @@ -38,5 +61,51 @@ namespace Recyclable.Collections.Benchmarks.POC { _ = item; } + + protected static Exception CreateUnknownBenchmarkTypeException(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 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 (BaselineBenchmarkType != null) + { + 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.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 *******"); + } } } diff --git a/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.EnsureCapacity.cs b/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.EnsureCapacity.cs index 6a2b9da..8c320c8 100644 --- a/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.EnsureCapacity.cs +++ b/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.EnsureCapacity.cs @@ -1,5 +1,4 @@ -using BenchmarkDotNet.Attributes; -using Recyclable.Collections.Pools; +using Recyclable.Collections.Pools; using System.Buffers; using System.Collections; using System.Numerics; diff --git a/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.IndexOf.cs b/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.IndexOf.cs index 3e34a5c..61cab10 100644 --- a/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.IndexOf.cs +++ b/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.IndexOf.cs @@ -1,5 +1,4 @@ -using BenchmarkDotNet.Attributes; -using Microsoft.Extensions.ObjectPool; +using Microsoft.Extensions.ObjectPool; using Recyclable.Collections.Parallel; using Recyclable.Collections.Pools; using System.Buffers; @@ -4654,7 +4653,7 @@ namespace Recyclable.Collections.Benchmarks.POC } } } - + #endregion public partial class RecyclableListPocBenchmarks diff --git a/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.cs index 0387c74..581622a 100644 --- a/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/RecyclableListPoc.Benchmarks.cs @@ -5,7 +5,7 @@ using Recyclable.Collections.Benchmarks.Core; namespace Recyclable.Collections.Benchmarks.POC { - public enum RecyclableListPocBenchmarkType + public enum RecyclableListPocBenchmarkType { IndexOfV1, IndexOfV2, @@ -19,23 +19,24 @@ namespace Recyclable.Collections.Benchmarks.POC EnsureCapacityV3_ByPowOf2, } - public partial class RecyclableListPocBenchmarks : PocBenchmarkBase + [MemoryDiagnoser] + public partial class RecyclableListPocBenchmarks : PocBenchmarkBase { - [Params(BenchmarkType.Array, BenchmarkType.List, BenchmarkType.PooledList, BenchmarkType.RecyclableArrayList, BenchmarkType.RecyclableList)] - // [Params(RecyclableListPocBenchmarkType.IndexOf)] - public RecyclableListPocBenchmarkType _benchmarkType; - private Action? _testMethod; + [Params(RecyclableListPocBenchmarkType.IndexOf)] + public override RecyclableListPocBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; } - [Benchmark] - public void RunWhen() => _testMethod!.Invoke(); + // [Params(BenchmarkType.Array, BenchmarkType.List, BenchmarkType.RecyclableArrayList, BenchmarkType.RecyclableList)] + [Params(RecyclableListPocBenchmarkType.IndexOf_PooledList)] + public override RecyclableListPocBenchmarkType 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"); - private RecyclableList? _testRecyclableList; + public RecyclableList TestObjectsAsRecyclableList => _testRecyclableList ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableList)} is null"); private RecyclableListIndexOfV1? _testRecyclableListIndexOfV1; internal RecyclableListIndexOfV1 TestObjectsAsRecyclableListIndexOfV1 => _testRecyclableListIndexOfV1 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableListIndexOfV1)} is null"); private RecyclableListIndexOfV2? _testRecyclableListIndexOfV2; + private RecyclableList? _testRecyclableList; internal RecyclableListIndexOfV2 TestObjectsAsRecyclableListIndexOfV2 => _testRecyclableListIndexOfV2 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableListIndexOfV2)} is null"); private RecyclableListIndexOfV3? _testRecyclableListIndexOfV3; internal RecyclableListIndexOfV3 TestObjectsAsRecyclableListIndexOfV3 => _testRecyclableListIndexOfV3 ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableListIndexOfV3)} is null"); @@ -67,74 +68,32 @@ namespace Recyclable.Collections.Benchmarks.POC public static void Run() { var benchmark = new RecyclableListPocBenchmarks(); - benchmark.RecyclableList_EnsureCapacity_ByPowOf2(); - benchmark.RecyclableList_EnsureCapacityV1_ByPowOf2(); - benchmark.RecyclableList_EnsureCapacityV2_ByPowOf2(); - benchmark.RecyclableList_EnsureCapacityV3_ByPowOf2(); - benchmark.RecyclableList_EnsureCapacity_ByBlockSize(); - benchmark.RecyclableList_EnsureCapacityV1_ByBlockSize(); - benchmark.RecyclableList_EnsureCapacityV2_ByBlockSize(); - benchmark.RecyclableList_EnsureCapacityV3_ByBlockSize(); + benchmark.Setup(); + // benchmark.RecyclableList_EnsureCapacity_ByPowOf2(); + // benchmark.RecyclableList_EnsureCapacityV1_ByPowOf2(); + // benchmark.RecyclableList_EnsureCapacityV2_ByPowOf2(); + // benchmark.RecyclableList_EnsureCapacityV3_ByPowOf2(); + // benchmark.RecyclableList_EnsureCapacity_ByBlockSize(); + // benchmark.RecyclableList_EnsureCapacityV1_ByBlockSize(); + // benchmark.RecyclableList_EnsureCapacityV2_ByBlockSize(); + // benchmark.RecyclableList_EnsureCapacityV3_ByBlockSize(); benchmark.RecyclableList_IndexOf(); benchmark.RecyclableList_IndexOfV1(); benchmark.RecyclableList_IndexOfV2(); benchmark.RecyclableList_IndexOfV3(); benchmark.RecyclableList_IndexOfV4(); + benchmark.Cleanup(); } - [GlobalSetup] - public void Setup() + public override void Setup() { - Console.WriteLine($"Setting up exptected results data"); + Console.WriteLine("******* SETTING UP EXPECTED RESULTS DATA *******"); _testArray = DataGenerator.EnumerateTestObjects(TestObjectCount); - Console.WriteLine($"Setting up test case for benchmark {{{_benchmarkType}}}"); - switch (_benchmarkType) - { - case RecyclableListPocBenchmarkType.IndexOfV1: - _testRecyclableListIndexOfV1 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); - _testMethod = () => RecyclableList_IndexOfV1(); - break; - case RecyclableListPocBenchmarkType.IndexOfV2: - _testRecyclableListIndexOfV2 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); - _testMethod = () => RecyclableList_IndexOfV2(); - break; - case RecyclableListPocBenchmarkType.IndexOfV3: - _testRecyclableListIndexOfV3 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); - _testMethod = () => RecyclableList_IndexOfV3(); - break; - case RecyclableListPocBenchmarkType.IndexOfV4: - _testRecyclableListIndexOfV4 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); - _testMethod = () => RecyclableList_IndexOfV4(); - break; - case RecyclableListPocBenchmarkType.IndexOf_PooledList: - _testPooledList = new PooledList(TestObjects, ClearMode.Auto); - _testMethod = () => PooledList_IndexOf(); - break; - case RecyclableListPocBenchmarkType.IndexOf: - _testRecyclableList = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); - _testMethod = () => RecyclableList_IndexOf(); - break; - case RecyclableListPocBenchmarkType.EnsureCapacity_ByPowOf2: - _testMethod = () => RecyclableList_EnsureCapacity_ByPowOf2(); - break; - case RecyclableListPocBenchmarkType.EnsureCapacityV1_ByPowOf2: - _testMethod = () => RecyclableList_EnsureCapacityV1_ByPowOf2(); - break; - case RecyclableListPocBenchmarkType.EnsureCapacityV2_ByPowOf2: - _testMethod = () => RecyclableList_EnsureCapacityV2_ByPowOf2(); - break; - case RecyclableListPocBenchmarkType.EnsureCapacityV3_ByPowOf2: - _testMethod = () => RecyclableList_EnsureCapacityV3_ByPowOf2(); - break; - default: - throw new InvalidOperationException($"Unknown benchmark type {{{_benchmarkType}}}"); - } - Console.WriteLine("Data prepared"); - } + base.Setup(); + } - [GlobalCleanup] - public void Cleanup() + public override void Cleanup() { _testArray = null; _testRecyclableList?.Dispose(); @@ -149,7 +108,50 @@ namespace Recyclable.Collections.Benchmarks.POC _testRecyclableListIndexOfV4 = null; _testPooledList?.Dispose(); _testPooledList = null; - GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true); + + base.Cleanup(); } - } + + protected override Action? GetTestMethod(RecyclableListPocBenchmarkType benchmarkType) => benchmarkType switch + { + RecyclableListPocBenchmarkType.IndexOfV1 => () => RecyclableList_IndexOfV1(), + RecyclableListPocBenchmarkType.IndexOfV2 => () => RecyclableList_IndexOfV2(), + RecyclableListPocBenchmarkType.IndexOfV3 => () => RecyclableList_IndexOfV3(), + RecyclableListPocBenchmarkType.IndexOfV4 => () => RecyclableList_IndexOfV4(), + RecyclableListPocBenchmarkType.IndexOf_PooledList => () => PooledList_IndexOf(), + RecyclableListPocBenchmarkType.IndexOf => () => RecyclableList_IndexOf(), + RecyclableListPocBenchmarkType.EnsureCapacity_ByPowOf2 => () => RecyclableList_EnsureCapacity_ByPowOf2(), + RecyclableListPocBenchmarkType.EnsureCapacityV1_ByPowOf2 => () => RecyclableList_EnsureCapacityV1_ByPowOf2(), + RecyclableListPocBenchmarkType.EnsureCapacityV2_ByPowOf2 => () => RecyclableList_EnsureCapacityV2_ByPowOf2(), + RecyclableListPocBenchmarkType.EnsureCapacityV3_ByPowOf2 => () => RecyclableList_EnsureCapacityV3_ByPowOf2(), + _ => throw CreateUnknownBenchmarkTypeException(benchmarkType), + }; + + protected override void PrepareData(T benchmarkType) + { + base.PrepareData(benchmarkType); + + switch (BenchmarkType) + { + case RecyclableListPocBenchmarkType.IndexOfV1: + _testRecyclableListIndexOfV1 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); + break; + case RecyclableListPocBenchmarkType.IndexOfV2: + _testRecyclableListIndexOfV2 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); + break; + case RecyclableListPocBenchmarkType.IndexOfV3: + _testRecyclableListIndexOfV3 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); + break; + case RecyclableListPocBenchmarkType.IndexOfV4: + _testRecyclableListIndexOfV4 = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); + break; + case RecyclableListPocBenchmarkType.IndexOf_PooledList: + _testPooledList = new PooledList(TestObjects, ClearMode.Auto); + break; + case RecyclableListPocBenchmarkType.IndexOf: + _testRecyclableList = new(TestObjects, BlockSize, expectedItemsCount: TestObjectCount); + break; + } + } + } } diff --git a/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs index 48e1bcf..d3b8223 100644 --- a/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs @@ -2,26 +2,44 @@ namespace Recyclable.Collections.Benchmarks.POC { - public class RoundBenchmarks : PocBenchmarkBase + public enum RoundBenchmarkType { + MathFloor, + MathRound, + WithTypecasting, + } + + public class RoundBenchmarks : PocBenchmarkBase + { + [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; - [Benchmark(Baseline = true)] public void RoundWithMathFloor() { DoNothing((long)Math.Floor(TestObjectCount * OptimalParallelSearchStep)); } - [Benchmark] public void RoundWithMathRound() { DoNothing((long)Math.Round(TestObjectCount * OptimalParallelSearchStep, 0)); } - [Benchmark(Baseline = false)] 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), + }; } } diff --git a/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs index d4dd096..b270c14 100644 --- a/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs @@ -2,10 +2,43 @@ namespace Recyclable.Collections.Benchmarks.POC { - public class SpanVsArrayBenchmarks : BenchmarkBase + public enum SpanVsArrayBenchmarkType { - //[Benchmark] - public void ArrayGetWithVar() + ArrayGetWithVar, + ArrayGetWithField, + SpanGet, + ArraySetWithVar, + ArraySetWithField, + SpanSet + } + + public class SpanVsArrayBenchmarks : RecyclableBenchmarkBase + { + // [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; @@ -15,7 +48,6 @@ namespace Recyclable.Collections.Benchmarks.POC } } - //[Benchmark(Baseline = true)] public void ArrayGetWithField() { var dataCount = TestObjectCount; @@ -25,7 +57,6 @@ namespace Recyclable.Collections.Benchmarks.POC } } - //[Benchmark] public void SpanGet() { var dataCount = TestObjectCount; @@ -36,7 +67,6 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void ArraySetWithVar() { var data = TestObjects; @@ -47,7 +77,6 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark(Baseline = true)] public void ArraySetWithField() { var dataCount = TestObjectCount; @@ -57,7 +86,6 @@ namespace Recyclable.Collections.Benchmarks.POC } } - [Benchmark] public void SpanSet() { var dataCount = TestObjectCount; diff --git a/Recyclable.Collections.Benchmarks/POC/WhenParallelSearchBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/WhenParallelSearchBenchmarks.cs index 1a33945..bad4c11 100644 --- a/Recyclable.Collections.Benchmarks/POC/WhenParallelSearchBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/WhenParallelSearchBenchmarks.cs @@ -1,19 +1,18 @@ using BenchmarkDotNet.Attributes; using MoreLinq; using System.Runtime.CompilerServices; -using System.Threading; namespace Recyclable.Collections.Benchmarks.POC { - [MemoryDiagnoser] - public class WhenParallelSearchBenchmarks : PocBenchmarkBase + public enum WhenParallelSearchBenchmarkType { - [MethodImpl(MethodImplOptions.NoInlining)] - private static void DoNothing(T index) - { - //Console.WriteLine(index); - } + IndexOfSequentially, + IndexOfParallel, + } + [MemoryDiagnoser] + public class WhenParallelSearchBenchmarks : PocBenchmarkBase + { //[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32)] //public int NumberOfThreads { get; set; } = 3; @@ -26,32 +25,11 @@ namespace Recyclable.Collections.Benchmarks.POC public object? ItemToFind { get; set; } - [GlobalSetup] - public void Setup() - { - _testData = Enumerable.Range(1, TestObjectCount).Cast().ToRecyclableList(BlockSize); - ItemToFind = _testData.Last(); - } + [Params(WhenParallelSearchBenchmarkType.IndexOfParallel)] + public override WhenParallelSearchBenchmarkType BenchmarkType { get => base.BenchmarkType; set => base.BenchmarkType = value; } - [GlobalCleanup] - public void Cleanup() - { - _testData = default; - } - - [Benchmark(Baseline = true)] - public void IndexOfSequentially() - { - long index = DoLongIndexOfSequentially(); - if (index >= 0) - { - DoNothing(index); - } - else - { - throw new Exception("Item not found"); - } - } + [Params(WhenParallelSearchBenchmarkType.IndexOfSequentially)] + public override WhenParallelSearchBenchmarkType BaselineBenchmarkType { get => base.BaselineBenchmarkType; set => base.BaselineBenchmarkType = value; } private long DoLongIndexOfSequentially() { @@ -95,7 +73,7 @@ namespace Recyclable.Collections.Benchmarks.POC int blockIndex = searchInfo.BlockIndex; long itemsToSearchCount = searchInfo.ItemsToSearchCount; long[][] memoryBlocks = list.AsArray; - index = Array.IndexOf(memoryBlocks[searchInfo.BlockIndex], itemToFind, searchInfo.StartingItemIndex, blockSize - searchInfo.StartingItemIndex); + index = Array.IndexOf(memoryBlocks[searchInfo.BlockIndex], itemToFind, 0, blockSize); if (itemFoundSignal.IsSet) { return -1; @@ -105,7 +83,7 @@ namespace Recyclable.Collections.Benchmarks.POC return (blockIndex << list.BlockSizePow2BitShift) + index; } - itemsToSearchCount -= blockSize - searchInfo.StartingItemIndex; + itemsToSearchCount -= blockSize; if (itemsToSearchCount < 0) { return -1; @@ -145,20 +123,6 @@ namespace Recyclable.Collections.Benchmarks.POC return itemFoundSignal.IsSet || index < 0 ? -1 : ((long)lastBlockWithData << list.BlockSizePow2BitShift) + index; } - [Benchmark] - public void IndexOfParallel() - { - var index = DoIndexOfParallel(); - if (index >= 0) - { - DoNothing(index); - } - else - { - throw new Exception("Item not found"); - } - } - private long DoIndexOfParallel() { using var itemFoundSignal = new ManualResetEventSlim(false); @@ -271,7 +235,55 @@ namespace Recyclable.Collections.Benchmarks.POC //} allDoneSignal.SignalAndWait(); + throw new NotImplementedException(); return foundItemIndex; } + + protected override void PrepareData(T benchmarkType) + { + base.PrepareData(benchmarkType); + + _testData ??= Enumerable.Range(1, TestObjectCount).Cast().ToRecyclableList(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"); + } + } } } diff --git a/Recyclable.Collections.Benchmarks/BenchmarkBase.cs b/Recyclable.Collections.Benchmarks/RecyclableBenchmarkBase.cs similarity index 75% rename from Recyclable.Collections.Benchmarks/BenchmarkBase.cs rename to Recyclable.Collections.Benchmarks/RecyclableBenchmarkBase.cs index 41925f4..28a163f 100644 --- a/Recyclable.Collections.Benchmarks/BenchmarkBase.cs +++ b/Recyclable.Collections.Benchmarks/RecyclableBenchmarkBase.cs @@ -1,10 +1,21 @@ using BenchmarkDotNet.Attributes; +using Collections.Pooled; using Recyclable.Collections.Benchmarks.Core; using Recyclable.Collections.Benchmarks.POC; namespace Recyclable.Collections.Benchmarks { - public class BenchmarkBase : PocBenchmarkBase + public enum RecyclableCollectionsBenchmarkSource + { + Array, + List, + PooledList, + RecyclableArrayList, + RecyclableList, + } + + [MemoryDiagnoser] + public class RecyclableBenchmarkBase : PocBenchmarkBase { protected long[]? _testObjects; protected long[] TestObjects => _testObjects ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); @@ -12,6 +23,8 @@ namespace Recyclable.Collections.Benchmarks protected List? _testObjectsAsList; protected List TestObjectsAsList => _testObjectsAsList ?? throw new NullReferenceException("Something went wront and the field is not initialized"); + protected PooledList? _testObjectsAsPooledList; + public PooledList TestObjectsAsPooledList => _testObjectsAsPooledList ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); protected RecyclableArrayList? _testObjectsAsRecyclableArrayList; protected RecyclableArrayList TestObjectsAsRecyclableArrayList => _testObjectsAsRecyclableArrayList ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); protected RecyclableList? _testObjectsAsRecyclableList; @@ -27,16 +40,45 @@ namespace Recyclable.Collections.Benchmarks } } - [GlobalSetup] - public virtual void Setup() + public override void Setup() { - Console.WriteLine("******* GLOBAL SETUP *******"); - _testObjects = DataGenerator.EnumerateTestObjects(TestObjectCount); - Console.WriteLine("******* TEST DATA CREATED *******"); + PrepareData(RecyclableCollectionsBenchmarkSource.Array); + base.Setup(); } - [GlobalCleanup] - public virtual void Cleanup() + protected override void PrepareData(T benchmarkType) + { + Console.WriteLine($"******* PREPARING DATA FOR {benchmarkType} *******"); + switch (benchmarkType) + { + case RecyclableCollectionsBenchmarkSource.Array: + _testObjects ??= DataGenerator.EnumerateTestObjects(TestObjectCount); + break; + + case RecyclableCollectionsBenchmarkSource.List: + _testObjectsAsList ??= TestObjects.ToList(); + break; + + case RecyclableCollectionsBenchmarkSource.PooledList: + _testObjectsAsPooledList ??= new PooledList(TestObjects, ClearMode.Auto); + break; + + case RecyclableCollectionsBenchmarkSource.RecyclableArrayList: + _testObjectsAsRecyclableArrayList ??= new(TestObjects, initialCapacity: TestObjectCount); + break; + + case RecyclableCollectionsBenchmarkSource.RecyclableList: + _testObjectsAsRecyclableList ??= 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 @@ -46,7 +88,14 @@ namespace Recyclable.Collections.Benchmarks //} _testObjects = default; - GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true); + _testObjectsAsList = default; + _testObjectsAsPooledList?.Dispose(); + _testObjectsAsPooledList = default; + _testObjectsAsRecyclableArrayList?.Dispose(); + _testObjectsAsRecyclableArrayList = default; + _testObjectsAsRecyclableList?.Dispose(); + _testObjectsAsRecyclableList = default; + base.Cleanup(); } }