From a3e2f7621ef981e675d95faef717128b4db07f2f Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Sat, 21 Oct 2023 14:44:23 +0200 Subject: [PATCH] CollectionsBenchmarksBase renamed to DataDrivenBenchmarksBase. Small cleanup. --- .../BaselineVsActualBenchmarkBase.cs | 17 +++++++---------- .../Collections.Benchmarks.Core.csproj | 11 +++++++---- .../CollectionsBenchmarkType.cs | 13 +++++++++++++ ...rksBase.cs => DataDrivenBenchmarksBase.cs} | 4 ++-- logo.png | Bin 3100 -> 14559 bytes 5 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 Collections.Benchmarks.Core/CollectionsBenchmarkType.cs rename Collections.Benchmarks.Core/{CollectionsBenchmarksBase.cs => DataDrivenBenchmarksBase.cs} (96%) diff --git a/Collections.Benchmarks.Core/BaselineVsActualBenchmarkBase.cs b/Collections.Benchmarks.Core/BaselineVsActualBenchmarkBase.cs index 4e69ef7..ec563f2 100644 --- a/Collections.Benchmarks.Core/BaselineVsActualBenchmarkBase.cs +++ b/Collections.Benchmarks.Core/BaselineVsActualBenchmarkBase.cs @@ -1,5 +1,6 @@ using BenchmarkDotNet.Attributes; using System.Numerics; +using System.Reflection; namespace Collections.Benchmarks.Core { @@ -34,18 +35,14 @@ namespace Collections.Benchmarks.Core public virtual int TestObjectCount { get; set; } = 0; public virtual int TestObjectCountForSlowMethods { get; private set; } - 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 static Exception CreateUnknownBenchmarkTypeException(T benchmarkType) => new InvalidOperationException($"******* UNKNOWN BENCHMARK TYPE {{{benchmarkType}}} *******"); + protected static Exception CreateMethodNotFoundException(in string methodName, in string? className) => new MethodAccessException($"******* METHOD {{{methodName}}} NOT FOUND IN CLASS {{{className}}} *******"); protected virtual void PrepareData(T benchmarkType) { } - protected virtual Action? GetTestMethod(TBenchmarkType? benchmarkType) => null; + protected virtual Action? GetTestMethod(TBenchmarkType? benchmarkType) + => (Action?)GetType().GetMethod(GetTestMethodName(benchmarkType), BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)?.CreateDelegate(typeof(Action), this) ?? throw CreateMethodNotFoundException(GetTestMethodName(benchmarkType), GetType().FullName); + + protected virtual string GetTestMethodName(TBenchmarkType? benchmarkType) => $"{benchmarkType}"; [GlobalCleanup] public virtual void Cleanup() diff --git a/Collections.Benchmarks.Core/Collections.Benchmarks.Core.csproj b/Collections.Benchmarks.Core/Collections.Benchmarks.Core.csproj index badc0fc..acef3e5 100644 --- a/Collections.Benchmarks.Core/Collections.Benchmarks.Core.csproj +++ b/Collections.Benchmarks.Core/Collections.Benchmarks.Core.csproj @@ -7,24 +7,27 @@ Library true Collections.Benchmarks.Core - 0.0.1 + 0.0.4 Marek Lemańczyk N/A Collections.Benchmarks.Core Recyclable Array Pool List Sortable Sort Benchmark Benchmarks Collection Collections - `Recyclable.Collections.Benchmarks.Core` project is a basic open source framework for performance measurements based on various collection types like `RecyclableList<T>`, `RecyclableLongList<T>`, `List<T>`, `SortableList<T>`, `PriorityQueue<T>` & similar. + `Collections.Benchmarks.Core` project is a basic open source framework for performance measurements based on various collection types like `RecyclableList<T>`, `RecyclableLongList<T>`, `List<T>`, `SortableList<T>`, `PriorityQueue<T>` & similar. https://github.com/mlemanczyk/Collections.Benchmarks.Core https://github.com/mlemanczyk/Collections.Benchmarks.Core Marek Lemańczyk 2023 LICENSE.md README.md git - Initial version. + CollectionsBenchmarksBase renamed to DataDrivenBenchmarksBase. Small cleanup. AnyCPU;x64 - https://github.com/mlemanczyk/Collections.Benchmarks.Core/logo.png + logo.png + + PreserveNewest + PreserveNewest diff --git a/Collections.Benchmarks.Core/CollectionsBenchmarkType.cs b/Collections.Benchmarks.Core/CollectionsBenchmarkType.cs new file mode 100644 index 0000000..97820ea --- /dev/null +++ b/Collections.Benchmarks.Core/CollectionsBenchmarkType.cs @@ -0,0 +1,13 @@ +namespace Collections.Benchmarks.Core +{ + public enum CollectionsBenchmarkType + { + Unknown, Add_WithCapacity, Add, AddRange_WithCapacity, AddRangeWhenSourceIsArray, AddRangeWhenSourceIsIEnumerable, + AddRangeWhenSourceIsIList, AddRangeWhenSourceIsList, AddRangeWhenSourceIsSameType, BinarySearch_BestAndWorstCases, + Contains_FirstItems, Contains_LastItems, ConvertAll, Count, Create_WithCapacity, Create, Exists_BestAndWorstCases, + Find_BestAndWorstCases, FindAll_BestAndWorstCases, FindLast_BestAndWorstCases, FindLastIndex_BestAndWorstCases, + ForEach, GetItem, IndexOf_BestAndWorstCases,IndexOf_FirstItems, IndexOf_LastItems, LongCount, + Remove_FirstItems, Remove_LastItems, RemoveAt_FirstItems, RemoveAt_LastItems, + SetItem, VersionedForEach + } +} diff --git a/Collections.Benchmarks.Core/CollectionsBenchmarksBase.cs b/Collections.Benchmarks.Core/DataDrivenBenchmarksBase.cs similarity index 96% rename from Collections.Benchmarks.Core/CollectionsBenchmarksBase.cs rename to Collections.Benchmarks.Core/DataDrivenBenchmarksBase.cs index 181e4d4..ecb71fc 100644 --- a/Collections.Benchmarks.Core/CollectionsBenchmarksBase.cs +++ b/Collections.Benchmarks.Core/DataDrivenBenchmarksBase.cs @@ -5,7 +5,7 @@ using Recyclable.Collections; namespace Collections.Benchmarks.Core { [MemoryDiagnoser] - public class CollectionsBenchmarksBase : BaselineVsActualBenchmarkBase + public class DataDrivenBenchmarksBase : BaselineVsActualBenchmarkBase { protected int[]? _testObjects; protected int[] TestObjects => _testObjects ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); @@ -62,7 +62,7 @@ namespace Collections.Benchmarks.Core base.PrepareData(benchmarkType); } - + public override void Cleanup() { Console.WriteLine("******* GLOBAL CLEANUP *******"); diff --git a/logo.png b/logo.png index 078521cf60ab03135993f633a406fc69ba205aab..da8146096e79f5b9cff6fffaf17b827d57f37afd 100644 GIT binary patch literal 14559 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