From fc3408279585e383d65539e53e7a934a6a5e8872 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Mon, 15 Feb 2021 22:24:26 +0000 Subject: [PATCH 1/7] add PriorityQueue benchmarks --- src/benchmarks/micro/MicroBenchmarks.csproj | 4 + .../PriorityQueue/Perf_PriorityQueue.cs | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs diff --git a/src/benchmarks/micro/MicroBenchmarks.csproj b/src/benchmarks/micro/MicroBenchmarks.csproj index 4c2ea392201..1608945fa6b 100644 --- a/src/benchmarks/micro/MicroBenchmarks.csproj +++ b/src/benchmarks/micro/MicroBenchmarks.csproj @@ -109,6 +109,10 @@ + + + + diff --git a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs new file mode 100644 index 00000000000..5d3adac8c17 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs @@ -0,0 +1,73 @@ +// 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 BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +namespace System.Collections.Tests +{ + [BenchmarkCategory(Categories.Libraries, Categories.Collections, Categories.GenericCollections)] + public class Perf_PriorityQueue + { + [Params(10, 100, 1000, 10_000, 100_000)] + public int Size; + + private int[] _priorities; + private PriorityQueue _priorityQueue; + + [GlobalSetup] + public void Setup() + { + var random = new Random(42); + _priorities = new int[Size]; + for (int i = 0; i < Size; i++) + { + _priorities[i] = random.Next(); + } + + _priorityQueue = new PriorityQueue(initialCapacity: Size); + } + + [Benchmark] + public void HeapSort() + { + var queue = _priorityQueue; + var priorities = _priorities; + + for (int i = 0; i < Size; i++) + { + queue.Enqueue(i, priorities[i]); + } + + while (queue.Count > 0) + { + queue.Dequeue(); + } + } + + [Benchmark] + public void K_Min_Elements() + { + const int k = 5; + var queue = _priorityQueue; + var priorities = _priorities; + + for (int i = 0; i < k; i++) + { + queue.Enqueue(i, _priorities[i]); + } + + for (int i = k; i < Size; i++) + { + queue.EnqueueDequeue(i, _priorities[i]); + } + + for (int i = 0; i < k; i++) + { + queue.Dequeue(); + } + } + } +} From 8f2cc0f0720d85178c4b2f7f3b8ee7a6834ea2d3 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 17 Feb 2021 12:24:36 +0000 Subject: [PATCH 2/7] add heapify and enumeration benchmarks --- .../PriorityQueue/Perf_PriorityQueue.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs index 5d3adac8c17..6a5a5fa0e3c 100644 --- a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs @@ -2,6 +2,7 @@ // 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.Linq; using System.Collections.Generic; using BenchmarkDotNet.Attributes; using MicroBenchmarks; @@ -15,7 +16,9 @@ public class Perf_PriorityQueue public int Size; private int[] _priorities; + private (int Element, int Priority)[] _elements; private PriorityQueue _priorityQueue; + private PriorityQueue _populatedPriorityQueue; [GlobalSetup] public void Setup() @@ -27,20 +30,55 @@ public void Setup() _priorities[i] = random.Next(); } + _elements = _priorities.Select((i, x) => (i, x)).ToArray(); _priorityQueue = new PriorityQueue(initialCapacity: Size); + _populatedPriorityQueue = new PriorityQueue(_elements); } [Benchmark] public void HeapSort() { + var queue = _priorityQueue; + queue.EnqueueRange(_elements); + + while (queue.Count > 0) + { + queue.Dequeue(); + } + } + + [Benchmark] + public void Enumerate() + { + foreach (var _ in _populatedPriorityQueue.UnorderedItems) + { + + } + } + + [Benchmark] + public void Dequeue_And_Enqueue() + { + // benchmarks dequeue and enqueue operations + // for heaps of fixed size. + var queue = _priorityQueue; var priorities = _priorities; + // populate the heap: incorporated in the + // benchmark to achieve determinism. for (int i = 0; i < Size; i++) { queue.Enqueue(i, priorities[i]); } + for (int i = 0; i < Size; i++) + { + queue.Dequeue(); + queue.Enqueue(i, priorities[i]); + } + + // Drain the heap while (queue.Count > 0) { queue.Dequeue(); From c1f3492f5880502324da3445b0ea188d237fae5f Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 18 Feb 2021 13:50:27 +0000 Subject: [PATCH 3/7] extend benchmarks to reference types --- .../PriorityQueue/Perf_PriorityQueue.cs | 91 +++++++++++++------ 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs index 6a5a5fa0e3c..0eae4017f9c 100644 --- a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs @@ -10,36 +10,38 @@ namespace System.Collections.Tests { [BenchmarkCategory(Categories.Libraries, Categories.Collections, Categories.GenericCollections)] - public class Perf_PriorityQueue + public abstract class Perf_PriorityQueue { [Params(10, 100, 1000, 10_000, 100_000)] public int Size; - private int[] _priorities; - private (int Element, int Priority)[] _elements; - private PriorityQueue _priorityQueue; - private PriorityQueue _populatedPriorityQueue; + private (TElement Element, TPriority Priority)[] _items; + private PriorityQueue _priorityQueue; + private PriorityQueue _prePopulatedPriorityQueue; + + public abstract IEnumerable<(TElement Element, TPriority Priority)> GenerateItems(int count); [GlobalSetup] public void Setup() { - var random = new Random(42); - _priorities = new int[Size]; - for (int i = 0; i < Size; i++) - { - _priorities[i] = random.Next(); - } - - _elements = _priorities.Select((i, x) => (i, x)).ToArray(); - _priorityQueue = new PriorityQueue(initialCapacity: Size); - _populatedPriorityQueue = new PriorityQueue(_elements); + _items = GenerateItems(Size).ToArray(); + //var random = new Random(42); + //_elements = new int[Size]; + //for (int i = 0; i < Size; i++) + //{ + // _elements[i] = random.Next(); + //} + + //_items = _elements.Select((i, x) => (i, x)).ToArray(); + _priorityQueue = new PriorityQueue(initialCapacity: Size); + _prePopulatedPriorityQueue = new PriorityQueue(_items); } [Benchmark] public void HeapSort() { var queue = _priorityQueue; - queue.EnqueueRange(_elements); + queue.EnqueueRange(_items); while (queue.Count > 0) { @@ -50,7 +52,7 @@ public void HeapSort() [Benchmark] public void Enumerate() { - foreach (var _ in _populatedPriorityQueue.UnorderedItems) + foreach (var _ in _prePopulatedPriorityQueue.UnorderedItems) { } @@ -63,19 +65,19 @@ public void Dequeue_And_Enqueue() // for heaps of fixed size. var queue = _priorityQueue; - var priorities = _priorities; + var items = _items; // populate the heap: incorporated in the // benchmark to achieve determinism. - for (int i = 0; i < Size; i++) + foreach ((TElement element, TPriority priority) in items) { - queue.Enqueue(i, priorities[i]); + queue.Enqueue(element, priority); } - for (int i = 0; i < Size; i++) + foreach ((TElement element, TPriority priority) in items) { queue.Dequeue(); - queue.Enqueue(i, priorities[i]); + queue.Enqueue(element, priority); } // Drain the heap @@ -86,20 +88,22 @@ public void Dequeue_And_Enqueue() } [Benchmark] - public void K_Min_Elements() + public void K_Max_Elements() { const int k = 5; var queue = _priorityQueue; - var priorities = _priorities; + var items = _items; for (int i = 0; i < k; i++) { - queue.Enqueue(i, _priorities[i]); + (TElement element, TPriority priority) = items[i]; + queue.Enqueue(element, priority); } for (int i = k; i < Size; i++) { - queue.EnqueueDequeue(i, _priorities[i]); + (TElement element, TPriority priority) = items[i]; + queue.EnqueueDequeue(element, priority); } for (int i = 0; i < k; i++) @@ -108,4 +112,39 @@ public void K_Min_Elements() } } } + + public class Perf_PriorityQueue_String_String : Perf_PriorityQueue + { + public override IEnumerable<(string Element, string Priority)> GenerateItems(int count) + { + var random = new Random(42); + const int MaxSize = 30; + byte[] buffer = new byte[MaxSize]; + + for (int i = 0; i < count; i++) + { + yield return (GenerateString(), GenerateString()); + } + + string GenerateString() + { + int size = random.Next(MaxSize); + Span slice = buffer.AsSpan().Slice(size); + random.NextBytes(slice); + return Convert.ToBase64String(slice); + } + } + } + + public class Perf_PriorityQueue_Int_Int : Perf_PriorityQueue + { + public override IEnumerable<(int Element, int Priority)> GenerateItems(int count) + { + var random = new Random(42); + for (int i = 0; i < count; i++) + { + yield return (random.Next(), random.Next()); + } + } + } } From e2a4dfacebdd0694c3185f084dbfb8b664e642a6 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 18 Feb 2021 13:52:38 +0000 Subject: [PATCH 4/7] remove comments --- .../PriorityQueue/Perf_PriorityQueue.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs index 0eae4017f9c..d8093a332ba 100644 --- a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs @@ -25,14 +25,6 @@ public abstract class Perf_PriorityQueue public void Setup() { _items = GenerateItems(Size).ToArray(); - //var random = new Random(42); - //_elements = new int[Size]; - //for (int i = 0; i < Size; i++) - //{ - // _elements[i] = random.Next(); - //} - - //_items = _elements.Select((i, x) => (i, x)).ToArray(); _priorityQueue = new PriorityQueue(initialCapacity: Size); _prePopulatedPriorityQueue = new PriorityQueue(_items); } From 85f7c60351b5ab4db671551a3af1888b212e7ba7 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 18 Feb 2021 16:19:43 +0000 Subject: [PATCH 5/7] address feedback --- .../PriorityQueue/Perf_PriorityQueue.cs | 46 +++---------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs index d8093a332ba..93ccf3fbc78 100644 --- a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs @@ -5,26 +5,27 @@ using System.Linq; using System.Collections.Generic; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; using MicroBenchmarks; namespace System.Collections.Tests { [BenchmarkCategory(Categories.Libraries, Categories.Collections, Categories.GenericCollections)] - public abstract class Perf_PriorityQueue + [GenericTypeArguments(typeof(int), typeof(int))] + [GenericTypeArguments(typeof(string), typeof(string))] + public class Perf_PriorityQueue { - [Params(10, 100, 1000, 10_000, 100_000)] + [Params(10, 100, 1000)] public int Size; private (TElement Element, TPriority Priority)[] _items; private PriorityQueue _priorityQueue; private PriorityQueue _prePopulatedPriorityQueue; - public abstract IEnumerable<(TElement Element, TPriority Priority)> GenerateItems(int count); - [GlobalSetup] public void Setup() { - _items = GenerateItems(Size).ToArray(); + _items = ValuesGenerator.Array(Size).Zip(ValuesGenerator.Array(Size)).ToArray(); _priorityQueue = new PriorityQueue(initialCapacity: Size); _prePopulatedPriorityQueue = new PriorityQueue(_items); } @@ -104,39 +105,4 @@ public void K_Max_Elements() } } } - - public class Perf_PriorityQueue_String_String : Perf_PriorityQueue - { - public override IEnumerable<(string Element, string Priority)> GenerateItems(int count) - { - var random = new Random(42); - const int MaxSize = 30; - byte[] buffer = new byte[MaxSize]; - - for (int i = 0; i < count; i++) - { - yield return (GenerateString(), GenerateString()); - } - - string GenerateString() - { - int size = random.Next(MaxSize); - Span slice = buffer.AsSpan().Slice(size); - random.NextBytes(slice); - return Convert.ToBase64String(slice); - } - } - } - - public class Perf_PriorityQueue_Int_Int : Perf_PriorityQueue - { - public override IEnumerable<(int Element, int Priority)> GenerateItems(int count) - { - var random = new Random(42); - for (int i = 0; i < count; i++) - { - yield return (random.Next(), random.Next()); - } - } - } } From 937f51514a1d6fe0e6904b48417cfca60a967a75 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 19 Feb 2021 20:38:25 +0000 Subject: [PATCH 6/7] add PriorityQueue Guid benchmarks --- .../System.Collections/PriorityQueue/Perf_PriorityQueue.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs index 93ccf3fbc78..0b371351409 100644 --- a/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs +++ b/src/benchmarks/micro/libraries/System.Collections/PriorityQueue/Perf_PriorityQueue.cs @@ -2,6 +2,7 @@ // 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; using System.Linq; using System.Collections.Generic; using BenchmarkDotNet.Attributes; @@ -13,6 +14,7 @@ namespace System.Collections.Tests [BenchmarkCategory(Categories.Libraries, Categories.Collections, Categories.GenericCollections)] [GenericTypeArguments(typeof(int), typeof(int))] [GenericTypeArguments(typeof(string), typeof(string))] + [GenericTypeArguments(typeof(Guid), typeof(Guid))] public class Perf_PriorityQueue { [Params(10, 100, 1000)] From efce7c9a5be3ceb2fcb5591c899f3a57b1f4412b Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 19 Feb 2021 20:52:47 +0000 Subject: [PATCH 7/7] add ValuesGenerator change --- .../BenchmarkDotNet.Extensions/ValuesGenerator.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs b/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs index 157aef81227..87bf6d82d8d 100644 --- a/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs +++ b/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs @@ -112,6 +112,8 @@ private static T GenerateValue(Random random) return (T)(object)(random.NextDouble() > 0.5); if (typeof(T) == typeof(string)) return (T)(object)GenerateRandomString(random, 1, 50); + if (typeof(T) == typeof(Guid)) + return (T)(object)GenerateRandomGuid(random); throw new NotImplementedException($"{typeof(T).Name} is not implemented"); } @@ -135,5 +137,12 @@ private static string GenerateRandomString(Random random, int minLength, int max return builder.ToString(); } + + private static Guid GenerateRandomGuid(Random random) + { + byte[] bytes = new byte[16]; + random.NextBytes(bytes); + return new Guid(bytes); + } } } \ No newline at end of file