Release 0.0.1
This commit is contained in:
1 parent
ccf5c61dd0
commit
f4a03406e3
10 files changed
+347
-1
No files matched your search
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.7.34031.279
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Collections.Benchmarks.Core", "Collections.Benchmarks.Core\Collections.Benchmarks.Core.csproj", "{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{CDB4A29F-D53D-4779-8DE2-EF6CA050DB11}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {3626D07F-F4BD-4292-8087-4DE458A2ADB6}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Collections.Benchmarks.Core
|
||||||
|
{
|
||||||
|
public abstract class BaselineVsActualBenchmarkBase<TBenchmarkType>
|
||||||
|
{
|
||||||
|
public virtual TBenchmarkType? DataType { get; set; }
|
||||||
|
public virtual TBenchmarkType? BaseDataType { get; set; }
|
||||||
|
|
||||||
|
private Action? _testMethod;
|
||||||
|
protected Action TestMethod
|
||||||
|
{
|
||||||
|
get => _testMethod ?? throw new OperationCanceledException("Skip - No actual defined");
|
||||||
|
set => _testMethod = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Action? _baselineMethod;
|
||||||
|
protected Action BaselineMethod
|
||||||
|
{
|
||||||
|
get => _baselineMethod ?? throw new OperationCanceledException("Skip - No baseline defined");
|
||||||
|
set => _baselineMethod = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public void Baseline() => BaselineMethod.Invoke();
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void Actual() => TestMethod.Invoke();
|
||||||
|
|
||||||
|
public virtual int BlockSize { get; protected set; }
|
||||||
|
public byte BlockSizePow2BitShift => checked((byte)(31 - BitOperations.LeadingZeroCount((uint)BlockSize)));
|
||||||
|
public virtual int Divider { get; protected set; } = 10;
|
||||||
|
public virtual int TestObjectCount { get; set; } = 0;
|
||||||
|
public virtual int TestObjectCountForSlowMethods { get; private set; }
|
||||||
|
|
||||||
|
protected static Exception CreateUnknownBenchmarkTypeException<T>(T benchmarkType)
|
||||||
|
{
|
||||||
|
return new InvalidOperationException($"******* UNKNOWN BENCHMARK TYPE {{{benchmarkType}}} *******");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Exception CreateMethodNotFoundException(in string methodName, in string? className)
|
||||||
|
{
|
||||||
|
return new MethodAccessException($"******* METHOD {{{methodName}}} NOT FOUND IN CLASS {{{className}}} *******");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void PrepareData<T>(T benchmarkType) { }
|
||||||
|
protected virtual Action? GetTestMethod(TBenchmarkType? benchmarkType) => null;
|
||||||
|
|
||||||
|
[GlobalCleanup]
|
||||||
|
public virtual void Cleanup()
|
||||||
|
{
|
||||||
|
_baselineMethod = null;
|
||||||
|
_testMethod = null;
|
||||||
|
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[GlobalSetup]
|
||||||
|
public virtual void Setup()
|
||||||
|
{
|
||||||
|
Console.WriteLine($"******* SETTING UP TEST CASE FOR BENCHMARK {{{DataType}}} *******");
|
||||||
|
|
||||||
|
TestObjectCountForSlowMethods = (TestObjectCount / 2) + 1;
|
||||||
|
|
||||||
|
BlockSize = TestObjectCount switch
|
||||||
|
{
|
||||||
|
0 => 1,
|
||||||
|
> 0 and <= 10_240 => TestObjectCount,
|
||||||
|
_ => TestObjectCount / Divider > 0 ? TestObjectCount / Divider : TestObjectCount
|
||||||
|
};
|
||||||
|
|
||||||
|
if (BlockSize > 0)
|
||||||
|
{
|
||||||
|
BlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)BlockSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"******* BaseDataType = {BaseDataType}; default = {default(TBenchmarkType)} *******");
|
||||||
|
|
||||||
|
if (!EqualityComparer<TBenchmarkType>.Default.Equals(BaseDataType, default))
|
||||||
|
{
|
||||||
|
Console.WriteLine("******* SETTING UP BASELINE DATA *******");
|
||||||
|
PrepareData(BaseDataType);
|
||||||
|
_baselineMethod = GetTestMethod(BaseDataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ We don't want to prepare data if baseline data is the same is benchmark data.
|
||||||
|
//~ One would override another - waste of time & resources.
|
||||||
|
if (!EqualityComparer<TBenchmarkType>.Default.Equals(BaseDataType, DataType))
|
||||||
|
{
|
||||||
|
Console.WriteLine("******* SETTING UP TEST CASE DATA *******");
|
||||||
|
//~ If BaseDataType == null, then we'll come here only if DataType != null.
|
||||||
|
PrepareData(DataType!);
|
||||||
|
_testMethod = GetTestMethod(DataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("******* DATA PREPARED *******");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<PackageId>Collections.Benchmarks.Core</PackageId>
|
||||||
|
<PackageVersion>0.0.1</PackageVersion>
|
||||||
|
<Authors>Marek Lemańczyk</Authors>
|
||||||
|
<Company>N/A</Company>
|
||||||
|
<Product>Collections.Benchmarks.Core</Product>
|
||||||
|
<PackageTags>Recyclable Array Pool List Sortable Sort Benchmark Benchmarks Collection Collections</PackageTags>
|
||||||
|
<Description>`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.</Description>
|
||||||
|
<PackageProjectUrl>https://github.com/mlemanczyk/Collections.Benchmarks.Core</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://github.com/mlemanczyk/Collections.Benchmarks.Core</RepositoryUrl>
|
||||||
|
<Copyright>Marek Lemańczyk 2023</Copyright>
|
||||||
|
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageReleaseNotes>Initial version.</PackageReleaseNotes>
|
||||||
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
|
<PackageIconUrl>https://github.com/mlemanczyk/Collections.Benchmarks.Core/logo.png</PackageIconUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\LICENSE.md" Pack="true" PackagePath="" Link="LICENSE.md">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="..\README.md" Pack="true" PackagePath="" Link="README.md">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.9" />
|
||||||
|
<PackageReference Include="Collections.Pooled" Version="1.0.82" />
|
||||||
|
<PackageReference Include="Recyclable.Collections" Version="0.0.6" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Collections.Pooled;
|
||||||
|
using Recyclable.Collections;
|
||||||
|
|
||||||
|
namespace Collections.Benchmarks.Core
|
||||||
|
{
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class CollectionsBenchmarksBase<TBenchmarkType> : BaselineVsActualBenchmarkBase<TBenchmarkType>
|
||||||
|
{
|
||||||
|
protected int[]? _testObjects;
|
||||||
|
protected int[] TestObjects => _testObjects ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
|
||||||
|
protected List<int>? _testObjectsAsList;
|
||||||
|
protected List<int> TestObjectsAsList => _testObjectsAsList ?? throw new NullReferenceException("Something went wrong and the field is not initialized");
|
||||||
|
protected PooledList<int>? _testObjectsAsPooledList;
|
||||||
|
public PooledList<int> TestObjectsAsPooledList => _testObjectsAsPooledList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
|
||||||
|
protected RecyclableList<int>? _testObjectsAsRecyclableList;
|
||||||
|
protected RecyclableList<int> TestObjectsAsRecyclableList => _testObjectsAsRecyclableList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
|
||||||
|
protected RecyclableLongList<int>? _testObjectsAsRecyclableLongList;
|
||||||
|
protected RecyclableLongList<int> TestObjectsAsRecyclableLongList => _testObjectsAsRecyclableLongList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
|
||||||
|
protected IEnumerable<int> TestObjectsAsIEnumerable
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (int i = 1; i <= TestObjectCount; i++)
|
||||||
|
{
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PrepareData<T>(T benchmarkType)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"******* PREPARING DATA FOR {benchmarkType} *******");
|
||||||
|
switch (benchmarkType)
|
||||||
|
{
|
||||||
|
case CollectionsBenchmarksSource.Unknown:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionsBenchmarksSource.Array:
|
||||||
|
_testObjects ??= DataGenerator.EnumerateTestObjects(TestObjectCount);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionsBenchmarksSource.List:
|
||||||
|
_testObjectsAsList ??= TestObjects.ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionsBenchmarksSource.PooledList:
|
||||||
|
_testObjectsAsPooledList ??= new(TestObjects, ClearMode.Auto);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionsBenchmarksSource.RecyclableList:
|
||||||
|
_testObjectsAsRecyclableList ??= new(TestObjects, initialCapacity: TestObjectCount);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CollectionsBenchmarksSource.RecyclableLongList:
|
||||||
|
_testObjectsAsRecyclableLongList ??= new(TestObjects, BlockSize, initialCapacity: base.TestObjectCount);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw CreateUnknownBenchmarkTypeException(benchmarkType);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.PrepareData(benchmarkType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Cleanup()
|
||||||
|
{
|
||||||
|
Console.WriteLine("******* GLOBAL CLEANUP *******");
|
||||||
|
|
||||||
|
if (_testObjects?.Length > 0 && !_testObjects[0].GetType().IsValueType)
|
||||||
|
{
|
||||||
|
Array.Fill(_testObjects, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_testObjects = default;
|
||||||
|
_testObjectsAsList = default;
|
||||||
|
_testObjectsAsPooledList?.Dispose();
|
||||||
|
_testObjectsAsPooledList = default;
|
||||||
|
_testObjectsAsRecyclableList?.Dispose();
|
||||||
|
_testObjectsAsRecyclableList = default;
|
||||||
|
_testObjectsAsRecyclableLongList?.Dispose();
|
||||||
|
_testObjectsAsRecyclableLongList = default;
|
||||||
|
base.Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Setup()
|
||||||
|
{
|
||||||
|
PrepareData(CollectionsBenchmarksSource.Array);
|
||||||
|
base.Setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Collections.Benchmarks.Core
|
||||||
|
{
|
||||||
|
public enum CollectionsBenchmarksSource
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Array,
|
||||||
|
List,
|
||||||
|
PooledList,
|
||||||
|
RecyclableList,
|
||||||
|
RecyclableLongList,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
namespace Collections.Benchmarks.Core
|
||||||
|
{
|
||||||
|
public static class DataGenerator
|
||||||
|
{
|
||||||
|
public static int[] EnumerateTestObjects(int testObjectCount)
|
||||||
|
{
|
||||||
|
var result = new int[testObjectCount];
|
||||||
|
Console.WriteLine("******* TEST DATA ARRAY CREATED *******");
|
||||||
|
|
||||||
|
Span<int> resultSpan = result;
|
||||||
|
for (int i = 0; i < testObjectCount; i++)
|
||||||
|
{
|
||||||
|
resultSpan[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<long> EnumerateTestObjects(long testObjectCount)
|
||||||
|
{
|
||||||
|
Console.WriteLine("******* TEST DATA ARRAY CREATED *******");
|
||||||
|
|
||||||
|
for (int i = 1; i <= testObjectCount; i++)
|
||||||
|
{
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
#pragma warning disable IDE0060 // Remove unused parameter
|
||||||
|
|
||||||
|
namespace Collections.Benchmarks.Core
|
||||||
|
{
|
||||||
|
public static class DoNothing
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||||
|
public static void With<T>(in T item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||||
|
public static void With<T>(in T item1, in T item2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||||
|
public static void With<T>(ReadOnlySpan<T> span)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# License
|
||||||
|
The project & source code is free for educational & personal use. **Any kind** of commercial use requires a donation, as prescribed below.
|
||||||
|
|
||||||
|
# Donation requirements for a life-time, commercial use
|
||||||
|
* Commercial license is paid one time.
|
||||||
|
* It can be obtained by donating $10 for each developer seat, using the link provided below. If you hire 2 developers, you need to donate $20 for a life-time, commercial use of this package.
|
||||||
|
* Your license stays with you, if your developer moves somewhere else.
|
||||||
|
|
||||||
|
# Link for donations
|
||||||
|
[](https://www.buymeacoffee.com/mlemanczyk)
|
||||||
@@ -1 +1,8 @@
|
|||||||
# Recyclable.Collections.Benchmarks
|
# Collections.Benchmarks.Core
|
||||||
|
`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.
|
||||||
|
|
||||||
|
## Included
|
||||||
|
* `BaselineVsActualBenchmarkBase<T>`
|
||||||
|
* `CollectionsBenchmarksBase<T>`
|
||||||
|
* `DataGenerator`
|
||||||
|
* `DoNothing`
|
||||||
Reference in new issue
Block a user