From 61a8ab8b9d227b2d9007199c569e146d49d1d043 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 17 Dec 2021 12:53:06 -0800 Subject: [PATCH 01/11] More efficient bucket finding --- src/OpenTelemetry/Metrics/MetricPoint.cs | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index c8b88755a1..ed011fab18 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -246,15 +246,7 @@ internal void Update(double number) case AggregationType.Histogram: { - int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) - { - // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) - { - break; - } - } + int i = this.FindHistogramBucketIndex(number); lock (this.histogramBuckets.LockObject) { @@ -437,5 +429,30 @@ internal void TakeSnapshot(bool outputDelta) } } } + + private int FindHistogramBucketIndex(double number) + { + var left = 0; + var right = this.histogramBuckets.ExplicitBounds.Length - 1; + + while (left <= right) + { + var mid = (int)Math.Floor((double)(left + right) / 2); + if (number == this.histogramBuckets.ExplicitBounds[mid]) + { + return mid; + } + else if (number > this.histogramBuckets.ExplicitBounds[mid]) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + + return right + 1; + } } } From 5ad482cc2bce46d99a0b096218eb346abbfa9ced Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 17 Dec 2021 12:58:24 -0800 Subject: [PATCH 02/11] Update CHANGELOG.md --- src/OpenTelemetry/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 5e81e0d12b..290897cc76 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,13 +2,16 @@ ## Unreleased +* More efficient histogram bucket finding algorithm. + ([#2754](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2754)) + ## 1.2.0-rc1 Released 2021-Nov-29 * Prevent accessing activity Id before sampler runs in case of legacy activities. - ([2659](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2659)) + ([#2659](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2659)) * Added `ReadOnlyTagCollection` and expose `Tags` on `MetricPoint` instead of `Keys`+`Values` From 00970cbf46a980cfcceeb1e33328c4e65f8ca60c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Sun, 19 Dec 2021 18:17:08 -0800 Subject: [PATCH 03/11] Update Program.cs --- test/OpenTelemetry.Tests.Stress.Metrics/Program.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index 869a02fca5..f781a312a1 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -27,6 +27,7 @@ public partial class Program private const int ArraySize = 10; private static readonly Meter TestMeter = new Meter(Utils.GetCurrentMethodName()); private static readonly Counter TestCounter = TestMeter.CreateCounter("TestCounter"); + private static readonly Histogram TestHistogram = TestMeter.CreateHistogram("TestHistogram"); private static readonly string[] DimensionValues = new string[ArraySize]; private static readonly ThreadLocal ThreadLocalRandom = new ThreadLocal(() => new Random()); @@ -37,6 +38,7 @@ public static void Main() DimensionValues[i] = $"DimValue{i}"; } + var boundaries = new double[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500 }; using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) .AddPrometheusExporter(options => @@ -45,6 +47,7 @@ public static void Main() options.HttpListenerPrefixes = new string[] { $"http://localhost:9185/" }; options.ScrapeResponseCacheDurationMilliseconds = 0; }) + .AddView(TestHistogram.Name, new ExplicitBucketHistogramConfiguration() { Boundaries = boundaries }) .Build(); Stress(prometheusPort: 9184); @@ -54,10 +57,11 @@ public static void Main() protected static void Run() { var random = ThreadLocalRandom.Value; - TestCounter.Add( + /*TestCounter.Add( 100, new("DimName1", DimensionValues[random.Next(0, ArraySize)]), new("DimName2", DimensionValues[random.Next(0, ArraySize)]), - new("DimName3", DimensionValues[random.Next(0, ArraySize)])); + new("DimName3", DimensionValues[random.Next(0, ArraySize)]));*/ + TestHistogram.Record(random.Next(-100, 600)); } } From 2cfd18540bf109b5051246b9c1227642e2626924 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 28 Dec 2021 12:44:49 -0800 Subject: [PATCH 04/11] Use Array.BinarySearch built-in --- src/OpenTelemetry/Metrics/MetricPoint.cs | 41 +++++++++--------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index ed011fab18..dcff8ddee8 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -246,7 +246,21 @@ internal void Update(double number) case AggregationType.Histogram: { - int i = this.FindHistogramBucketIndex(number); + int i; + if (double.IsNaN(number)) + { + i = this.histogramBuckets.ExplicitBounds.Length; + } + else + { + // If number is not a histogram bound, then the result will be zero + // The bitwise complement of the returned value is the insertion index + i = Array.BinarySearch(this.histogramBuckets.ExplicitBounds, number); + if (i < 0) + { + i = ~i; + } + } lock (this.histogramBuckets.LockObject) { @@ -429,30 +443,5 @@ internal void TakeSnapshot(bool outputDelta) } } } - - private int FindHistogramBucketIndex(double number) - { - var left = 0; - var right = this.histogramBuckets.ExplicitBounds.Length - 1; - - while (left <= right) - { - var mid = (int)Math.Floor((double)(left + right) / 2); - if (number == this.histogramBuckets.ExplicitBounds[mid]) - { - return mid; - } - else if (number > this.histogramBuckets.ExplicitBounds[mid]) - { - left = mid + 1; - } - else - { - right = mid - 1; - } - } - - return right + 1; - } } } From 31261572f9f22b7fa53c3d45908091a59803a6b1 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 28 Dec 2021 15:01:16 -0800 Subject: [PATCH 05/11] Update MetricPoint.cs --- src/OpenTelemetry/Metrics/MetricPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index dcff8ddee8..47cc2b1aaf 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -253,7 +253,7 @@ internal void Update(double number) } else { - // If number is not a histogram bound, then the result will be zero + // If `number` is not a histogram bound, the result will be negative // The bitwise complement of the returned value is the insertion index i = Array.BinarySearch(this.histogramBuckets.ExplicitBounds, number); if (i < 0) From a5efd0e9660f0650133887b409861ca3cf6f34eb Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 7 Jan 2022 17:55:28 -0800 Subject: [PATCH 06/11] Delete work and just include a benchmark --- src/OpenTelemetry/CHANGELOG.md | 3 - src/OpenTelemetry/Metrics/MetricPoint.cs | 14 +-- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 100 ++++++++++++++++++ .../Program.cs | 8 +- 4 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 test/Benchmarks/Metrics/HistogramBenchmarks.cs diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 290897cc76..5dc0265b2f 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,9 +2,6 @@ ## Unreleased -* More efficient histogram bucket finding algorithm. - ([#2754](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2754)) - ## 1.2.0-rc1 Released 2021-Nov-29 diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 47cc2b1aaf..c8b88755a1 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -247,18 +247,12 @@ internal void Update(double number) case AggregationType.Histogram: { int i; - if (double.IsNaN(number)) + for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) { - i = this.histogramBuckets.ExplicitBounds.Length; - } - else - { - // If `number` is not a histogram bound, the result will be negative - // The bitwise complement of the returned value is the insertion index - i = Array.BinarySearch(this.histogramBuckets.ExplicitBounds, number); - if (i < 0) + // Upper bound is inclusive + if (number <= this.histogramBuckets.ExplicitBounds[i]) { - i = ~i; + break; } } diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs new file mode 100644 index 0000000000..0a22f49a6a --- /dev/null +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -0,0 +1,100 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.Metrics; +using BenchmarkDotNet.Attributes; +using OpenTelemetry; +using OpenTelemetry.Exporter; +using OpenTelemetry.Metrics; +using OpenTelemetry.Tests; + +/* +| Method | BoundCount | Mean | Error | StdDev | Allocated | +|----------------------- |----------- |---------:|---------:|---------:|----------:| +| HistogramLongHotPath | 10 | 43.85 ns | 0.151 ns | 0.134 ns | - | +| HistogramDoubleHotPath | 10 | 42.62 ns | 0.428 ns | 0.400 ns | - | +| HistogramLongHotPath | 20 | 46.81 ns | 0.229 ns | 0.214 ns | - | +| HistogramDoubleHotPath | 20 | 44.97 ns | 0.106 ns | 0.099 ns | - | +| HistogramLongHotPath | 50 | 58.76 ns | 0.179 ns | 0.150 ns | - | +| HistogramDoubleHotPath | 50 | 53.16 ns | 0.168 ns | 0.149 ns | - | +| HistogramLongHotPath | 100 | 69.91 ns | 1.021 ns | 0.955 ns | - | +| HistogramDoubleHotPath | 100 | 64.25 ns | 0.088 ns | 0.082 ns | - | +*/ + +namespace Benchmarks.Metrics +{ + [MemoryDiagnoser] + public class HistogramBenchmarks + { + private const int MaxValue = 1000; + private readonly Random random = new(); + private Histogram histogramLong; + private Histogram histogramDouble; + private MeterProvider provider; + private Meter meter; + private double[] bounds; + + [Params(10, 20, 50, 100)] + public int BoundCount { get; set; } + + [GlobalSetup] + public void Setup() + { + this.meter = new Meter(Utils.GetCurrentMethodName()); + + this.histogramLong = this.meter.CreateHistogram("histogramLong"); + this.histogramDouble = this.meter.CreateHistogram("histogramDouble"); + + // Evenly distribute the bound values over the range [0, MaxValue) + this.bounds = new double[this.BoundCount]; + for (int i = 0; i < this.bounds.Length; i++) + { + this.bounds[i] = i * MaxValue / this.bounds.Length; + } + + var exportedItems = new List(); + var reader = new PeriodicExportingMetricReader(new InMemoryExporter(exportedItems), 1000); + + this.provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(this.meter.Name) + .AddReader(reader) + .AddView(this.histogramLong.Name, new ExplicitBucketHistogramConfiguration() { Boundaries = this.bounds }) + .AddView(this.histogramDouble.Name, new ExplicitBucketHistogramConfiguration() { Boundaries = this.bounds }) + .Build(); + } + + [GlobalCleanup] + public void Cleanup() + { + this.meter?.Dispose(); + this.provider?.Dispose(); + } + + [Benchmark] + public void HistogramLongHotPath() + { + this.histogramLong?.Record(this.random.Next(MaxValue)); + } + + [Benchmark] + public void HistogramDoubleHotPath() + { + this.histogramDouble?.Record(this.random.NextDouble() * MaxValue); + } + } +} diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index f781a312a1..869a02fca5 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -27,7 +27,6 @@ public partial class Program private const int ArraySize = 10; private static readonly Meter TestMeter = new Meter(Utils.GetCurrentMethodName()); private static readonly Counter TestCounter = TestMeter.CreateCounter("TestCounter"); - private static readonly Histogram TestHistogram = TestMeter.CreateHistogram("TestHistogram"); private static readonly string[] DimensionValues = new string[ArraySize]; private static readonly ThreadLocal ThreadLocalRandom = new ThreadLocal(() => new Random()); @@ -38,7 +37,6 @@ public static void Main() DimensionValues[i] = $"DimValue{i}"; } - var boundaries = new double[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500 }; using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) .AddPrometheusExporter(options => @@ -47,7 +45,6 @@ public static void Main() options.HttpListenerPrefixes = new string[] { $"http://localhost:9185/" }; options.ScrapeResponseCacheDurationMilliseconds = 0; }) - .AddView(TestHistogram.Name, new ExplicitBucketHistogramConfiguration() { Boundaries = boundaries }) .Build(); Stress(prometheusPort: 9184); @@ -57,11 +54,10 @@ public static void Main() protected static void Run() { var random = ThreadLocalRandom.Value; - /*TestCounter.Add( + TestCounter.Add( 100, new("DimName1", DimensionValues[random.Next(0, ArraySize)]), new("DimName2", DimensionValues[random.Next(0, ArraySize)]), - new("DimName3", DimensionValues[random.Next(0, ArraySize)]));*/ - TestHistogram.Record(random.Next(-100, 600)); + new("DimName3", DimensionValues[random.Next(0, ArraySize)])); } } From 9cecddc766dfa1cbb89789b511fba2ce49467ab9 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 10 Jan 2022 08:33:01 -0800 Subject: [PATCH 07/11] Rerun CI From 6158988397b2963cf8ad0367ab04739626bd1b2c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 27 Jan 2022 13:59:20 -0800 Subject: [PATCH 08/11] use threadsafe random generator --- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 0a22f49a6a..6e418e4fc0 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.Metrics; +using System.Threading; using BenchmarkDotNet.Attributes; using OpenTelemetry; using OpenTelemetry.Exporter; @@ -26,14 +27,14 @@ /* | Method | BoundCount | Mean | Error | StdDev | Allocated | |----------------------- |----------- |---------:|---------:|---------:|----------:| -| HistogramLongHotPath | 10 | 43.85 ns | 0.151 ns | 0.134 ns | - | -| HistogramDoubleHotPath | 10 | 42.62 ns | 0.428 ns | 0.400 ns | - | -| HistogramLongHotPath | 20 | 46.81 ns | 0.229 ns | 0.214 ns | - | -| HistogramDoubleHotPath | 20 | 44.97 ns | 0.106 ns | 0.099 ns | - | -| HistogramLongHotPath | 50 | 58.76 ns | 0.179 ns | 0.150 ns | - | -| HistogramDoubleHotPath | 50 | 53.16 ns | 0.168 ns | 0.149 ns | - | -| HistogramLongHotPath | 100 | 69.91 ns | 1.021 ns | 0.955 ns | - | -| HistogramDoubleHotPath | 100 | 64.25 ns | 0.088 ns | 0.082 ns | - | +| HistogramLongHotPath | 10 | 65.10 ns | 0.694 ns | 0.649 ns | - | +| HistogramDoubleHotPath | 10 | 61.06 ns | 0.370 ns | 0.328 ns | - | +| HistogramLongHotPath | 20 | 68.32 ns | 1.237 ns | 1.157 ns | - | +| HistogramDoubleHotPath | 20 | 67.71 ns | 0.753 ns | 0.704 ns | - | +| HistogramLongHotPath | 50 | 80.11 ns | 0.864 ns | 0.721 ns | - | +| HistogramDoubleHotPath | 50 | 75.49 ns | 0.437 ns | 0.409 ns | - | +| HistogramLongHotPath | 100 | 90.48 ns | 0.296 ns | 0.262 ns | - | +| HistogramDoubleHotPath | 100 | 86.93 ns | 0.915 ns | 0.856 ns | - | */ namespace Benchmarks.Metrics @@ -42,7 +43,8 @@ namespace Benchmarks.Metrics public class HistogramBenchmarks { private const int MaxValue = 1000; - private readonly Random random = new(); + private static readonly string[] DimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; + private static readonly ThreadLocal ThreadLocalRandom = new(() => new Random()); private Histogram histogramLong; private Histogram histogramDouble; private MeterProvider provider; @@ -52,6 +54,7 @@ public class HistogramBenchmarks [Params(10, 20, 50, 100)] public int BoundCount { get; set; } + [GlobalSetup] public void Setup() { @@ -88,13 +91,15 @@ public void Cleanup() [Benchmark] public void HistogramLongHotPath() { - this.histogramLong?.Record(this.random.Next(MaxValue)); + var random = ThreadLocalRandom.Value; + this.histogramLong?.Record(random.Next(MaxValue)); } [Benchmark] public void HistogramDoubleHotPath() { - this.histogramDouble?.Record(this.random.NextDouble() * MaxValue); + var random = ThreadLocalRandom.Value; + this.histogramDouble?.Record(random.NextDouble() * MaxValue); } } } From a178715dd167c39fd26ead2ce34a88bf04ea49f6 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 27 Jan 2022 14:25:57 -0800 Subject: [PATCH 09/11] empty line --- test/Benchmarks/Metrics/HistogramBenchmarks.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 6e418e4fc0..457e57a5d5 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -54,7 +54,6 @@ public class HistogramBenchmarks [Params(10, 20, 50, 100)] public int BoundCount { get; set; } - [GlobalSetup] public void Setup() { From ba40004fc73900654f90d3308880dbe8993392c5 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 2 Feb 2022 10:56:35 -0800 Subject: [PATCH 10/11] Update HistogramBenchmarks.cs --- test/Benchmarks/Metrics/HistogramBenchmarks.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 457e57a5d5..467381ff56 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -43,7 +43,6 @@ namespace Benchmarks.Metrics public class HistogramBenchmarks { private const int MaxValue = 1000; - private static readonly string[] DimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; private static readonly ThreadLocal ThreadLocalRandom = new(() => new Random()); private Histogram histogramLong; private Histogram histogramDouble; From 700c7bbf81b8cc33ec75211df1bfc653e42148d4 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 3 Feb 2022 11:10:32 -0800 Subject: [PATCH 11/11] add benchmark meta data - cpu/framework --- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 467381ff56..aff46b7668 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -25,16 +25,23 @@ using OpenTelemetry.Tests; /* +BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1503 (21H2) +AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores +.NET SDK=6.0.101 + [Host] : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT + DefaultJob : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT + + | Method | BoundCount | Mean | Error | StdDev | Allocated | |----------------------- |----------- |---------:|---------:|---------:|----------:| -| HistogramLongHotPath | 10 | 65.10 ns | 0.694 ns | 0.649 ns | - | -| HistogramDoubleHotPath | 10 | 61.06 ns | 0.370 ns | 0.328 ns | - | -| HistogramLongHotPath | 20 | 68.32 ns | 1.237 ns | 1.157 ns | - | -| HistogramDoubleHotPath | 20 | 67.71 ns | 0.753 ns | 0.704 ns | - | -| HistogramLongHotPath | 50 | 80.11 ns | 0.864 ns | 0.721 ns | - | -| HistogramDoubleHotPath | 50 | 75.49 ns | 0.437 ns | 0.409 ns | - | -| HistogramLongHotPath | 100 | 90.48 ns | 0.296 ns | 0.262 ns | - | -| HistogramDoubleHotPath | 100 | 86.93 ns | 0.915 ns | 0.856 ns | - | +| HistogramLongHotPath | 10 | 55.44 ns | 0.211 ns | 0.187 ns | - | +| HistogramDoubleHotPath | 10 | 55.69 ns | 0.129 ns | 0.107 ns | - | +| HistogramLongHotPath | 20 | 57.71 ns | 0.297 ns | 0.278 ns | - | +| HistogramDoubleHotPath | 20 | 58.10 ns | 0.117 ns | 0.110 ns | - | +| HistogramLongHotPath | 50 | 65.21 ns | 0.356 ns | 0.333 ns | - | +| HistogramDoubleHotPath | 50 | 66.34 ns | 0.381 ns | 0.356 ns | - | +| HistogramLongHotPath | 100 | 79.49 ns | 0.804 ns | 0.753 ns | - | +| HistogramDoubleHotPath | 100 | 85.77 ns | 0.947 ns | 0.840 ns | - | */ namespace Benchmarks.Metrics