diff --git a/src/benchmarks/micro/MicroBenchmarks.csproj b/src/benchmarks/micro/MicroBenchmarks.csproj index 5d08089bd81..3be2354aeca 100644 --- a/src/benchmarks/micro/MicroBenchmarks.csproj +++ b/src/benchmarks/micro/MicroBenchmarks.csproj @@ -224,6 +224,10 @@ + + + + diff --git a/src/benchmarks/micro/libraries/System.Collections/Add/AddGivenSize.cs b/src/benchmarks/micro/libraries/System.Collections/Add/AddGivenSize.cs index 4e24ede54ab..066960cd257 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Add/AddGivenSize.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Add/AddGivenSize.cs @@ -133,5 +133,17 @@ public ObservableCollection ObservableCollection() } return collection; } + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() + { + var collection = new OrderedDictionary(Size); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.Add(uniqueValues[i], uniqueValues[i]); + return collection; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Add/TryAddDefaultSize.cs b/src/benchmarks/micro/libraries/System.Collections/Add/TryAddDefaultSize.cs index 7939abd052c..4bb1a395072 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Add/TryAddDefaultSize.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Add/TryAddDefaultSize.cs @@ -7,6 +7,7 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Extensions; using MicroBenchmarks; +using System.Drawing; namespace System.Collections { @@ -44,5 +45,17 @@ public ConcurrentDictionary ConcurrentDictionary() collection.TryAdd(uniqueValues[i], uniqueValues[i]); return collection; } + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() + { + var collection = new OrderedDictionary(); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Add/TryAddGivenSize.cs b/src/benchmarks/micro/libraries/System.Collections/Add/TryAddGivenSize.cs index c0d06db6e21..276ec416480 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Add/TryAddGivenSize.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Add/TryAddGivenSize.cs @@ -44,5 +44,17 @@ public ConcurrentDictionary ConcurrentDictionary() collection.TryAdd(uniqueValues[i], uniqueValues[i]); return collection; } + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() + { + var collection = new OrderedDictionary(Count); + var uniqueValues = _uniqueValues; + for (int i = 0; i < uniqueValues.Length; i++) + collection.TryAdd(uniqueValues[i], uniqueValues[i]); + return collection; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyFalse.cs b/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyFalse.cs index 65a71e7e4d5..36664e5d097 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyFalse.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyFalse.cs @@ -29,6 +29,9 @@ public class ContainsKeyFalse private ImmutableDictionary _immutableDictionary; private ImmutableSortedDictionary _immutableSortedDictionary; private FrozenDictionary _frozenDictionary; +#if NET9_0_OR_GREATER + private OrderedDictionary _orderedDictionary; +#endif [Params(Utils.DefaultCollectionSize)] public int Size; @@ -47,6 +50,9 @@ public void Setup() _immutableDictionary = Immutable.ImmutableDictionary.CreateRange(_source); _immutableSortedDictionary = Immutable.ImmutableSortedDictionary.CreateRange(_source); _frozenDictionary = _source.ToFrozenDictionary(); +#if NET9_0_OR_GREATER + _orderedDictionary = new OrderedDictionary(_source); +#endif } [Benchmark] @@ -139,5 +145,18 @@ public bool FrozenDictionary() result ^= collection.ContainsKey(notFound[i]); return result; } + +#if NET9_0_OR_GREATER + [Benchmark] + public bool OrderedDictionary() + { + bool result = default; + var collection = _orderedDictionary; + var notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.ContainsKey(notFound[i]); + return result; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyTrue.cs b/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyTrue.cs index 1e273248212..104471d8cf8 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyTrue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Contains/ContainsKeyTrue.cs @@ -29,6 +29,9 @@ public class ContainsKeyTrue private ImmutableDictionary _immutableDictionary; private ImmutableSortedDictionary _immutableSortedDictionary; private FrozenDictionary _frozenDictionary; +#if NET9_0_OR_GREATER + private OrderedDictionary _orderedDictionary; +#endif [Params(Utils.DefaultCollectionSize)] public int Size; @@ -45,6 +48,9 @@ public void Setup() _immutableDictionary = Immutable.ImmutableDictionary.CreateRange(_source); _immutableSortedDictionary = Immutable.ImmutableSortedDictionary.CreateRange(_source); _frozenDictionary = _source.ToFrozenDictionary(); +#if NET9_0_OR_GREATER + _orderedDictionary = new OrderedDictionary(_source); +#endif } [Benchmark] @@ -137,5 +143,18 @@ public bool FrozenDictionary() result ^= collection.ContainsKey(found[i]); return result; } + +#if NET9_0_OR_GREATER + [Benchmark] + public bool OrderedDictionary() + { + bool result = default; + var collection = _orderedDictionary; + var found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.ContainsKey(found[i]); + return result; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Create/CtorDefaultSize.cs b/src/benchmarks/micro/libraries/System.Collections/Create/CtorDefaultSize.cs index 3e5ffa80554..deea37e77e9 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Create/CtorDefaultSize.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Create/CtorDefaultSize.cs @@ -53,5 +53,10 @@ public class CtorDefaultSize [Benchmark] public ConcurrentBag ConcurrentBag() => new ConcurrentBag(); + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() => new OrderedDictionary(); +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Create/CtorFromCollection.cs b/src/benchmarks/micro/libraries/System.Collections/Create/CtorFromCollection.cs index 825c0510605..533e39730a6 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Create/CtorFromCollection.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Create/CtorFromCollection.cs @@ -29,7 +29,11 @@ public class CtorFromCollection nameof(FrozenSet)})] public void SetupCollection() => _collection = ValuesGenerator.ArrayOfUniqueValues(Size); - [GlobalSetup(Targets = new[] { nameof(Dictionary), nameof(SortedList), nameof(SortedDictionary), nameof(ConcurrentDictionary), nameof(ImmutableDictionary), nameof(ImmutableSortedDictionary), nameof(FrozenDictionaryOptimized) })] + [GlobalSetup(Targets = new[] { nameof(Dictionary), nameof(SortedList), nameof(SortedDictionary), nameof(ConcurrentDictionary), nameof(ImmutableDictionary), nameof(ImmutableSortedDictionary), nameof(FrozenDictionaryOptimized), +#if NET9_0_OR_GREATER + nameof(OrderedDictionary) +#endif + })] public void SetupDictionary() => _dictionary = ValuesGenerator.Dictionary(Size); [GlobalSetup(Targets = new[] { nameof(SortedDictionaryDeepCopy) })] @@ -107,5 +111,10 @@ public FrozenDictionary FrozenDictionaryOptimized() // we kept the old nam [Benchmark] public FrozenSet FrozenSet() => _collection.ToFrozenSet(); + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() => new OrderedDictionary(_dictionary); +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Create/CtorGivenSize.cs b/src/benchmarks/micro/libraries/System.Collections/Create/CtorGivenSize.cs index 64b138ed7de..53c040faa51 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Create/CtorGivenSize.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Create/CtorGivenSize.cs @@ -41,5 +41,10 @@ public class CtorGivenSize [Benchmark] public ConcurrentDictionary ConcurrentDictionary() => new ConcurrentDictionary(Utils.ConcurrencyLevel, Size); + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() => new OrderedDictionary(Size); +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/CreateAddAndClear.cs b/src/benchmarks/micro/libraries/System.Collections/CreateAddAndClear.cs index 247be837355..6ff8dd5b378 100644 --- a/src/benchmarks/micro/libraries/System.Collections/CreateAddAndClear.cs +++ b/src/benchmarks/micro/libraries/System.Collections/CreateAddAndClear.cs @@ -326,5 +326,19 @@ public ImmutableQueue ImmutableQueue() } return immutableQueue.Clear(); } + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() + { + OrderedDictionary orderedDictionary = new OrderedDictionary(); + foreach (T value in _uniqueValues) + { + orderedDictionary.Add(value, value); + } + orderedDictionary.Clear(); + return orderedDictionary; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/CreateAddAndRemove.cs b/src/benchmarks/micro/libraries/System.Collections/CreateAddAndRemove.cs index 0bbc9a59ad8..72276a4a265 100644 --- a/src/benchmarks/micro/libraries/System.Collections/CreateAddAndRemove.cs +++ b/src/benchmarks/micro/libraries/System.Collections/CreateAddAndRemove.cs @@ -157,5 +157,22 @@ public Queue Queue() } return queue; } + +#if NET9_0_OR_GREATER + [Benchmark] + public OrderedDictionary OrderedDictionary() + { + OrderedDictionary orderedDictionary = new OrderedDictionary(); + foreach (T key in _keys) + { + orderedDictionary.Add(key, key); + } + foreach (T key in _keys) + { + orderedDictionary.Remove(key); + } + return orderedDictionary; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Indexer/IndexerSet.cs b/src/benchmarks/micro/libraries/System.Collections/Indexer/IndexerSet.cs index b9d9fc3c615..9a2e0ebf01c 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Indexer/IndexerSet.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Indexer/IndexerSet.cs @@ -28,6 +28,9 @@ public class IndexerSet private SortedList _sortedList; private SortedDictionary _sortedDictionary; private ConcurrentDictionary _concurrentDictionary; +#if NET9_0_OR_GREATER + private OrderedDictionary _orderedDictionary; +#endif [GlobalSetup(Targets = new[] { nameof(Array), nameof(Span) })] public void SetupArray() => _array = ValuesGenerator.ArrayOfUniqueValues(Size); @@ -143,5 +146,34 @@ public ConcurrentDictionary ConcurrentDictionary() dictionary[keys[i]] = default; return dictionary; } + +#if NET9_0_OR_GREATER + [GlobalSetup(Targets = [ nameof(OrderedDictionary), nameof(OrderedDictionary_SetAt) ])] + public void SetupOrderedDictionary() + { + _keys = ValuesGenerator.ArrayOfUniqueValues(Size); + _orderedDictionary = new OrderedDictionary(_keys.ToDictionary(i => i, i => i)); + } + + [Benchmark] + public OrderedDictionary OrderedDictionary() + { + var dictionary = _orderedDictionary; + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + dictionary[keys[i]] = default; + return dictionary; + } + + [Benchmark] + public OrderedDictionary OrderedDictionary_SetAt() + { + var dictionary = _orderedDictionary; + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + dictionary.SetAt(i, keys[i], default); + return dictionary; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateFor.cs b/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateFor.cs index 27eaed17a67..840c2388a5d 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateFor.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateFor.cs @@ -25,6 +25,10 @@ public class IterateFor private ImmutableArray _immutablearray; private ImmutableList _immutablelist; private ImmutableSortedSet _immutablesortedset; +#if NET9_0_OR_GREATER + private OrderedDictionary _ordereddictionary; +#endif + [GlobalSetup(Target = nameof(Array))] public void SetupArray() => _array = ValuesGenerator.ArrayOfUniqueValues(Size); @@ -134,5 +138,20 @@ public T ImmutableSortedSet() result = collection[i]; return result; } + +#if NET9_0_OR_GREATER + [GlobalSetup(Target = nameof(OrderedDictionary))] + public void SetupOrderedDictionary() => _ordereddictionary = new OrderedDictionary(ValuesGenerator.Dictionary(Size)); + + [Benchmark] + public KeyValuePair OrderedDictionary() + { + KeyValuePair result = default; + var collection = _ordereddictionary; + for (int i = 0; i < collection.Count; i++) + result = collection.GetAt(i); + return result; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateForEach.cs b/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateForEach.cs index 5e70148a6b5..8de8b6dfb81 100644 --- a/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateForEach.cs +++ b/src/benchmarks/micro/libraries/System.Collections/Iterate/IterateForEach.cs @@ -46,6 +46,9 @@ public class IterateForEach private ImmutableSortedSet _immutablesortedset; private FrozenDictionary _frozenDictionary; private FrozenSet _frozenset; +#if NET9_0_OR_GREATER + private OrderedDictionary _orderedDictionary; +#endif [GlobalSetup(Targets = new [] { nameof(Array), nameof(Span), nameof(ReadOnlySpan)})] public void SetupArray() => _array = ValuesGenerator.ArrayOfUniqueValues(Size); @@ -396,5 +399,20 @@ public T FrozenSet() result = item; return result; } + +#if NET9_0_OR_GREATER + [GlobalSetup(Target = nameof(OrderedDictionary))] + public void SetupOrderedDictionary() => _orderedDictionary = new OrderedDictionary(ValuesGenerator.Dictionary(Size)); + + [Benchmark] + public T OrderedDictionary() + { + T result = default; + var collection = _orderedDictionary; + foreach (var item in collection) + result = item.Value; + return result; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/OrderedDictionary/Perf_OrderedDictionary.cs b/src/benchmarks/micro/libraries/System.Collections/OrderedDictionary/Perf_OrderedDictionary.cs new file mode 100644 index 00000000000..0dff9c78e31 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.Collections/OrderedDictionary/Perf_OrderedDictionary.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; +using MicroBenchmarks; + +namespace System.Collections +{ + [BenchmarkCategory(Categories.Libraries, Categories.Collections, Categories.GenericCollections)] + [GenericTypeArguments(typeof(int))] // value type + [GenericTypeArguments(typeof(string))] // reference type + public class Perf_OrderedDictionary + { + [Params(Utils.DefaultCollectionSize)] + public int Size; + + private T[] _keys; + private Dictionary _dictionary; + + [GlobalSetup] + public void SetupOrderedDictionary() + { + _keys = ValuesGenerator.ArrayOfUniqueValues(2 * Size); + _dictionary = _keys.Take(Size).ToDictionary(i => i, _ => default(T)); + } + + [Benchmark] + public OrderedDictionary AddOrUpdate() + { + var dictionary = new OrderedDictionary(_dictionary); + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + { + var key = keys[i]; + if (dictionary.TryGetValue(key, out T value)) + { + dictionary[key] = value ?? key; + } + else + { + dictionary.Add(key, key); + } + } + return dictionary; + } + + [Benchmark] + public OrderedDictionary AddOrUpdate2() + { + var dictionary = new OrderedDictionary(_dictionary); + var keys = _keys; + for (int i = 0; i < keys.Length; i++) + { + var key = keys[i]; + if (!dictionary.TryAdd(key, key)) + { + dictionary[key] = key; + } + } + return dictionary; + } + } +} \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueFalse.cs b/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueFalse.cs index 21bc91f753e..06e1d6c2de5 100644 --- a/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueFalse.cs +++ b/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueFalse.cs @@ -29,6 +29,9 @@ public class TryGetValueFalse private ImmutableDictionary _immutableDictionary; private ImmutableSortedDictionary _immutableSortedDictionary; private FrozenDictionary _frozenDictionary; +#if NET9_0_OR_GREATER + private OrderedDictionary _orderedDictionary; +#endif [Params(Utils.DefaultCollectionSize)] public int Size; @@ -47,6 +50,9 @@ public void Setup() _immutableDictionary = Immutable.ImmutableDictionary.CreateRange(_source); _immutableSortedDictionary = Immutable.ImmutableSortedDictionary.CreateRange(_source); _frozenDictionary = _source.ToFrozenDictionary(); +#if NET9_0_OR_GREATER + _orderedDictionary = new OrderedDictionary(_source); +#endif } [Benchmark] @@ -139,5 +145,18 @@ public bool FrozenDictionaryOptimized() // we kept the old name on purpose to av result ^= collection.TryGetValue(notFound[i], out _); return result; } + +#if NET9_0_OR_GREATER + [Benchmark] + public bool OrderedDictionary() + { + bool result = default; + OrderedDictionary collection = _orderedDictionary; + TKey[] notFound = _notFound; + for (int i = 0; i < notFound.Length; i++) + result ^= collection.TryGetValue(notFound[i], out _); + return result; + } +#endif } } \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueTrue.cs b/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueTrue.cs index e5d23e5ab2e..a70556cfcdd 100644 --- a/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueTrue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/TryGetValue/TryGetValueTrue.cs @@ -29,6 +29,9 @@ public class TryGetValueTrue private ImmutableDictionary _immutableDictionary; private ImmutableSortedDictionary _immutableSortedDictionary; private FrozenDictionary _frozenDictionary; +#if NET9_0_OR_GREATER + private OrderedDictionary _orderedDictionary; +#endif [Params(Utils.DefaultCollectionSize)] public int Size; @@ -45,6 +48,9 @@ public void Setup() _immutableDictionary = Immutable.ImmutableDictionary.CreateRange(_source); _immutableSortedDictionary = Immutable.ImmutableSortedDictionary.CreateRange(_source); _frozenDictionary = _source.ToFrozenDictionary(); +#if NET9_0_OR_GREATER + _orderedDictionary = new OrderedDictionary(_source); +#endif } [Benchmark] @@ -137,5 +143,18 @@ public bool FrozenDictionaryOptimized() // we kept the old name on purpose to av result ^= collection.TryGetValue(found[i], out _); return result; } + +#if NET9_0_OR_GREATER + [Benchmark] + public bool OrderedDictionary() + { + bool result = default; + OrderedDictionary collection = _orderedDictionary; + TKey[] found = _found; + for (int i = 0; i < found.Length; i++) + result ^= collection.TryGetValue(found[i], out _); + return result; + } +#endif } } \ No newline at end of file