Skip to content

Commit

Permalink
Start adding benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
viceroypenguin committed Apr 30, 2024
1 parent ef180fd commit ddcb0cf
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 1 deletion.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ obj/
# Rider cache/options directory
.idea/

# TestResults
# Test Results
[Tt]est[Rr]esults/
# Benchmark Results
BenchmarkDotNet.Artifacts/

# NuGet Packages
*.nupkg
Expand Down
17 changes: 17 additions & 0 deletions Benchmarks/SuperLinq.Benchmarks/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[*.cs]

dotnet_diagnostic.CA1062.severity = none
dotnet_diagnostic.CA1515.severity = none
dotnet_diagnostic.CA1707.severity = none # CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1861.severity = none # CA1861: Avoid constant arrays as arguments
dotnet_diagnostic.CA2201.severity = none # CA2201: Do not raise reserved exception types

dotnet_diagnostic.IDE0022.severity = none # IDE0022: Use expression body for methods

# XML Documentation
dotnet_diagnostic.CS1573.severity = none # CS1573: Missing XML comment for parameter
dotnet_diagnostic.CS1591.severity = none # CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1712.severity = none # CS1712: Type parameter has no matching typeparam tag in the XML comment (but other type parameters do)

dotnet_diagnostic.MA0046.severity = none
dotnet_diagnostic.MA0053.severity = none
130 changes: 130 additions & 0 deletions Benchmarks/SuperLinq.Benchmarks/LinqTestData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics.CodeAnalysis;

namespace SuperLinq.Benchmarks;

[SuppressMessage("Design", "CA1052:Static holder types should be Static or NotInheritable")]
public class TestDataBenchmark
{
public static IEnumerable<LinqTestData> NoSpecialization()
{
yield return LinqTestData.s_iEnumerable;
}

public static IEnumerable<LinqTestData> CollectionSpecialization()
{
yield return LinqTestData.s_iEnumerable;
yield return LinqTestData.s_iCollection;
}

public static IEnumerable<LinqTestData> CountSpecialization()
{
yield return LinqTestData.s_iEnumerable;
yield return LinqTestData.s_range;
yield return LinqTestData.s_iCollection;
}

public static IEnumerable<LinqTestData> ListSpecialization()
{
yield return LinqTestData.s_iEnumerable;
yield return LinqTestData.s_array;
yield return LinqTestData.s_list;
yield return LinqTestData.s_iList;
}

public static IEnumerable<LinqTestData> FullSpecialization()
{
yield return LinqTestData.s_iEnumerable;
yield return LinqTestData.s_iCollection;
yield return LinqTestData.s_array;
yield return LinqTestData.s_list;
yield return LinqTestData.s_iList;
}
}

public sealed class LinqTestData
{
// this field is a const (not instance field) to avoid creating closures in tested LINQ
internal const int Size = 100;

private static readonly int[] s_arrayOf100Integers = Enumerable.Range(0, Size).ToArray();

internal static readonly LinqTestData s_array = new(s_arrayOf100Integers);
internal static readonly LinqTestData s_list = new(new List<int>(s_arrayOf100Integers));
internal static readonly LinqTestData s_range = new(Enumerable.Range(0, Size));
internal static readonly LinqTestData s_iEnumerable = new(new IEnumerableWrapper<int>(s_arrayOf100Integers));
internal static readonly LinqTestData s_iList = new(new IListWrapper<int>(s_arrayOf100Integers));
internal static readonly LinqTestData s_iCollection = new(new ICollectionWrapper<int>(s_arrayOf100Integers));
internal static readonly LinqTestData s_iOrderedEnumerable = new(s_arrayOf100Integers.OrderBy(i => i)); // OrderBy() returns IOrderedEnumerable (OrderedEnumerable is internal)

private LinqTestData(IEnumerable<int> collection) => Collection = collection;

internal IEnumerable<int> Collection { get; }

public override string ToString()
{
if (ReferenceEquals(this, s_range)) // RangeIterator is a private type
return "Range";

return Collection switch
{
int[] => "Array",
List<int> => "List",
IList<int> => "IList",
ICollection<int> => "ICollection",
IOrderedEnumerable<int> => "IOrderedEnumerable",
_ => "IEnumerable",
};
}

private sealed class IEnumerableWrapper<T>(T[] array) : IEnumerable<T>
{
public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)array).GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => ((IEnumerable<T>)array).GetEnumerator();
}

private sealed class ICollectionWrapper<T>(T[] array) : ICollection<T>
{
private readonly T[] _array = array;

public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)_array).GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => ((IEnumerable<T>)_array).GetEnumerator();

public int Count => _array.Length;
public bool IsReadOnly => true;
public bool Contains(T item) => Array.IndexOf(_array, item) >= 0;
public void CopyTo(T[] array, int arrayIndex) => _array.CopyTo(array, arrayIndex);

public void Add(T item) => throw new NotSupportedException();
public void Clear() => throw new NotSupportedException();
public bool Remove(T item) => throw new NotSupportedException();
}

private sealed class IListWrapper<T>(T[] array) : IList<T>
{
private readonly T[] _array = array;

public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)_array).GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => ((IEnumerable<T>)_array).GetEnumerator();

public int Count => _array.Length;
public bool IsReadOnly => true;
public T this[int index]
{
get => _array[index];
set => throw new NotSupportedException();
}
public bool Contains(T item) => Array.IndexOf(_array, item) >= 0;
public void CopyTo(T[] array, int arrayIndex) => _array.CopyTo(array, arrayIndex);
public int IndexOf(T item) => Array.IndexOf(_array, item);

public void Add(T item) => throw new NotSupportedException();
public void Clear() => throw new NotSupportedException();
public bool Remove(T item) => throw new NotSupportedException();
public void Insert(int index, T item) => throw new NotSupportedException();
public void RemoveAt(int index) => throw new NotSupportedException();
}
}
11 changes: 11 additions & 0 deletions Benchmarks/SuperLinq.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Running;

BenchmarkSwitcher
.FromAssembly(typeof(Program).Assembly)
.Run(
args,
DefaultConfig.Instance
.AddDiagnoser(MemoryDiagnoser.Default)
);
17 changes: 17 additions & 0 deletions Benchmarks/SuperLinq.Benchmarks/SuperLinq.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../../Source/SuperLinq.Async/SuperLinq.Async.csproj" />
<ProjectReference Include="../../Source/SuperLinq/SuperLinq.csproj" />
</ItemGroup>

</Project>
51 changes: 51 additions & 0 deletions Benchmarks/SuperLinq.Benchmarks/Sync/ProjectionBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using BenchmarkDotNet.Attributes;

namespace SuperLinq.Benchmarks.Sync;

[BenchmarkCategory("Projection")]
public class ProjectionBenchmarks : TestDataBenchmark
{
[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void EquiZip(LinqTestData testData) => testData.Collection.EquiZip(testData.Collection);

[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void ZipShortest(LinqTestData testData) => testData.Collection.ZipShortest(testData.Collection);

[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void ZipLongest(LinqTestData testData) => testData.Collection.ZipLongest(testData.Collection);

[Benchmark]
[ArgumentsSource(nameof(CountSpecialization))]
public void CountDown(LinqTestData testData) => testData.Collection.CountDown(5);

[Benchmark]
[ArgumentsSource(nameof(CountSpecialization))]
public void TagFirstLast(LinqTestData testData) => testData.Collection.TagFirstLast();

[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void Index(LinqTestData testData) => testData.Collection.Index();

[Benchmark]
[ArgumentsSource(nameof(NoSpecialization))]
public void IndexBy(LinqTestData testData) => testData.Collection.IndexBy(x => x % 10);

[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void Lag(LinqTestData testData) => testData.Collection.Lag(1);

[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void Lead(LinqTestData testData) => testData.Collection.Lead(1);

[Benchmark]
[ArgumentsSource(nameof(NoSpecialization))]
public void Rank(LinqTestData testData) => testData.Collection.Rank();

[Benchmark]
[ArgumentsSource(nameof(ListSpecialization))]
public void ZipMap(LinqTestData testData) => testData.Collection.ZipMap(_ => true);
}
Loading

0 comments on commit ddcb0cf

Please sign in to comment.