Files
Recyclable.Collections/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerBenchmarks.cs
T

350 lines
9.8 KiB
C#

// Ignore Spelling: Poc Structs Unboxed Funcs Comparers
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum DelegateVsComparerBenchmarkType
{
Comparer,
Delegate,
Func,
ListOfBoxedStructs,
ListOfClasses,
ListOfComparers,
ListOfDelegates,
ListOfFuncs,
ListOfLocalFuncs,
ListOfStructs,
ListOfUnboxedReadOnlyStructs,
ListOfUnboxedStructs,
StaticFunc,
}
[MemoryDiagnoser]
public class DelegateVsComparerBenchmarks : BaselineVsActualBenchmarkBase<DelegateVsComparerBenchmarkType>
{
[Params
(
DelegateVsComparerBenchmarkType.Delegate,
DelegateVsComparerBenchmarkType.Func,
DelegateVsComparerBenchmarkType.ListOfBoxedStructs,
DelegateVsComparerBenchmarkType.ListOfClasses,
DelegateVsComparerBenchmarkType.ListOfComparers,
DelegateVsComparerBenchmarkType.ListOfDelegates,
DelegateVsComparerBenchmarkType.ListOfFuncs,
DelegateVsComparerBenchmarkType.ListOfLocalFuncs,
DelegateVsComparerBenchmarkType.ListOfStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedReadOnlyStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedStructs,
DelegateVsComparerBenchmarkType.StaticFunc
)]
public override DelegateVsComparerBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(DelegateVsComparerBenchmarkType.Comparer)]
public override DelegateVsComparerBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
#region Dummy classes
private delegate T Compare<T>(T x, T y);
public readonly struct MyComparerReadOnlyStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Comparer<T>.Default.Compare(x, y);
}
private struct MyComparerStruct<T> : IComparer<T>
{
public readonly int Compare(T? x, T? y) => Comparer<T>.Default.Compare(x, y);
}
private class MyComparer : IComparer<long>
{
public int Compare(long x, long y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
#endregion
public static void Run()
{
var benchmark = new DelegateVsComparerBenchmarks();
benchmark.Setup();
benchmark.Comparer();
benchmark.Delegate();
benchmark.Func();
benchmark.ListOfBoxedStructs();
benchmark.ListOfClasses();
benchmark.ListOfComparers();
benchmark.ListOfDelegates();
benchmark.ListOfFuncs();
benchmark.ListOfLocalFuncs();
benchmark.ListOfStructs();
benchmark.ListOfUnboxedReadOnlyStructs();
benchmark.ListOfUnboxedStructs();
benchmark.StaticFunc();
benchmark.Cleanup();
}
private static readonly Comparer<long> _comparer = Comparer<long>.Default;
private IEnumerable<long>? _testObjects;
private IEnumerable<Func<long, long, int>>? _testListOfFunctions;
private IEnumerable<IComparer<long>>? _testListOfComparers;
private IEnumerable<Compare<long>>? _testListOfDelegates;
private IEnumerable<Func<long, long, int>>? _testListOfLocalFunctions;
private IEnumerable<MyComparer>? _testListOfClasses;
private IEnumerable<MyComparerStruct<long>>? _testListOfStructs;
private IEnumerable<IComparer<long>>? _testListOfBoxedStructs;
private IEnumerable<TComparer> TestListOfUnboxedStructs<TComparer, TValue>() where TComparer : IComparer<TValue>, new()
{
foreach (var _ in _testObjects!)
{
yield return new TComparer();
}
}
private static IEnumerable<Func<long, long, int>> GetLocalFunctions(IEnumerable<long> testObjects)
{
static int compareFunc(long x, long y)
{
return (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
};
}
foreach (var _ in testObjects)
{
yield return compareFunc;
}
}
private void TestWithComparer(IComparer<long> comparer)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = comparer.Compare(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithDelegate(Compare<long> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithFunc(Func<long, long, int> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
public void Comparer()
{
TestWithComparer(_comparer);
}
public void Func()
{
TestWithFunc((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void StaticFunc()
{
TestWithFunc(static (x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void Delegate()
{
TestWithDelegate((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void ListOfFuncs()
{
const long X = 2, Y = 5;
var testData = _testListOfFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(X, Y);
}
}
public void ListOfLocalFuncs()
{
const long X = 2, Y = 5;
var testData = _testListOfLocalFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(X, Y);
}
}
public void ListOfComparers()
{
const long X = 2, Y = 5;
var testData = _testListOfComparers!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfClasses()
{
const long X = 2, Y = 5;
var testData = _testListOfClasses!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfStructs()
{
const long X = 2, Y = 5;
var testData = _testListOfStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfBoxedStructs()
{
const long X = 2, Y = 5;
var testData = _testListOfBoxedStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfUnboxedStructs()
{
const long X = 2, Y = 5;
var testData = TestListOfUnboxedStructs<MyComparerStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfUnboxedReadOnlyStructs()
{
const long X = 2, Y = 5;
var testData = TestListOfUnboxedStructs<MyComparerReadOnlyStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfDelegates()
{
const long X = 2, Y = 5;
var testData = _testListOfDelegates!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareDelegate = testData[itemIdx];
_ = compareDelegate(X, Y);
}
}
protected override Action? GetTestMethod(DelegateVsComparerBenchmarkType benchmarkType) => benchmarkType switch
{
DelegateVsComparerBenchmarkType.Comparer => Comparer,
DelegateVsComparerBenchmarkType.Delegate => Delegate,
DelegateVsComparerBenchmarkType.Func => Func,
DelegateVsComparerBenchmarkType.ListOfBoxedStructs => ListOfBoxedStructs,
DelegateVsComparerBenchmarkType.ListOfClasses => ListOfClasses,
DelegateVsComparerBenchmarkType.ListOfComparers => ListOfComparers,
DelegateVsComparerBenchmarkType.ListOfDelegates => ListOfDelegates,
DelegateVsComparerBenchmarkType.ListOfFuncs => ListOfFuncs,
DelegateVsComparerBenchmarkType.ListOfLocalFuncs => ListOfLocalFuncs,
DelegateVsComparerBenchmarkType.ListOfStructs => ListOfStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedReadOnlyStructs => ListOfUnboxedReadOnlyStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedStructs => ListOfUnboxedStructs,
DelegateVsComparerBenchmarkType.StaticFunc => StaticFunc,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
public override void Setup()
{
Console.WriteLine("******* SETTING UP COMMON TEST DATA *******");
_testObjects = Enumerable.Range(1, TestObjectCount).Select(x => (long)x);
base.Setup();
}
public override void Cleanup()
{
_testObjects = null;
base.Cleanup();
}
protected override void PrepareData<T>(T benchmarkType)
{
switch (benchmarkType)
{
case DelegateVsComparerBenchmarkType.ListOfBoxedStructs:
_testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer<long>)new MyComparerStruct<long>());
break;
case DelegateVsComparerBenchmarkType.ListOfClasses:
_testListOfClasses = _testObjects!.Select(_ => new MyComparer());
break;
case DelegateVsComparerBenchmarkType.ListOfComparers:
_testListOfComparers = _testObjects!.Select(_ => (IComparer<long>)new MyComparer());
break;
case DelegateVsComparerBenchmarkType.ListOfDelegates:
_testListOfDelegates = _testObjects!.Select(_ => new Compare<long>((x, y) => new MyComparer().Compare(x, y)));
break;
case DelegateVsComparerBenchmarkType.ListOfFuncs:
_testListOfFunctions = _testObjects!.Select<long, Func<long, long, int>>(static _ => new MyComparer().Compare);
break;
case DelegateVsComparerBenchmarkType.ListOfLocalFuncs:
_testListOfLocalFunctions = GetLocalFunctions(_testObjects!);
break;
case DelegateVsComparerBenchmarkType.ListOfStructs:
_testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct<long>());
break;
}
}
}
}