-
Notifications
You must be signed in to change notification settings - Fork 272
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
Changes from 19 commits
13e43b2
85f98c1
34fc804
af04aa7
8fb685d
3321633
cf7fa2f
578c546
cfafed8
1f81328
aff1094
6e68408
a954576
c9a467b
8317a31
fb4a0fe
512d24b
eb1344f
6ccfc27
6bbd707
41aa067
255f153
843741c
baf6e76
a99efaf
e279cfb
90fa210
87527d1
229c5e6
d734b8e
71d8e8e
fb87ea3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,15 +6,15 @@ | |
<DebugType>pdbonly</DebugType> | ||
<DebugSymbols>true</DebugSymbols> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
<LangVersion>7.3</LangVersion> | ||
<LangVersion>latest</LangVersion> | ||
</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" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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" /> | ||
|
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! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
👍 #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! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
nit: Can we make the seed a |
||
|
||
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"); | ||
} | ||
} | ||
} |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jorive @ViktorHofer |
||
[GenericTypeArguments(typeof(string))] // reference type | ||
public class AddDefaultSize<T> | ||
{ | ||
private T[] _uniqueValues; | ||
|
||
[Params(Utils.DefaultCollectionSize)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jorive @ViktorHofer |
||
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; | ||
} | ||
} | ||
} |
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Feels like There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
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; | ||
} | ||
} | ||
} |
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; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call! 👍 #Closed