diff --git a/src/benchmarks/Benchmarks.csproj b/src/benchmarks/Benchmarks.csproj index 69158298199..370f0682281 100644 --- a/src/benchmarks/Benchmarks.csproj +++ b/src/benchmarks/Benchmarks.csproj @@ -6,7 +6,7 @@ pdbonly true true - 7.3 + latest @@ -14,7 +14,7 @@ - + diff --git a/src/benchmarks/Categories.cs b/src/benchmarks/Categories.cs index 61e8d802bd8..d7d2b66e33e 100644 --- a/src/benchmarks/Categories.cs +++ b/src/benchmarks/Categories.cs @@ -10,11 +10,15 @@ public static class Categories public const string Inlining = "Inlining"; public const string V8 = "V8"; public const string Perflab = "Perflab"; + public const string Virtual = "Virtual"; public const string CoreFX = "CoreFX"; 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"; } } \ No newline at end of file diff --git a/src/benchmarks/Program.cs b/src/benchmarks/Program.cs index 7a1f35e7791..1191eb45046 100644 --- a/src/benchmarks/Program.cs +++ b/src/benchmarks/Program.cs @@ -61,12 +61,8 @@ private static IConfig GetConfig(Options options) config = config.With(new AllCategoriesFilter(options.AllCategories.ToArray())); if (options.AnyCategories.Any()) config = config.With(new AnyCategoriesFilter(options.AnyCategories.ToArray())); - if (options.Namespaces.Any()) - config = config.With(new NamespacesFilter(options.Namespaces.ToArray())); - if (options.MethodNames.Any()) - config = config.With(new MethodNamesFilter(options.MethodNames.ToArray())); - if (options.TypeNames.Any()) - config = config.With(new TypeNamesFilter(options.TypeNames.ToArray())); + if (options.Filters.Any()) + config = config.With(new GlobFilter(options.Filters.ToArray())); config = config.With(JsonExporter.Full); // make sure we export to Json (for BenchView integration purpose) @@ -282,14 +278,8 @@ public class Options [Option("anyCategories", Required = false, HelpText = "Any Categories to run")] public IEnumerable AnyCategories { get; set; } - [Option("namespace", Required = false, HelpText = "Namespace(s) to run")] - public IEnumerable Namespaces { get; set; } - - [Option("method", Required = false, HelpText = "Method(s) to run")] - public IEnumerable MethodNames { get; set; } - - [Option("class", Required = false, HelpText = "Class(es) with benchmarks to run")] - public IEnumerable TypeNames { get; set; } + [Option('f', "filters", Required = false, HelpText = "Filter(s) to apply, globs that operate on namespace.typename.methodname")] + public IEnumerable Filters { get; set; } [Option("join", Required = false, Default = false, HelpText = "Prints single table with results for all benchmarks")] public bool Join { get; set; } diff --git a/src/benchmarks/coreclr/Devirtualization/DefaultEqualityComparerPerf.cs b/src/benchmarks/coreclr/Devirtualization/DefaultEqualityComparerPerf.cs index 3fdfcff1f34..77d59d6393d 100644 --- a/src/benchmarks/coreclr/Devirtualization/DefaultEqualityComparerPerf.cs +++ b/src/benchmarks/coreclr/Devirtualization/DefaultEqualityComparerPerf.cs @@ -57,7 +57,7 @@ public bool CompareWrapped(ref T x, ref T y) } } - [BenchmarkCategory(Categories.CoreCLR)] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] public class EqualityComparer { public enum E diff --git a/src/benchmarks/corefx/Common/UniqueValuesGenerator.cs b/src/benchmarks/corefx/Common/UniqueValuesGenerator.cs new file mode 100644 index 00000000000..fcf006a8a47 --- /dev/null +++ b/src/benchmarks/corefx/Common/UniqueValuesGenerator.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Helpers +{ + internal static class UniqueValuesGenerator + { + private const int Seed = 12345; // we always use the same seed to have repeatable results! + + internal static T[] GenerateArray(int count) + { + var random = new Random(Seed); + + var uniqueValues = new HashSet(); + + while (uniqueValues.Count != count) + { + T value = GenerateValue(random); + + if (!uniqueValues.Contains(value)) + uniqueValues.Add(value); + } + + return uniqueValues.ToArray(); + } + + internal static Dictionary GenerateDictionary(int count) + { + var random = new Random(Seed); + + var dictionary = new Dictionary(); + + while (dictionary.Count != count) + { + TKey key = GenerateValue(random); + + if (!dictionary.ContainsKey(key)) + dictionary.Add(key, GenerateValue(random)); + } + + return dictionary; + } + + private static T GenerateValue(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"); + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Add/AddDefaultSize.cs b/src/benchmarks/corefx/System.Collections/Add/AddDefaultSize.cs new file mode 100644 index 00000000000..d2768fe619f --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Add/AddDefaultSize.cs @@ -0,0 +1,169 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +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 AddDefaultSize + { + private T[] _uniqueValues; + + [Params(Utils.DefaultCollectionSize)] + public int Count; + + [GlobalSetup] + public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray(Count); + + [Benchmark] + public List List() + { + var collection = new List(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public ICollection ICollection() => AddToICollection(new List()); + + [MethodImpl(MethodImplOptions.NoInlining)] // we want to prevent from inlining this particular method to make sure that JIT does not find out that ICollection is always List + private ICollection AddToICollection(ICollection collection) + { + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + + [Benchmark] + public HashSet HashSet() + { + var collection = new HashSet(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + + [Benchmark] + public Dictionary Dictionary() + { + var collection = new Dictionary(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public IDictionary IDictionary() => AddToIDictionary(new Dictionary()); + + [MethodImpl(MethodImplOptions.NoInlining)] + private IDictionary AddToIDictionary(IDictionary collection) + { + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + public SortedList SortedList() + { + var collection = new SortedList(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + public SortedSet SortedSet() + { + var collection = new SortedSet(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + + [Benchmark] + public SortedDictionary SortedDictionary() + { + var collection = new SortedDictionary(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + public ConcurrentBag ConcurrentBag() + { + var collection = new ConcurrentBag(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + + [Benchmark] + public Queue Queue() + { + var collection = new Queue(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Enqueue(uniqueValues[i]); + return collection; + } + + [Benchmark] + public Stack Stack() + { + var collection = new Stack(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Push(uniqueValues[i]); + return collection; + } + + [Benchmark] + public ConcurrentQueue ConcurrentQueue() + { + var collection = new ConcurrentQueue(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Enqueue(uniqueValues[i]); + return collection; + } + + [Benchmark] + public ConcurrentStack ConcurrentStack() + { + var collection = new ConcurrentStack(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Push(uniqueValues[i]); + return collection; + } + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() + { + var collection = new ConcurrentDictionary(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Add/AddGivenSize.cs b/src/benchmarks/corefx/System.Collections/Add/AddGivenSize.cs new file mode 100644 index 00000000000..c9dad67f028 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Add/AddGivenSize.cs @@ -0,0 +1,121 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +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 + { + private T[] _uniqueValues; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray(Size); + + [Benchmark] + public List List() + { + var collection = new List(Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public ICollection ICollection() => AddToICollection(new List(Size)); + + [MethodImpl(MethodImplOptions.NoInlining)] + private ICollection AddToICollection(ICollection collection) + { + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } + +#if !NETFRAMEWORK // API added in .NET Core 2.0 + [Benchmark] + public HashSet HashSet() + { + var collection = new HashSet(Size); + var uniqueValues = _uniqueValues; + for(int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i]); + return collection; + } +#endif + + [Benchmark] + public Dictionary Dictionary() + { + var collection = new Dictionary(Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public IDictionary IDictionary() => AddToIDictionary(new Dictionary(Size)); + + [MethodImpl(MethodImplOptions.NoInlining)] + private IDictionary AddToIDictionary(IDictionary collection) + { + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + public SortedList SortedList() + { + var collection = new SortedList(Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } + + [Benchmark] + public Queue Queue() + { + var collection = new Queue(Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Enqueue(uniqueValues[i]); + return collection; + } + + [Benchmark] + public Stack Stack() + { + var collection = new Stack(Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Push(uniqueValues[i]); + return collection; + } + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() + { + var collection = new ConcurrentDictionary(Utils.ConcurrencyLevel, Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Add/TryAddDefaultSize.cs b/src/benchmarks/corefx/System.Collections/Add/TryAddDefaultSize.cs new file mode 100644 index 00000000000..5dafd160e6d --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Add/TryAddDefaultSize.cs @@ -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 + { + private T[] _uniqueValues; + + [Params(Utils.DefaultCollectionSize)] + public int Count; + + [GlobalSetup] + public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray(Count); + +#if !NETFRAMEWORK // API added in .NET Core 2.0 + [Benchmark] + public Dictionary Dictionary() + { + var collection = new Dictionary(); + var uniqueValues = _uniqueValues; + for(int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } +#endif + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() + { + var collection = new ConcurrentDictionary(); + var uniqueValues = _uniqueValues; + for(int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Add/TryAddGivenSize.cs b/src/benchmarks/corefx/System.Collections/Add/TryAddGivenSize.cs new file mode 100644 index 00000000000..8ecdae098e0 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Add/TryAddGivenSize.cs @@ -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 TryAddGiventSize + { + private T[] _uniqueValues; + + [Params(Utils.DefaultCollectionSize)] + public int Count; + + [GlobalSetup] + public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray(Count); + +#if !NETFRAMEWORK // API added in .NET Core 2.0 + [Benchmark] + public Dictionary Dictionary() + { + var collection = new Dictionary(Count); + var uniqueValues = _uniqueValues; + for(int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } +#endif + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() + { + var collection = new ConcurrentDictionary(Utils.ConcurrencyLevel, Count); + var uniqueValues = _uniqueValues; + for(int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Concurrent/AddRemoveFromDifferentThreads.cs b/src/benchmarks/corefx/System.Collections/Concurrent/AddRemoveFromDifferentThreads.cs new file mode 100644 index 00000000000..a670f8d653c --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Concurrent/AddRemoveFromDifferentThreads.cs @@ -0,0 +1,151 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Benchmarks; + +namespace System.Collections.Concurrent +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + [MinWarmupCount(6, forceAutoWarmup: true)] + [MaxWarmupCount(10, forceAutoWarmup: true)] + public class AddRemoveFromDifferentThreads + { + const int NumThreads = 2; + + [Params(2_000_000)] + public int Size; + + private Barrier _barrier; + private Task _producer, _consumer; + + [IterationCleanup] + public void IterationCleanup() => _barrier.Dispose(); + + [IterationSetup(Target = nameof(ConcurrentBag))] + public void SetupConcurrentBagIteration() + { + var bag = new ConcurrentBag(); + + _barrier = new Barrier(NumThreads + 1); + + _producer = Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + _barrier.SignalAndWait(); + + for (int i = 0; i < Size; i++) + { + bag.Add(default); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + _consumer = Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + _barrier.SignalAndWait(); + + int count = 0; + while (count < Size) + { + if (bag.TryTake(out T _)) + { + count++; + } + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + _barrier.SignalAndWait(); + } + + [Benchmark] + public void ConcurrentBag() => SignalAndWaitForAllTasks(); + + [IterationSetup(Target = nameof(ConcurrentStack))] + public void SetupConcurrentStackIteration() + { + var stack = new ConcurrentStack(); + + _barrier = new Barrier(NumThreads + 1); + + _producer = Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + _barrier.SignalAndWait(); + + for (int i = 0; i < Size; i++) + { + stack.Push(default); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + _consumer = Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + _barrier.SignalAndWait(); + + int count = 0; + while (count < Size) + { + if (stack.TryPop(out T _)) + { + count++; + } + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + _barrier.SignalAndWait(); + } + + [Benchmark] + public void ConcurrentStack() => SignalAndWaitForAllTasks(); + + [IterationSetup(Target = nameof(ConcurrentQueue))] + public void SetupConcurrentQueueIteration() + { + var queue = new ConcurrentQueue(); + + _barrier = new Barrier(NumThreads + 1); + + _producer = Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + _barrier.SignalAndWait(); + + for (int i = 0; i < Size; i++) + { + queue.Enqueue(default); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + _consumer = Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + _barrier.SignalAndWait(); + + int count = 0; + while (count < Size) + { + if (queue.TryDequeue(out T _)) + { + count++; + } + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + _barrier.SignalAndWait(); + } + + [Benchmark] + public void ConcurrentQueue() => SignalAndWaitForAllTasks(); + + private void SignalAndWaitForAllTasks() + { + _barrier.SignalAndWait(); + + Task.WaitAll(_producer, _consumer); + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Concurrent/AddRemoveFromSameThreads.cs b/src/benchmarks/corefx/System.Collections/Concurrent/AddRemoveFromSameThreads.cs new file mode 100644 index 00000000000..a01562ba48d --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Concurrent/AddRemoveFromSameThreads.cs @@ -0,0 +1,106 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Benchmarks; + +namespace System.Collections.Concurrent +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + [MinWarmupCount(6, forceAutoWarmup: true)] + [MaxWarmupCount(10, forceAutoWarmup: true)] + public class AddRemoveFromSameThreads + { + const int NumThreads = 2; + + [Params(2_000_000)] + public int Size; + + private Barrier _barrier; + private Task[] _tasks; + + [IterationCleanup] + public void IterationCleanup() => _barrier.Dispose(); + + [IterationSetup(Target = nameof(ConcurrentBag))] + public void SetupConcurrentBagIteration() + { + var bag = new ConcurrentBag(); + + _barrier = new Barrier(NumThreads + 1); + _tasks = Enumerable.Range(0, NumThreads) + .Select(_ => + Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + + for (int i = 0; i < Size; i++) + { + bag.Add(default); + bag.TryTake(out T _); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)) + .ToArray(); + } + + [Benchmark] + public void ConcurrentBag() => SignalAndWaitForAllTasks(); + + [IterationSetup(Target = nameof(ConcurrentStack))] + public void SetupConcurrentStackIteration() + { + var stack = new ConcurrentStack(); + + _barrier = new Barrier(NumThreads + 1); + _tasks = Enumerable.Range(0, NumThreads) + .Select(_ => + Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + + for (int i = 0; i < Size; i++) + { + stack.Push(default); + stack.TryPop(out T _); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)) + .ToArray(); + } + + [Benchmark] + public void ConcurrentStack() => SignalAndWaitForAllTasks(); + + [IterationSetup(Target = nameof(ConcurrentQueue))] + public void SetupConcurrentQueueIteration() + { + var queue = new ConcurrentQueue(); + + _barrier = new Barrier(NumThreads + 1); + _tasks = Enumerable.Range(0, NumThreads) + .Select(_ => + Task.Factory.StartNew(() => + { + _barrier.SignalAndWait(); + + for (int i = 0; i < Size; i++) + { + queue.Enqueue(default); + queue.TryDequeue(out T _); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)) + .ToArray(); + } + + [Benchmark] + public void ConcurrentQueue() => SignalAndWaitForAllTasks(); + + private void SignalAndWaitForAllTasks() + { + _barrier.SignalAndWait(); + + Task.WaitAll(_tasks); + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Concurrent/Count.cs b/src/benchmarks/corefx/System.Collections/Concurrent/Count.cs new file mode 100644 index 00000000000..e45c9ca3a61 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Concurrent/Count.cs @@ -0,0 +1,44 @@ +using System.Linq; +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections.Concurrent +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + public class Count + { + private ConcurrentDictionary _dictionary; + private ConcurrentQueue _queue; + private ConcurrentStack _stack; + private ConcurrentBag _bag; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + var values = UniqueValuesGenerator.GenerateArray(Size); + + _dictionary = new ConcurrentDictionary(values.ToDictionary(v => v, v => v)); + _queue = new ConcurrentQueue(values); + _stack = new ConcurrentStack(values); + _bag = new ConcurrentBag(values); + } + + [Benchmark] + public int Dictionary() => _dictionary.Count; + + [Benchmark] + public int Queue() => _queue.Count; + + [Benchmark] + public int Stack() => _stack.Count; + + [Benchmark] + public int Bag() => _bag.Count; + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Concurrent/IsEmpty.cs b/src/benchmarks/corefx/System.Collections/Concurrent/IsEmpty.cs new file mode 100644 index 00000000000..dc202819fe1 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Concurrent/IsEmpty.cs @@ -0,0 +1,44 @@ +using System.Linq; +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections.Concurrent +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + public class IsEmpty + { + private ConcurrentDictionary _dictionary; + private ConcurrentQueue _queue; + private ConcurrentStack _stack; + private ConcurrentBag _bag; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + var values = UniqueValuesGenerator.GenerateArray(Size); + + _dictionary = new ConcurrentDictionary(values.ToDictionary(v => v, v => v)); + _queue = new ConcurrentQueue(values); + _stack = new ConcurrentStack(values); + _bag = new ConcurrentBag(values); + } + + [Benchmark] + public bool Dictionary() => _dictionary.IsEmpty; + + [Benchmark] + public bool Queue() => _queue.IsEmpty; + + [Benchmark] + public bool Stack() => _stack.IsEmpty; + + [Benchmark] + public bool Bag() => _bag.IsEmpty; + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Contains/ContainsFalse.cs b/src/benchmarks/corefx/System.Collections/Contains/ContainsFalse.cs new file mode 100644 index 00000000000..7e78798d9a1 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Contains/ContainsFalse.cs @@ -0,0 +1,188 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +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 ContainsFalse + { + private T[] _notFound; + + private T[] _array; + private List _list; + private LinkedList _linkedList; + private HashSet _hashSet; + private Queue _queue; + private Stack _stack; + private SortedSet _sortedSet; + private ImmutableArray _immutableArray; + private ImmutableHashSet _immutableHashSet; + private ImmutableList _immutableList; + private ImmutableSortedSet _immutableSortedSet; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + var values = UniqueValuesGenerator.GenerateArray(Size * 2); + _notFound = values.Take(Size).ToArray(); + var secondHalf = values.Skip(Size).Take(Size).ToArray(); + + _array = secondHalf; + _list = new List(secondHalf); + _linkedList = new LinkedList(secondHalf); + _hashSet = new HashSet(secondHalf); + _queue = new Queue(secondHalf); + _stack = new Stack(secondHalf); + _sortedSet = new SortedSet(secondHalf); + _immutableArray = Immutable.ImmutableArray.CreateRange(secondHalf); + _immutableHashSet = Immutable.ImmutableHashSet.CreateRange(secondHalf); + _immutableList = Immutable.ImmutableList.CreateRange(secondHalf); + _immutableSortedSet = Immutable.ImmutableSortedSet.CreateRange(secondHalf); + } + + [Benchmark] + public bool Array() + { + bool result = default; + var collection = _array; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool List() + { + bool result = default; + var collection = _list; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public bool ICollection() => Contains(_list); + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool Contains(ICollection collection) + { + bool result = default; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool LinkedList() + { + bool result = default; + var collection = _linkedList; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool HashSet() + { + bool result = default; + var collection = _hashSet; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool Queue() + { + bool result = default; + var collection = _queue; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool Stack() + { + bool result = default; + var collection = _stack; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool SortedSet() + { + bool result = default; + var collection = _sortedSet; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool ImmutableArray() + { + bool result = default; + var collection = _immutableArray; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool ImmutableHashSet() + { + bool result = default; + var collection = _immutableHashSet; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool ImmutableList() + { + bool result = default; + var collection = _immutableList; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + + [Benchmark] + public bool ImmutableSortedSet() + { + bool result = default; + var collection = _immutableSortedSet; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.Contains(notFound[i]); + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Contains/ContainsKeyFalse.cs b/src/benchmarks/corefx/System.Collections/Contains/ContainsKeyFalse.cs new file mode 100644 index 00000000000..c7bff8d14e9 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Contains/ContainsKeyFalse.cs @@ -0,0 +1,125 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int), typeof(int))] // value type + [GenericTypeArguments(typeof(string), typeof(string))] // reference type + public class ContainsKeyFalse + { + private TKey[] _notFound; + private Dictionary _source; + + private Dictionary _dictionary; + private SortedList _sortedList; + private SortedDictionary _sortedDictionary; + private ConcurrentDictionary _concurrentDictionary; + private ImmutableDictionary _immutableDictionary; + private ImmutableSortedDictionary _immutableSortedDictionary; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + var values = UniqueValuesGenerator.GenerateArray(Size * 2); + _notFound = values.Take(Size).ToArray(); + + _source = values.Skip(Size).Take(Size).ToDictionary(item => item, item => (TValue)(object)item); + _dictionary = new Dictionary(_source); + _sortedList = new SortedList(_source); + _sortedDictionary = new SortedDictionary(_source); + _concurrentDictionary = new ConcurrentDictionary(_source); + _immutableDictionary = Immutable.ImmutableDictionary.CreateRange(_source); + _immutableSortedDictionary = Immutable.ImmutableSortedDictionary.CreateRange(_source); + } + + [Benchmark] + public bool Dictionary() + { + bool result = default; + var collection = _dictionary; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public bool IDictionary() => ContainsKey(_dictionary); + + [MethodImpl(MethodImplOptions.NoInlining)] + public bool ContainsKey(IDictionary collection) + { + bool result = default; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + + [Benchmark] + public bool SortedList() + { + bool result = default; + var collection = _sortedList; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + + [Benchmark] + public bool SortedDictionary() + { + bool result = default; + var collection = _sortedDictionary; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + + [Benchmark] + public bool ConcurrentDictionary() + { + bool result = default; + var collection = _concurrentDictionary; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + + [Benchmark] + public bool ImmutableDictionary() + { + bool result = default; + var collection = _immutableDictionary; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + + [Benchmark] + public bool ImmutableSortedDictionary() + { + bool result = default; + var collection = _immutableSortedDictionary; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Contains/ContainsKeyTrue.cs b/src/benchmarks/corefx/System.Collections/Contains/ContainsKeyTrue.cs new file mode 100644 index 00000000000..6f580767c00 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Contains/ContainsKeyTrue.cs @@ -0,0 +1,123 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int), typeof(int))] // value type + [GenericTypeArguments(typeof(string), typeof(string))] // reference type + public class ContainsKeyTrue + { + private TKey[] _found; + private Dictionary _source; + + private Dictionary _dictionary; + private SortedList _sortedList; + private SortedDictionary _sortedDictionary; + private ConcurrentDictionary _concurrentDictionary; + private ImmutableDictionary _immutableDictionary; + private ImmutableSortedDictionary _immutableSortedDictionary; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + _found = UniqueValuesGenerator.GenerateArray(Size); + _source = _found.ToDictionary(item => item, item => (TValue)(object)item); + _dictionary = new Dictionary(_source); + _sortedList = new SortedList(_source); + _sortedDictionary = new SortedDictionary(_source); + _concurrentDictionary = new ConcurrentDictionary(_source); + _immutableDictionary = Immutable.ImmutableDictionary.CreateRange(_source); + _immutableSortedDictionary = Immutable.ImmutableSortedDictionary.CreateRange(_source); + } + + [Benchmark] + public bool Dictionary() + { + bool result = default; + var collection = _dictionary; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public bool IDictionary() => ContainsKey(_dictionary); + + [MethodImpl(MethodImplOptions.NoInlining)] + public bool ContainsKey(IDictionary collection) + { + bool result = default; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + + [Benchmark] + public bool SortedList() + { + bool result = default; + var collection = _sortedList; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + + [Benchmark] + public bool SortedDictionary() + { + bool result = default; + var collection = _sortedDictionary; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + + [Benchmark] + public bool ConcurrentDictionary() + { + bool result = default; + var collection = _concurrentDictionary; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + + [Benchmark] + public bool ImmutableDictionary() + { + bool result = default; + var collection = _immutableDictionary; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + + [Benchmark] + public bool ImmutableSortedDictionary() + { + bool result = default; + var collection = _immutableSortedDictionary; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Contains/ContainsTrue.cs b/src/benchmarks/corefx/System.Collections/Contains/ContainsTrue.cs new file mode 100644 index 00000000000..53bd8dd1f21 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Contains/ContainsTrue.cs @@ -0,0 +1,185 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +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 ContainsTrue + { + private T[] _found; + + private T[] _array; + private List _list; + private LinkedList _linkedList; + private HashSet _hashSet; + private Queue _queue; + private Stack _stack; + private SortedSet _sortedSet; + private ImmutableArray _immutableArray; + private ImmutableHashSet _immutableHashSet; + private ImmutableList _immutableList; + private ImmutableSortedSet _immutableSortedSet; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + _found = UniqueValuesGenerator.GenerateArray(Size); + _array = _found.ToArray(); + _list = new List(_found); + _linkedList = new LinkedList(_found); + _hashSet = new HashSet(_found); + _queue = new Queue(_found); + _stack = new Stack(_found); + _sortedSet = new SortedSet(_found); + _immutableArray = Immutable.ImmutableArray.CreateRange(_found); + _immutableHashSet = Immutable.ImmutableHashSet.CreateRange(_found); + _immutableList = Immutable.ImmutableList.CreateRange(_found); + _immutableSortedSet = Immutable.ImmutableSortedSet.CreateRange(_found); + } + + [Benchmark] + public bool Array() + { + bool result = default; + var collection = _array; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool List() + { + bool result = default; + var collection = _list; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public bool ICollection() => Contains(_list); + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool Contains(ICollection collection) + { + bool result = default; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool LinkedList() + { + bool result = default; + var collection = _linkedList; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool HashSet() + { + bool result = default; + var collection = _hashSet; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool Queue() + { + bool result = default; + var collection = _queue; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool Stack() + { + bool result = default; + var collection = _stack; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool SortedSet() + { + bool result = default; + var collection = _sortedSet; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool ImmutableArray() + { + bool result = default; + var collection = _immutableArray; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool ImmutableHashSet() + { + bool result = default; + var collection = _immutableHashSet; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool ImmutableList() + { + bool result = default; + var collection = _immutableList; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + + [Benchmark] + public bool ImmutableSortedSet() + { + bool result = default; + var collection = _immutableSortedSet; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.Contains(found[i]); + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Create/CtorDefaultSize.cs b/src/benchmarks/corefx/System.Collections/Create/CtorDefaultSize.cs new file mode 100644 index 00000000000..f5b60870a8c --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Create/CtorDefaultSize.cs @@ -0,0 +1,77 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using BenchmarkDotNet.Attributes; +using Benchmarks; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + public class CtorDefaultSize + { + [Benchmark] + public List List() => new List(); + + [Benchmark] + public LinkedList LinkedList() => new LinkedList(); + + [Benchmark] + public HashSet HashSet() => new HashSet(); + + [Benchmark] + public Dictionary Dictionary() => new Dictionary(); + + [Benchmark] + public Queue Queue() => new Queue(); + + [Benchmark] + public Stack Stack() => new Stack(); + + [Benchmark] + public SortedList SortedList() => new SortedList(); + + [Benchmark] + public SortedSet SortedSet() => new SortedSet(); + + [Benchmark] + public SortedDictionary SortedDictionary() => new SortedDictionary(); + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() => new ConcurrentDictionary(); + + [Benchmark] + public ConcurrentQueue ConcurrentQueue() => new ConcurrentQueue(); + + [Benchmark] + public ConcurrentStack ConcurrentStack() => new ConcurrentStack(); + + [Benchmark] + public ConcurrentBag ConcurrentBag() => new ConcurrentBag(); + + [Benchmark] + public ImmutableArray ImmutableArray() => Immutable.ImmutableArray.Create(); + + [Benchmark] + public ImmutableDictionary ImmutableDictionary() => Immutable.ImmutableDictionary.Create(); + + [Benchmark] + public ImmutableHashSet ImmutableHashSet() => Immutable.ImmutableHashSet.Create(); + + [Benchmark] + public ImmutableList ImmutableList() => Immutable.ImmutableList.Create(); + + [Benchmark] + public ImmutableQueue ImmutableQueue() => Immutable.ImmutableQueue.Create(); + + [Benchmark] + public ImmutableStack ImmutableStack() => Immutable.ImmutableStack.Create(); + + [Benchmark] + public ImmutableSortedDictionary ImmutableSortedDictionary() => Immutable.ImmutableSortedDictionary.Create(); + + [Benchmark] + public ImmutableSortedSet ImmutableSortedSet() => Immutable.ImmutableSortedSet.Create(); + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Create/CtorDefaultSizeNonGeneric.cs b/src/benchmarks/corefx/System.Collections/Create/CtorDefaultSizeNonGeneric.cs new file mode 100644 index 00000000000..2d01d66c25e --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Create/CtorDefaultSizeNonGeneric.cs @@ -0,0 +1,24 @@ +using BenchmarkDotNet.Attributes; +using Benchmarks; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.NonGenericCollections)] + public class CtorDefaultSizeNonGeneric + { + [Benchmark] + public ArrayList ArrayList() => new ArrayList(); + + [Benchmark] + public Hashtable Hashtable() => new Hashtable(); + + [Benchmark] + public Queue Queue() => new Queue(); + + [Benchmark] + public Stack Stack() => new Stack(); + + [Benchmark] + public SortedList SortedList() => new SortedList(); + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Create/CtorFromCollection.cs b/src/benchmarks/corefx/System.Collections/Create/CtorFromCollection.cs new file mode 100644 index 00000000000..ffd56570ccd --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Create/CtorFromCollection.cs @@ -0,0 +1,91 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +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 CtorFromCollection + { + private ICollection _collection; + private IDictionary _dictionary; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + _collection = UniqueValuesGenerator.GenerateArray(Size); + _dictionary = UniqueValuesGenerator.GenerateDictionary(Size); + } + + [Benchmark] + public List List() => new List(_collection); + + [Benchmark] + public LinkedList LinkedList() => new LinkedList(_collection); + + [Benchmark] + public HashSet HashSet() => new HashSet(_collection); + + [Benchmark] + public Dictionary Dictionary() => new Dictionary(_dictionary); + + [Benchmark] + public Queue Queue() => new Queue(_collection); + + [Benchmark] + public Stack Stack() => new Stack(_collection); + + [Benchmark] + public SortedList SortedList() => new SortedList(_dictionary); + + [Benchmark] + public SortedSet SortedSet() => new SortedSet(_collection); + + [Benchmark] + public SortedDictionary SortedDictionary() => new SortedDictionary(_dictionary); + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() => new ConcurrentDictionary(_dictionary); + + [Benchmark] + public ConcurrentQueue ConcurrentQueue() => new ConcurrentQueue(_collection); + + [Benchmark] + public ConcurrentStack ConcurrentStack() => new ConcurrentStack(_collection); + + [Benchmark] + public ConcurrentBag ConcurrentBag() => new ConcurrentBag(_collection); + + [Benchmark] + public ImmutableArray ImmutableArray() => Immutable.ImmutableArray.CreateRange(_collection); + + [Benchmark] + public ImmutableDictionary ImmutableDictionary() => Immutable.ImmutableDictionary.CreateRange(_dictionary); + + [Benchmark] + public ImmutableHashSet ImmutableHashSet() => Immutable.ImmutableHashSet.CreateRange(_collection); + + [Benchmark] + public ImmutableList ImmutableList() => Immutable.ImmutableList.CreateRange(_collection); + + [Benchmark] + public ImmutableQueue ImmutableQueue() => Immutable.ImmutableQueue.CreateRange(_collection); + + [Benchmark] + public ImmutableStack ImmutableStack() => Immutable.ImmutableStack.CreateRange(_collection); + + [Benchmark] + public ImmutableSortedDictionary ImmutableSortedDictionary() => Immutable.ImmutableSortedDictionary.CreateRange(_dictionary); + + [Benchmark] + public ImmutableSortedSet ImmutableSortedSet() => Immutable.ImmutableSortedSet.CreateRange(_collection); + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Create/CtorFromCollectionNonGeneric.cs b/src/benchmarks/corefx/System.Collections/Create/CtorFromCollectionNonGeneric.cs new file mode 100644 index 00000000000..c55fd788245 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Create/CtorFromCollectionNonGeneric.cs @@ -0,0 +1,40 @@ +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.NonGenericCollections)] + [GenericTypeArguments(typeof(int))] // value type (it shows how bad idea is to use non-generic collections for value types) + [GenericTypeArguments(typeof(string))] // reference type + public class CtorFromCollectionNonGeneric + { + private ICollection _collection; + private IDictionary _dictionary; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [GlobalSetup] + public void Setup() + { + _collection = UniqueValuesGenerator.GenerateArray(Size); + _dictionary = UniqueValuesGenerator.GenerateDictionary(Size); + } + + [Benchmark] + public ArrayList ArrayList() => new ArrayList(_collection); + + [Benchmark] + public Hashtable Hashtable() => new Hashtable(_dictionary); + + [Benchmark] + public Queue Queue() => new Queue(_collection); + + [Benchmark] + public Stack Stack() => new Stack(_collection); + + [Benchmark] + public SortedList SortedList() => new SortedList(_dictionary); + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Create/CtorGivenSize.cs b/src/benchmarks/corefx/System.Collections/Create/CtorGivenSize.cs new file mode 100644 index 00000000000..311b388df62 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Create/CtorGivenSize.cs @@ -0,0 +1,41 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using Benchmarks; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + public class CtorGivenSize + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [Benchmark] + public T[] Array() => new T[Size]; + + [Benchmark] + public List List() => new List(Size); + +#if !NETFRAMEWORK // API added in .NET Core 2.0 + [Benchmark] + public HashSet HashSet() => new HashSet(Size); +#endif + [Benchmark] + public Dictionary Dictionary() => new Dictionary(Size); + + [Benchmark] + public Queue Queue() => new Queue(Size); + + [Benchmark] + public Stack Stack() => new Stack(Size); + + [Benchmark] + public SortedList SortedList() => new SortedList(Size); + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() => new ConcurrentDictionary(Utils.ConcurrencyLevel, Size); + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Create/CtorGivenSizeNonGeneric.cs b/src/benchmarks/corefx/System.Collections/Create/CtorGivenSizeNonGeneric.cs new file mode 100644 index 00000000000..98fa0b6734b --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Create/CtorGivenSizeNonGeneric.cs @@ -0,0 +1,27 @@ +using BenchmarkDotNet.Attributes; +using Benchmarks; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.NonGenericCollections)] + public class CtorGivenSizeNonGeneric + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + [Benchmark] + public ArrayList ArrayList() => new ArrayList(Size); + + [Benchmark] + public Hashtable Hashtable() => new Hashtable(Size); + + [Benchmark] + public Queue Queue() => new Queue(Size); + + [Benchmark] + public Stack Stack() => new Stack(Size); + + [Benchmark] + public SortedList SortedList() => new SortedList(Size); + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Indexer/IndexerSet.cs b/src/benchmarks/corefx/System.Collections/Indexer/IndexerSet.cs new file mode 100644 index 00000000000..2734a20f949 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Indexer/IndexerSet.cs @@ -0,0 +1,110 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +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 IndexerSet + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private T[] _keys; + + private T[] _array; + private List _list; + private Dictionary _dictionary; + private SortedList _sortedList; + private SortedDictionary _sortedDictionary; + private ConcurrentDictionary _concurrentDictionary; + + [GlobalSetup] + public void Setup() + { + _keys = UniqueValuesGenerator.GenerateArray(Size); + + _array = _keys.ToArray(); + _list = new List(_keys); + _dictionary = new Dictionary(_keys.ToDictionary(i => i, i => i)); + _sortedList = new SortedList(_keys.ToDictionary(i => i, i => i)); + _sortedDictionary = new SortedDictionary(_keys.ToDictionary(i => i, i => i)); + _concurrentDictionary = new ConcurrentDictionary(_keys.ToDictionary(i => i, i => i)); + } + + [Benchmark] + public T[] Array() + { + var array = _array; + for (int i = 0; i < array.Length; i++) + array[i] = default; + return array; + } + + [Benchmark] + public List List() + { + var list = _list; + for (int i = 0; i < list.Count; i++) + list[i] = default; + return list; + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public IList IList() => Set(_list); + + [MethodImpl(MethodImplOptions.NoInlining)] + private IList Set(IList collection) + { + for (int i = 0; i < collection.Count; i++) + collection[i] = default; + return collection; + } + + [Benchmark] + public Dictionary Dictionary() + { + var dictionary = _dictionary; + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + dictionary[keys[i]] = default; + return dictionary; + } + [Benchmark] + public SortedList SortedList() + { + var sortedList = _sortedList; + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + sortedList[keys[i]] = default; + return sortedList; + } + + [Benchmark] + public SortedDictionary SortedDictionary() + { + var dictionary = _sortedDictionary; + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + dictionary[keys[i]] = default; + return dictionary; + } + + [Benchmark] + public ConcurrentDictionary ConcurrentDictionary() + { + var dictionary = _concurrentDictionary; + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + dictionary[keys[i]] = default; + return dictionary; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Iterate/IterateFor.cs b/src/benchmarks/corefx/System.Collections/Iterate/IterateFor.cs new file mode 100644 index 00000000000..1ff343caa4b --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Iterate/IterateFor.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +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 IterateFor + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private T[] _array; + private List _list; + private IList _ilist; + private ImmutableArray _immutablearray; + private ImmutableList _immutablelist; + private ImmutableSortedSet _immutablesortedset; + + [GlobalSetup(Target = nameof(Array))] + public void SetupArray() => _array = UniqueValuesGenerator.GenerateArray(Size); + + [Benchmark] + public T Array() + { + T result = default; + var collection = _array; + for (int i = 0; i < collection.Length; i++) + result = collection[i]; + return result; + } + + [GlobalSetup(Target = nameof(List))] + public void SetupList() => _list = new List(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T List() + { + T result = default; + var collection = _list; + for(int i = 0; i < collection.Count; i++) + result = collection[i]; + return result;; + } + + [GlobalSetup(Target = nameof(IList))] + public void SetupIList() => _ilist = new List(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public T IList() => Get(_ilist); + + [MethodImpl(MethodImplOptions.NoInlining)] + private T Get(IList collection) + { + T result = default; + for (int i = 0; i < collection.Count; i++) + result = collection[i]; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableArray))] + public void SetupImmutableArray() => _immutablearray = Immutable.ImmutableArray.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableArray() + { + T result = default; + var collection = _immutablearray; + for(int i = 0; i < collection.Length; i++) + result = collection[i]; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableList))] + public void SetupImmutableList() => _immutablelist = Immutable.ImmutableList.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableList() + { + T result = default; + var collection = _immutablelist; + for(int i = 0; i < collection.Count; i++) + result = collection[i]; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableSortedSet))] + public void SetupImmutableSortedSet() => _immutablesortedset = Immutable.ImmutableSortedSet.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableSortedSet() + { + T result = default; + var collection = _immutablesortedset; + for(int i = 0; i < collection.Count; i++) + result = collection[i]; + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Iterate/IterateForEach.cs b/src/benchmarks/corefx/System.Collections/Iterate/IterateForEach.cs new file mode 100644 index 00000000000..818bf1e6d8b --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Iterate/IterateForEach.cs @@ -0,0 +1,345 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +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 IterateForEach + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private T[] _array; + private IEnumerable _ienumerable; + private List _list; + private LinkedList _linkedlist; + private HashSet _hashset; + private Dictionary _dictionary; + private Queue _queue; + private Stack _stack; + private SortedList _sortedlist; + private SortedSet _sortedset; + private SortedDictionary _sorteddictionary; + private ConcurrentDictionary _concurrentdictionary; + private ConcurrentQueue _concurrentqueue; + private ConcurrentStack _concurrentstack; + private ConcurrentBag _concurrentbag; + private ImmutableArray _immutablearray; + private ImmutableDictionary _immutabledictionary; + private ImmutableHashSet _immutablehashset; + private ImmutableList _immutablelist; + private ImmutableQueue _immutablequeue; + private ImmutableStack _immutablestack; + private ImmutableSortedDictionary _immutablesorteddictionary; + private ImmutableSortedSet _immutablesortedset; + + [GlobalSetup(Target = nameof(Array))] + public void SetupArray() => _array = UniqueValuesGenerator.GenerateArray(Size); + + [Benchmark] + public T Array() + { + T result = default; + var collection = _array; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(IEnumerable))] + public void SetupIEnumerable() => _ienumerable = UniqueValuesGenerator.GenerateArray(Size); + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public T IEnumerable() => Get(_ienumerable); + + [MethodImpl(MethodImplOptions.NoInlining)] + private T Get(IEnumerable collection) + { + T result = default; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(List))] + public void SetupList() => _list = new List(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T List() + { + T result = default; + var collection = _list; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(LinkedList))] + public void SetupLinkedList() => _linkedlist = new LinkedList(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T LinkedList() + { + T result = default; + var collection = _linkedlist; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(HashSet))] + public void SetupHashSet() => _hashset = new HashSet(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T HashSet() + { + T result = default; + var collection = _hashset; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(Dictionary))] + public void SetupDictionary() => _dictionary = new Dictionary(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public T Dictionary() + { + T result = default; + var collection = _dictionary; + foreach (var item in collection) + result = item.Value; + return result; + } + + [GlobalSetup(Target = nameof(Queue))] + public void SetupQueue() => _queue = new Queue(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T Queue() + { + T result = default; + var collection = _queue; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(Stack))] + public void SetupStack() => _stack = new Stack(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T Stack() + { + T result = default; + var collection = _stack; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(SortedList))] + public void SetupSortedList() => _sortedlist = new SortedList(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public T SortedList() + { + T result = default; + var collection = _sortedlist; + foreach (var item in collection) + result = item.Value; + return result; + } + + [GlobalSetup(Target = nameof(SortedSet))] + public void SetupSortedSet() => _sortedset = new SortedSet(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T SortedSet() + { + T result = default; + var collection = _sortedset; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(SortedDictionary))] + public void SetupSortedDictionary() => _sorteddictionary = new SortedDictionary(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public T SortedDictionary() + { + T result = default; + var collection = _sorteddictionary; + foreach (var item in collection) + result = item.Value; + return result; + } + + [GlobalSetup(Target = nameof(ConcurrentDictionary))] + public void SetupConcurrentDictionary() => _concurrentdictionary = new ConcurrentDictionary(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public T ConcurrentDictionary() + { + T result = default; + var collection = _concurrentdictionary; + foreach (var item in collection) + result = item.Value; + return result; + } + + [GlobalSetup(Target = nameof(ConcurrentQueue))] + public void SetupConcurrentQueue() => _concurrentqueue = new ConcurrentQueue(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ConcurrentQueue() + { + T result = default; + var collection = _concurrentqueue; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ConcurrentStack))] + public void SetupConcurrentStack() => _concurrentstack = new ConcurrentStack(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ConcurrentStack() + { + T result = default; + var collection = _concurrentstack; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ConcurrentBag))] + public void SetupConcurrentBag() => _concurrentbag = new ConcurrentBag(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ConcurrentBag() + { + T result = default; + var collection = _concurrentbag; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableArray))] + public void SetupImmutableArray() => _immutablearray = Immutable.ImmutableArray.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableArray() + { + T result = default; + var collection = _immutablearray; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableDictionary))] + public void SetupImmutableDictionary() => _immutabledictionary = Immutable.ImmutableDictionary.CreateRange(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public T ImmutableDictionary() + { + T result = default; + var collection = _immutabledictionary; + foreach (var item in collection) + result = item.Value; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableHashSet))] + public void SetupImmutableHashSet() => _immutablehashset = Immutable.ImmutableHashSet.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableHashSet() + { + T result = default; + var collection = _immutablehashset; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableList))] + public void SetupImmutableList() => _immutablelist = Immutable.ImmutableList.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableList() + { + T result = default; + var collection = _immutablelist; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableQueue))] + public void SetupImmutableQueue() => _immutablequeue = Immutable.ImmutableQueue.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableQueue() + { + T result = default; + var collection = _immutablequeue; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableStack))] + public void SetupImmutableStack() => _immutablestack = Immutable.ImmutableStack.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableStack() + { + T result = default; + var collection = _immutablestack; + foreach (var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableSortedDictionary))] + public void SetupImmutableSortedDictionary() => _immutablesorteddictionary = Immutable.ImmutableSortedDictionary.CreateRange(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public T ImmutableSortedDictionary() + { + T result = default; + var collection = _immutablesorteddictionary; + foreach (var item in collection) + result = item.Value; + return result; + } + + [GlobalSetup(Target = nameof(ImmutableSortedSet))] + public void SetupImmutableSortedSet() => _immutablesortedset = Immutable.ImmutableSortedSet.CreateRange(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public T ImmutableSortedSet() + { + T result = default; + var collection = _immutablesortedset; + foreach (var item in collection) + result = item; + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Iterate/IterateForEachNonGeneric.cs b/src/benchmarks/corefx/System.Collections/Iterate/IterateForEachNonGeneric.cs new file mode 100644 index 00000000000..cb7ff3c2a3b --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Iterate/IterateForEachNonGeneric.cs @@ -0,0 +1,86 @@ +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.NonGenericCollections)] + [GenericTypeArguments(typeof(int))] // value type (it shows how bad idea is to use non-generic collections for value types) + [GenericTypeArguments(typeof(string))] // reference type + public class IterateForEachNonGeneric + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private ArrayList _arraylist; + private Hashtable _hashtable; + private Queue _queue; + private Stack _stack; + private SortedList _sortedlist; + + [GlobalSetup(Target = nameof(ArrayList))] + public void SetupArrayList() => _arraylist = new ArrayList(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public object ArrayList() + { + object result = default; + var collection = _arraylist; + foreach(var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(Hashtable))] + public void SetupHashtable() => _hashtable = new Hashtable(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public object Hashtable() + { + object result = default; + var collection = _hashtable; + foreach(var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(Queue))] + public void SetupQueue() => _queue = new Queue(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public object Queue() + { + object result = default; + var collection = _queue; + foreach(var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(Stack))] + public void SetupStack() => _stack = new Stack(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public object Stack() + { + object result = default; + var collection = _stack; + foreach(var item in collection) + result = item; + return result; + } + + [GlobalSetup(Target = nameof(SortedList))] + public void SetupSortedList() => _sortedlist = new SortedList(UniqueValuesGenerator.GenerateDictionary(Size)); + + [Benchmark] + public object SortedList() + { + object result = default; + var collection = _sortedlist; + foreach(var item in collection) + result = item; + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Iterate/IterateForNonGeneric.cs b/src/benchmarks/corefx/System.Collections/Iterate/IterateForNonGeneric.cs new file mode 100644 index 00000000000..9bd6141d350 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Iterate/IterateForNonGeneric.cs @@ -0,0 +1,30 @@ +using BenchmarkDotNet.Attributes; +using Benchmarks; +using Helpers; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.NonGenericCollections)] + [GenericTypeArguments(typeof(int))] // value type (it shows how bad idea is to use non-generic collections for value types) + [GenericTypeArguments(typeof(string))] // reference type + public class IterateForNonGeneric + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private ArrayList _arraylist; + + [GlobalSetup(Target = nameof(ArrayList))] + public void SetupArrayList() => _arraylist = new ArrayList(UniqueValuesGenerator.GenerateArray(Size)); + + [Benchmark] + public object ArrayList() + { + object result = default; + var collection = _arraylist; + for(int i = 0; i < collection.Count; i++) + result = collection[i]; + return result; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Remove/Clear.cs b/src/benchmarks/corefx/System.Collections/Remove/Clear.cs new file mode 100644 index 00000000000..b929d8e16c9 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Remove/Clear.cs @@ -0,0 +1,116 @@ +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 + [InvocationCount(InvocationsPerIteration)] + public class Clear + { + private const int InvocationsPerIteration = 1000; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private int _iterationIndex = 0; + private T[] _keys; + + private List[] _lists; + private LinkedList[] _linkedLists; + private HashSet[] _hashSets; + private Dictionary[] _dictionaries; + private SortedList[] _sortedLists; + private SortedSet[] _sortedSets; + private SortedDictionary[] _sortedDictionaries; + private ConcurrentDictionary[] _concurrentDictionaries; + private Stack[] _stacks; + private Queue[] _queues; + private ConcurrentStack[] _concurrentStacks; + private ConcurrentQueue[] _concurrentQueues; + + [GlobalSetup] + public void Setup() => _keys = UniqueValuesGenerator.GenerateArray(Size); + + [IterationCleanup] + public void CleanupIteration() => _iterationIndex = 0; // after every iteration end we set the index to 0 + + [IterationSetup(Target = nameof(List))] + public void SetupListIteration() => Utils.FillCollections(ref _lists, InvocationsPerIteration, _keys); + + [Benchmark] + public void List() => _lists[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(LinkedList))] + public void SetupLinkedListIteration() => Utils.FillCollections(ref _linkedLists, InvocationsPerIteration, _keys); + + [Benchmark] + public void LinkedList() => _linkedLists[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(HashSet))] + public void SetupHashSetIteration() => Utils.FillCollections(ref _hashSets, InvocationsPerIteration, _keys); + + [Benchmark] + public void HashSet() => _hashSets[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(Dictionary))] + public void SetupDictionaryIteration() => Utils.FillDictionaries(ref _dictionaries, InvocationsPerIteration, _keys); + + [Benchmark] + public void Dictionary() => _dictionaries[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(SortedList))] + public void SetupSortedListIteration() => Utils.FillDictionaries(ref _sortedLists, InvocationsPerIteration, _keys); + + [Benchmark] + public void SortedList() => _sortedLists[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(SortedSet))] + public void SetupSortedSetIteration() => Utils.FillCollections(ref _sortedSets, InvocationsPerIteration, _keys); + + [Benchmark] + public void SortedSet() => _sortedSets[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(SortedDictionary))] + public void SetupSortedDictionaryIteration() => Utils.FillDictionaries(ref _sortedDictionaries, InvocationsPerIteration, _keys); + + [Benchmark] + public void SortedDictionary() => _sortedDictionaries[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(ConcurrentDictionary))] + public void SetupConcurrentDictionaryIteration() => Utils.FillDictionaries(ref _concurrentDictionaries, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentDictionary() => _concurrentDictionaries[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(Stack))] + public void SetupStackIteration() => Utils.FillStacks(ref _stacks, InvocationsPerIteration, _keys); + + [Benchmark] + public void Stack() => _stacks[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(ConcurrentStack))] + public void SetupConcurrentStackIteration() => Utils.FillProducerConsumerCollection(ref _concurrentStacks, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentStack() => _concurrentStacks[_iterationIndex++].Clear(); + + [IterationSetup(Target = nameof(Queue))] + public void SetupQueueIteration() => Utils.FillQueues(ref _queues, InvocationsPerIteration, _keys); + + [Benchmark] + public void Queue() => _queues[_iterationIndex++].Clear(); + +#if !NETFRAMEWORK // API added in .NET Core 2.0 + [IterationSetup(Target = nameof(ConcurrentQueue))] + public void SetupConcurrentQueueIteration() => Utils.FillProducerConsumerCollection(ref _concurrentQueues, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentQueue() => _concurrentQueues[_iterationIndex++].Clear(); +#endif + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Remove/Remove.cs b/src/benchmarks/corefx/System.Collections/Remove/Remove.cs new file mode 100644 index 00000000000..7d3245c0b46 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Remove/Remove.cs @@ -0,0 +1,213 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +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 + [InvocationCount(InvocationsPerIteration)] + public class Remove + { + private const int InvocationsPerIteration = 1000; + + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private int _iterationIndex = 0; + private T[] _keys; + + private List[] _lists; + private LinkedList[] _linkedLists; + private HashSet[] _hashSets; + private Dictionary[] _dictionaries; + private SortedList[] _sortedLists; + private SortedSet[] _sortedSets; + private SortedDictionary[] _sortedDictionaries; + private ConcurrentDictionary[] _concurrentDictionaries; + private Stack[] _stacks; + private Queue[] _queues; + private ConcurrentStack[] _concurrentStacks; + private ConcurrentQueue[] _concurrentQueues; + private ConcurrentBag[] _concurrentBags; + + [GlobalSetup] + public void Setup() => _keys = UniqueValuesGenerator.GenerateArray(Size); + + [IterationCleanup] + public void CleanupIteration() => _iterationIndex = 0; // after every iteration end we set the index to 0 + + [IterationSetup(Targets = new []{ nameof(List), nameof(ICollection) })] + public void SetupListIteration() => Utils.FillCollections(ref _lists, InvocationsPerIteration, _keys); + + [Benchmark] + public void List() + { + var list = _lists[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + list.Remove(key); + } + + [Benchmark] + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public void ICollection() => RemoveFromCollection(_lists[_iterationIndex++]); + + [MethodImpl(MethodImplOptions.NoInlining)] + private void RemoveFromCollection(ICollection collection) + { + var keys = _keys; + foreach (var key in keys) + collection.Remove(key); + } + + [IterationSetup(Target = nameof(LinkedList))] + public void SetupLinkedListIteration() => Utils.FillCollections(ref _linkedLists, InvocationsPerIteration, _keys); + + [Benchmark] + public void LinkedList() + { + var linkedlist = _linkedLists[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + linkedlist.Remove(key); + } + + [IterationSetup(Target = nameof(HashSet))] + public void SetupHashSetIteration() => Utils.FillCollections(ref _hashSets, InvocationsPerIteration, _keys); + + [Benchmark] + public void HashSet() + { + var hashset = _hashSets[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + hashset.Remove(key); + } + + [IterationSetup(Target = nameof(Dictionary))] + public void SetupDictionaryIteration() => Utils.FillDictionaries(ref _dictionaries, InvocationsPerIteration, _keys); + + [Benchmark] + public void Dictionary() + { + var dictionary = _dictionaries[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + dictionary.Remove(key); + } + + [IterationSetup(Target = nameof(SortedList))] + public void SetupSortedListIteration() => Utils.FillDictionaries(ref _sortedLists, InvocationsPerIteration, _keys); + + [Benchmark] + public void SortedList() + { + var sortedlist = _sortedLists[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + sortedlist.Remove(key); + } + + [IterationSetup(Target = nameof(SortedSet))] + public void SetupSortedSetIteration() => Utils.FillCollections(ref _sortedSets, InvocationsPerIteration, _keys); + + [Benchmark] + public void SortedSet() + { + var sortedset = _sortedSets[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + sortedset.Remove(key); + } + + [IterationSetup(Target = nameof(SortedDictionary))] + public void SetupSortedDictionaryIteration() => Utils.FillDictionaries(ref _sortedDictionaries, InvocationsPerIteration, _keys); + + [Benchmark] + public void SortedDictionary() + { + var sorteddictionary = _sortedDictionaries[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + sorteddictionary.Remove(key); + } + + [IterationSetup(Target = nameof(ConcurrentDictionary))] + public void SetupConcurrentDictionaryIteration() => Utils.FillDictionaries(ref _concurrentDictionaries, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentDictionary() + { + var concurrentdictionary = _concurrentDictionaries[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) + concurrentdictionary.TryRemove(key, out _); + } + + [IterationSetup(Target = nameof(Stack))] + public void SetupStackIteration() => Utils.FillStacks(ref _stacks, InvocationsPerIteration, _keys); + + [Benchmark] + public void Stack() + { + var stack = _stacks[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) // we don't need to iterate over keys but to compare apples to apples we do + stack.Pop(); + } + + [IterationSetup(Target = nameof(ConcurrentStack))] + public void SetupConcurrentStackIteration() => Utils.FillProducerConsumerCollection(ref _concurrentStacks, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentStack() + { + var stack = _concurrentStacks[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) // we don't need to iterate over keys but to compare apples to apples we do + stack.TryPop(out _); + } + + [IterationSetup(Target = nameof(Queue))] + public void SetupQueueIteration() => Utils.FillQueues(ref _queues, InvocationsPerIteration, _keys); + + [Benchmark] + public void Queue() + { + var queue = _queues[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) // we don't need to iterate over keys but to compare apples to apples we do + queue.Dequeue(); + } + + [IterationSetup(Target = nameof(ConcurrentQueue))] + public void SetupConcurrentQueueIteration() => Utils.FillProducerConsumerCollection(ref _concurrentQueues, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentQueue() + { + var queue = _concurrentQueues[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) // we don't need to iterate over keys but to compare apples to apples we do + queue.TryDequeue(out _); + } + + [IterationSetup(Target = nameof(ConcurrentBag))] + public void SetupConcurrentBagIteration() => Utils.FillProducerConsumerCollection(ref _concurrentBags, InvocationsPerIteration, _keys); + + [Benchmark] + public void ConcurrentBag() + { + var bag = _concurrentBags[_iterationIndex++]; + var keys = _keys; + foreach (var key in keys) // we don't need to iterate over keys but to compare apples to apples we do + bag.TryTake(out _); + } + } +} \ No newline at end of file diff --git a/src/benchmarks/corefx/System.Collections/Utils.cs b/src/benchmarks/corefx/System.Collections/Utils.cs new file mode 100644 index 00000000000..b9afa6d4789 --- /dev/null +++ b/src/benchmarks/corefx/System.Collections/Utils.cs @@ -0,0 +1,81 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace System.Collections +{ + internal static class Utils + { + internal const int DefaultCollectionSize = 512; + + internal const int ConcurrencyLevel = 4; + + internal static void FillCollections(ref TCollection[] collections, int collectionsCount, TValues[] keys) + where TCollection : ICollection, new() + { + if (collections == null) + collections = Enumerable.Range(0, collectionsCount).Select(_ => new TCollection()).ToArray(); + + foreach (var collection in collections.Where(collection => collection.Count < keys.Length)) + foreach (var value in keys) + collection.Add(value); + + if(collections.Any(collection => collection.Count != keys.Length)) // we dont use Debug.Assert here because this code will be executed mostly in Release + throw new InvalidOperationException(); + } + + internal static void FillDictionaries(ref TCollection[] collections, int collectionsCount, TValues[] keys) + where TCollection : IDictionary, new() + { + if (collections == null) + collections = Enumerable.Range(0, collectionsCount).Select(_ => new TCollection()).ToArray(); + + foreach (var collection in collections.Where(collection => collection.Count < keys.Length)) + foreach (var key in keys) + collection.Add(key, key); + + if(collections.Any(collection => collection.Count != keys.Length)) + throw new InvalidOperationException(); + } + + internal static void FillProducerConsumerCollection(ref TCollection[] collections, int collectionsCount, TValues[] keys) + where TCollection : IProducerConsumerCollection, new() + { + if (collections == null) + collections = Enumerable.Range(0, collectionsCount).Select(_ => new TCollection()).ToArray(); + + foreach (var collection in collections.Where(collection => collection.Count < keys.Length)) + foreach (var value in keys) + collection.TryAdd(value); + + if(collections.Any(collection => collection.Count != keys.Length)) + throw new InvalidOperationException(); + } + + internal static void FillStacks(ref Stack[] stacks, int collectionsCount, T[] keys) // Stack does not implement any interface that exposes .Push method + { + if (stacks == null) + stacks = Enumerable.Range(0, collectionsCount).Select(_ => new Stack()).ToArray(); + + foreach (var stack in stacks.Where(stack => stack.Count < keys.Length)) + foreach (var value in keys) + stack.Push(value); + + if(stacks.Any(collection => collection.Count != keys.Length)) + throw new InvalidOperationException(); + } + + internal static void FillQueues(ref Queue[] queues, int collectionsCount, T[] keys) // Queue does not implement any interface that exposes .Enqueue method + { + if (queues == null) + queues = Enumerable.Range(0, collectionsCount).Select(_ => new Queue()).ToArray(); + + foreach (var queue in queues.Where(queue => queue.Count < keys.Length)) + foreach (var value in keys) + queue.Enqueue(value); + + if(queues.Any(collection => collection.Count != keys.Length)) + throw new InvalidOperationException(); + } + } +} \ No newline at end of file