Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collections benchmarks rewrite #92

Merged
merged 32 commits into from
Jul 20, 2018
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
13e43b2
ctor default size all collections benchmarks
adamsitnik Jul 11, 2018
85f98c1
ctor given size all collections benchmarks
adamsitnik Jul 11, 2018
34fc804
ctor from collection all collections benchmarks
adamsitnik Jul 11, 2018
af04aa7
move to a dedicated folder, add categories
adamsitnik Jul 11, 2018
8fb685d
iterate for each all collections
adamsitnik Jul 11, 2018
3321633
iterate for loop all collections
adamsitnik Jul 11, 2018
cf7fa2f
iterate for each non generic collections
adamsitnik Jul 11, 2018
578c546
iterate for loop non generic collections
adamsitnik Jul 11, 2018
cfafed8
update to BDN which offers glob filtering so I can filter like a pro ;)
adamsitnik Jul 11, 2018
1f81328
Contains for all generic collections
adamsitnik Jul 12, 2018
aff1094
ContainsKey for all generic collections
adamsitnik Jul 12, 2018
6e68408
add benchmarks
adamsitnik Jul 12, 2018
a954576
try add benchmarks
adamsitnik Jul 12, 2018
c9a467b
Enqueue and Push benchmarks
adamsitnik Jul 12, 2018
8317a31
Indexer Set benchmarks
adamsitnik Jul 12, 2018
fb4a0fe
remove benchmarks
adamsitnik Jul 12, 2018
512d24b
clear benchmarks
adamsitnik Jul 12, 2018
eb1344f
refactoring and cleanup + set LangVersion to latest
adamsitnik Jul 13, 2018
6ccfc27
add missing benchmarks
adamsitnik Jul 13, 2018
6bbd707
Merge remote-tracking branch 'upstream/master' into collectionsRewrite
adamsitnik Jul 13, 2018
41aa067
fix a typo
adamsitnik Jul 17, 2018
255f153
add missing ConcurrentBag.TryTake benchmark
adamsitnik Jul 17, 2018
843741c
AddRemoveFromSameThreads benchmarks
adamsitnik Jul 17, 2018
baf6e76
AddRemoveFromDifferentThreads benchmarks
adamsitnik Jul 17, 2018
a99efaf
IsEmpty benchmarks
adamsitnik Jul 17, 2018
e279cfb
Count benchmarks
adamsitnik Jul 17, 2018
90fa210
support new glob filters
adamsitnik Jul 17, 2018
87527d1
add ICollection, IDictionary and IEnumerable benchmarks
adamsitnik Jul 19, 2018
229c5e6
use more future proof constant
adamsitnik Jul 19, 2018
d734b8e
code review fixes
adamsitnik Jul 19, 2018
71d8e8e
NETFRAMEWORK is predefined const!
adamsitnik Jul 19, 2018
fb87ea3
remove the array benchmark
adamsitnik Jul 19, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>7.3</LangVersion>
<LangVersion>latest</LangVersion>
Copy link
Member

@jorive jorive Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! 👍 #Closed

</PropertyGroup>
<ItemGroup>
<Compile Remove="img\**" />
<EmbeddedResource Remove="img\**" />
<None Remove="img\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.14.665" />
<PackageReference Include="BenchmarkDotNet" Version="0.10.14.683" />
Copy link
Member Author

@adamsitnik adamsitnik Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jorive I needed to update BDN to have glob filtering support #Closed

<PackageReference Include="CommandLineParser" Version="2.2.1" />
<PackageReference Include="Jil" Version="2.15.4" />
<PackageReference Include="MessagePack" Version="1.7.3.4" />
Expand Down
3 changes: 3 additions & 0 deletions src/benchmarks/Categories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ public static class Categories
public const string LINQ = "LINQ";
public const string SIMD = "SIMD";
public const string Span = "Span";
public const string Collections = "Collections";
public const string GenericCollections = "GenericCollections";
public const string NonGenericCollections = "NonGenericCollections";
}
}
55 changes: 55 additions & 0 deletions src/benchmarks/corefx/Common/UniqueValuesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Helpers
{
internal static class UniqueValuesGenerator
{
internal static T[] GenerateArray<T>(int count)
{
var random = new Random(12345); // we always use the same seed to have repeatable results!
Copy link
Member

@jorive jorive Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// we always use the same seed to have repeatable results! [](start = 44, length = 58)

👍 #Closed


var uniqueValues = new HashSet<T>();

while (uniqueValues.Count != count)
{
T value = GenerateValue<T>(random);

if (!uniqueValues.Contains(value))
uniqueValues.Add(value);
}

return uniqueValues.ToArray();
}

internal static Dictionary<TKey, TValue> GenerateDictionary<TKey, TValue>(int count)
{
var random = new Random(12345); // we always use the same seed to have repeatable results!
Copy link
Member

@jorive jorive Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12345 [](start = 36, length = 5)

nit: Can we make the seed a const variable used in both methods? #Closed


var dictionary = new Dictionary<TKey, TValue>();

while (dictionary.Count != count)
{
TKey key = GenerateValue<TKey>(random);

if (!dictionary.ContainsKey(key))
dictionary.Add(key, GenerateValue<TValue>(random));
}

return dictionary;
}

private static T GenerateValue<T>(Random random)
{
if (typeof(T) == typeof(int))
return (T)(object)random.Next();
if (typeof(T) == typeof(double))
return (T)(object)random.NextDouble();
if (typeof(T) == typeof(string))
return (T)(object)Guid.NewGuid().ToString(); // I am open to better ideas!

throw new NotImplementedException($"{typeof(T).Name} is not implemented");
}
}
}
142 changes: 142 additions & 0 deletions src/benchmarks/corefx/System.Collections/Add/AddDefaultSize.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using Benchmarks;
using Helpers;

namespace System.Collections
{
[BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)]
[GenericTypeArguments(typeof(int))] // value type
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jorive @ViktorHofer GenericTypeArguments is the way to tell BDN what T is for generic classes with benchmarks

[GenericTypeArguments(typeof(string))] // reference type
public class AddDefaultSize<T>
{
private T[] _uniqueValues;

[Params(Utils.DefaultCollectionSize)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jorive @ViktorHofer Params is the way to parametrize benchmarks per given type, Params can have multiple values like [Params(1, 2, 3)] but we don't have enough time to run all the benchmarks for more test cases so I am using single, same value everywhere

public int Count;

[GlobalSetup]
public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray<T>(Count);

[Benchmark]
public List<T> List()
{
var collection = new List<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i]);
return collection;
}

[Benchmark]
public HashSet<T> HashSet()
{
var collection = new HashSet<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i]);
return collection;
}

[Benchmark]
public Dictionary<T, T> Dictionary()
{
var collection = new Dictionary<T, T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i], uniqueValues[i]);
return collection;
}

[Benchmark]
public SortedList<T, T> SortedList()
{
var collection = new SortedList<T, T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i], uniqueValues[i]);
return collection;
}

[Benchmark]
public SortedSet<T> SortedSet()
{
var collection = new SortedSet<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i]);
return collection;
}

[Benchmark]
public SortedDictionary<T, T> SortedDictionary()
{
var collection = new SortedDictionary<T, T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i], uniqueValues[i]);
return collection;
}

[Benchmark]
public ConcurrentBag<T> ConcurrentBag()
{
var collection = new ConcurrentBag<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i]);
return collection;
}

[Benchmark]
public Queue<T> Queue()
{
var collection = new Queue<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Enqueue(uniqueValues[i]);
return collection;
}

[Benchmark]
public Stack<T> Stack()
{
var collection = new Stack<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Push(uniqueValues[i]);
return collection;
}

[Benchmark]
public ConcurrentQueue<T> ConcurrentQueue()
{
var collection = new ConcurrentQueue<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Enqueue(uniqueValues[i]);
return collection;
}

[Benchmark]
public ConcurrentStack<T> ConcurrentStack()
{
var collection = new ConcurrentStack<T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Push(uniqueValues[i]);
return collection;
}

[Benchmark]
public ConcurrentDictionary<T, T> ConcurrentDictionary()
{
var collection = new ConcurrentDictionary<T, T>();
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.TryAdd(uniqueValues[i], uniqueValues[i]);
return collection;
}
}
}
94 changes: 94 additions & 0 deletions src/benchmarks/corefx/System.Collections/Add/AddGivenSize.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using Benchmarks;
using Helpers;

namespace System.Collections
{
[BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)]
[GenericTypeArguments(typeof(int))] // value type
[GenericTypeArguments(typeof(string))] // reference type
public class AddGivenSize<T>
{
private T[] _uniqueValues;

[Params(Utils.DefaultCollectionSize)]
public int Count;

[GlobalSetup]
public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray<T>(Count);
Copy link
Member

@jorive jorive Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Feels like Count here should be replaced with Utils.DefaultCollectionSize, and Count on the benchmarks with _uniqueValues.Length #ByDesign

Copy link
Member Author

@adamsitnik adamsitnik Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using the value of Param everywhere (not Utils.DefaultCollectionSize) because in the future somebody might like to run this benchmark for more values and then it will require just adding the values to [Param]

[Params(10, 2000, 100000)]
public int Size;

BDN will then run the same benchmark for all provided values (10, 2000, 100000) #Closed


[Benchmark]
public List<T> List()
{
var collection = new List<T>(Count);
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i]);
return collection;
}

#if !NET461 // API added in .NET Core 2.0
[Benchmark]
public HashSet<T> HashSet()
{
var collection = new HashSet<T>(Count);
var uniqueValues = _uniqueValues;
for(int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i]);
return collection;
}
#endif

[Benchmark]
public Dictionary<T, T> Dictionary()
{
var collection = new Dictionary<T, T>(Count);
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i], uniqueValues[i]);
return collection;
}

[Benchmark]
public SortedList<T, T> SortedList()
{
var collection = new SortedList<T, T>(Count);
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Add(uniqueValues[i], uniqueValues[i]);
return collection;
}

[Benchmark]
public Queue<T> Queue()
{
var collection = new Queue<T>(Count);
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Enqueue(uniqueValues[i]);
return collection;
}

[Benchmark]
public Stack<T> Stack()
{
var collection = new Stack<T>(Count);
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.Push(uniqueValues[i]);
return collection;
}

[Benchmark]
public ConcurrentDictionary<T, T> ConcurrentDictionary()
{
var collection = new ConcurrentDictionary<T, T>(Utils.ConcurrencyLevel, Count);
var uniqueValues = _uniqueValues;
for (int i = 0; i < uniqueValues.Length; i++)
collection.TryAdd(uniqueValues[i], uniqueValues[i]);
return collection;
}
}
}
44 changes: 44 additions & 0 deletions src/benchmarks/corefx/System.Collections/Add/TryAddDefaultSize.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Collections.Concurrent;
using BenchmarkDotNet.Attributes;
using Benchmarks;
using Helpers;

namespace System.Collections
{
[BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)]
[GenericTypeArguments(typeof(int))] // value type
[GenericTypeArguments(typeof(string))] // reference type
public class TryAddDefaultSize<T>
{
private T[] _uniqueValues;

[Params(Utils.DefaultCollectionSize)]
public int Count;

[GlobalSetup]
public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray<T>(Count);

#if !NET461 // API added in .NET Core 2.0
[Benchmark]
public Dictionary<T, T> Dictionary()
{
var collection = new Dictionary<T, T>();
var uniqueValues = _uniqueValues;
for(int i = 0; i < uniqueValues.Length; i++)
collection.TryAdd(uniqueValues[i], uniqueValues[i]);
return collection;
}
#endif

[Benchmark]
public ConcurrentDictionary<T, T> ConcurrentDictionary()
{
var collection = new ConcurrentDictionary<T, T>();
var uniqueValues = _uniqueValues;
for(int i = 0; i < uniqueValues.Length; i++)
collection.TryAdd(uniqueValues[i], uniqueValues[i]);
return collection;
}
}
}
Loading