From 17efad04b59584898cc29fcf1cd18a1b414d9ebe Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 1 Dec 2021 11:30:12 -0800 Subject: [PATCH 1/5] WIP compacting MetricPoint struct part 2. --- src/OpenTelemetry/Metrics/AggregationType.cs | 2 +- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 14 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 143 ++++++++++-------- ...e.cs => MetricPointPrimaryValueStorage.cs} | 33 +++- 4 files changed, 118 insertions(+), 74 deletions(-) rename src/OpenTelemetry/Metrics/{MetricPointValueStorage.cs => MetricPointPrimaryValueStorage.cs} (53%) diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index bd87c9e5b4f..2ee2b6d1e0e 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum AggregationType + internal enum AggregationType : sbyte { /// /// Invalid. diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 8b4464c2ac4..a5640e85926 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -18,19 +18,21 @@ namespace OpenTelemetry.Metrics { public class HistogramBuckets { - internal readonly long[] BucketCounts; + internal readonly long[] CurrentBucketCounts; - internal readonly long[] AggregatedBucketCounts; + internal readonly long[] SnapshotBucketCounts; internal readonly double[] ExplicitBounds; internal readonly object LockObject; + internal MetricPointPrimaryValueStorage Sum; + internal HistogramBuckets(double[] histogramBounds) { this.ExplicitBounds = histogramBounds; - this.BucketCounts = histogramBounds != null ? new long[histogramBounds.Length + 1] : null; - this.AggregatedBucketCounts = histogramBounds != null ? new long[histogramBounds.Length + 1] : null; + this.CurrentBucketCounts = histogramBounds != null ? new long[histogramBounds.Length + 1] : null; + this.SnapshotBucketCounts = histogramBounds != null ? new long[histogramBounds.Length + 1] : null; this.LockObject = new object(); } @@ -47,7 +49,7 @@ internal Enumerator(HistogramBuckets histogramMeasurements) this.histogramMeasurements = histogramMeasurements; this.index = 0; this.Current = default; - this.numberOfBuckets = histogramMeasurements.AggregatedBucketCounts == null ? 0 : histogramMeasurements.AggregatedBucketCounts.Length; + this.numberOfBuckets = histogramMeasurements.SnapshotBucketCounts == null ? 0 : histogramMeasurements.SnapshotBucketCounts.Length; } public HistogramBucket Current { get; private set; } @@ -59,7 +61,7 @@ public bool MoveNext() double explicitBound = this.index < this.numberOfBuckets - 1 ? this.histogramMeasurements.ExplicitBounds[this.index] : double.PositiveInfinity; - long bucketCount = this.histogramMeasurements.AggregatedBucketCounts[this.index]; + long bucketCount = this.histogramMeasurements.SnapshotBucketCounts[this.index]; this.Current = new HistogramBucket(explicitBound, bucketCount); this.index++; return true; diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index c8b88755a1e..5eb57c540ff 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -24,13 +24,12 @@ namespace OpenTelemetry.Metrics public struct MetricPoint { private readonly AggregationType aggType; - private readonly HistogramBuckets histogramBuckets; // Represents either "value" for double/long metric types or "count" when histogram - private MetricPointValueStorage primaryValue; + private MetricPointPrimaryValueStorage primaryValue; - // Represents either "lastValue" for double/long metric types when delta or "sum" when histogram - private MetricPointValueStorage secondaryValue; + // Represents either "lastValue" for double/long metric types when delta or pointer to buckets when histogram + private MetricPointSecondaryValueStorage secondaryValue; internal MetricPoint( AggregationType aggType, @@ -51,15 +50,11 @@ internal MetricPoint( if (this.aggType == AggregationType.Histogram) { - this.histogramBuckets = new HistogramBuckets(histogramBounds); + this.secondaryValue.HistogramBuckets = new HistogramBuckets(histogramBounds); } else if (this.aggType == AggregationType.HistogramSumCount) { - this.histogramBuckets = new HistogramBuckets(null); - } - else - { - this.histogramBuckets = null; + this.secondaryValue.HistogramBuckets = new HistogramBuckets(null); } } @@ -92,7 +87,7 @@ public long GetSumLong() { if (this.aggType == AggregationType.LongSumIncomingDelta || this.aggType == AggregationType.LongSumIncomingCumulative) { - return this.primaryValue.SnapshotAsLong; + return this.primaryValue.Snapshot.AsLong; } else { @@ -104,7 +99,7 @@ public double GetSumDouble() { if (this.aggType == AggregationType.DoubleSumIncomingDelta || this.aggType == AggregationType.DoubleSumIncomingCumulative) { - return this.primaryValue.SnapshotAsDouble; + return this.primaryValue.Snapshot.AsDouble; } else { @@ -116,7 +111,7 @@ public long GetGaugeLastValueLong() { if (this.aggType == AggregationType.LongGauge) { - return this.primaryValue.SnapshotAsLong; + return this.primaryValue.Snapshot.AsLong; } else { @@ -128,7 +123,7 @@ public double GetGaugeLastValueDouble() { if (this.aggType == AggregationType.DoubleGauge) { - return this.primaryValue.SnapshotAsDouble; + return this.primaryValue.Snapshot.AsDouble; } else { @@ -140,7 +135,7 @@ public long GetHistogramCount() { if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) { - return this.primaryValue.SnapshotAsLong; + return this.primaryValue.Snapshot.AsLong; } else { @@ -152,7 +147,7 @@ public double GetHistogramSum() { if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) { - return this.secondaryValue.SnapshotAsDouble; + return this.secondaryValue.HistogramBuckets.Sum.Snapshot.AsDouble; } else { @@ -164,7 +159,7 @@ public HistogramBuckets GetHistogramBuckets() { if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) { - return this.histogramBuckets; + return this.secondaryValue.HistogramBuckets; } else { @@ -178,19 +173,19 @@ internal void Update(long number) { case AggregationType.LongSumIncomingDelta: { - Interlocked.Add(ref this.primaryValue.CurrentAsLong, number); + Interlocked.Add(ref this.primaryValue.Current.AsLong, number); break; } case AggregationType.LongSumIncomingCumulative: { - Interlocked.Exchange(ref this.primaryValue.CurrentAsLong, number); + Interlocked.Exchange(ref this.primaryValue.Current.AsLong, number); break; } case AggregationType.LongGauge: { - Interlocked.Exchange(ref this.primaryValue.CurrentAsLong, number); + Interlocked.Exchange(ref this.primaryValue.Current.AsLong, number); break; } @@ -225,42 +220,44 @@ internal void Update(double number) double initValue, newValue; do { - initValue = this.primaryValue.CurrentAsDouble; + initValue = this.primaryValue.Current.AsDouble; newValue = initValue + number; } - while (initValue != Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, newValue, initValue)); + while (initValue != Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, newValue, initValue)); break; } case AggregationType.DoubleSumIncomingCumulative: { - Interlocked.Exchange(ref this.primaryValue.CurrentAsDouble, number); + Interlocked.Exchange(ref this.primaryValue.Current.AsDouble, number); break; } case AggregationType.DoubleGauge: { - Interlocked.Exchange(ref this.primaryValue.CurrentAsDouble, number); + Interlocked.Exchange(ref this.primaryValue.Current.AsDouble, number); break; } case AggregationType.Histogram: { + var histogramBuckets = this.secondaryValue.HistogramBuckets; + int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) + for (i = 0; i < histogramBuckets.ExplicitBounds.Length; i++) { // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) + if (number <= histogramBuckets.ExplicitBounds[i]) { break; } } - lock (this.histogramBuckets.LockObject) + lock (histogramBuckets.LockObject) { - this.primaryValue.CurrentAsLong++; - this.secondaryValue.CurrentAsDouble += number; - this.histogramBuckets.BucketCounts[i]++; + this.primaryValue.Current.AsLong++; + histogramBuckets.Sum.Current.AsDouble += number; + histogramBuckets.CurrentBucketCounts[i]++; } break; @@ -268,10 +265,12 @@ internal void Update(double number) case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) + var histogramBuckets = this.secondaryValue.HistogramBuckets; + + lock (histogramBuckets.LockObject) { - this.primaryValue.CurrentAsLong++; - this.secondaryValue.CurrentAsDouble += number; + this.primaryValue.Current.AsLong++; + histogramBuckets.Sum.Current.AsDouble += number; } break; @@ -301,21 +300,23 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { - long initValue = Interlocked.Read(ref this.primaryValue.CurrentAsLong); - this.primaryValue.SnapshotAsLong = initValue - this.secondaryValue.CurrentAsLong; - this.secondaryValue.CurrentAsLong = initValue; + MetricPointDeltaState deltaState = this.EnsureDeltaState(); + + long initValue = Interlocked.Read(ref this.primaryValue.Current.AsLong); + this.primaryValue.Snapshot.AsLong = initValue - deltaState.LastValue.AsLong; + deltaState.LastValue.AsLong = initValue; this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (initValue != Interlocked.Read(ref this.primaryValue.CurrentAsLong)) + if (initValue != Interlocked.Read(ref this.primaryValue.Current.AsLong)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } } else { - this.primaryValue.SnapshotAsLong = Interlocked.Read(ref this.primaryValue.CurrentAsLong); + this.primaryValue.Snapshot.AsLong = Interlocked.Read(ref this.primaryValue.Current.AsLong); } break; @@ -326,19 +327,21 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { + MetricPointDeltaState deltaState = this.EnsureDeltaState(); + // TODO: // Is this thread-safe way to read double? // As long as the value is not -ve infinity, // the exchange (to 0.0) will never occur, // but we get the original value atomically. - double initValue = Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity); - this.primaryValue.SnapshotAsDouble = initValue - this.secondaryValue.CurrentAsDouble; - this.secondaryValue.CurrentAsDouble = initValue; + double initValue = Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity); + this.primaryValue.Snapshot.AsDouble = initValue - deltaState.LastValue.AsDouble; + deltaState.LastValue.AsDouble = initValue; this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (initValue != Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity)) + if (initValue != Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -350,7 +353,7 @@ internal void TakeSnapshot(bool outputDelta) // As long as the value is not -ve infinity, // the exchange (to 0.0) will never occur, // but we get the original value atomically. - this.primaryValue.SnapshotAsDouble = Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity); + this.primaryValue.Snapshot.AsDouble = Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity); } break; @@ -358,12 +361,12 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.LongGauge: { - this.primaryValue.SnapshotAsLong = Interlocked.Read(ref this.primaryValue.CurrentAsLong); + this.primaryValue.Snapshot.AsLong = Interlocked.Read(ref this.primaryValue.Current.AsLong); this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (this.primaryValue.SnapshotAsLong != Interlocked.Read(ref this.primaryValue.CurrentAsLong)) + if (this.primaryValue.Snapshot.AsLong != Interlocked.Read(ref this.primaryValue.Current.AsLong)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -378,12 +381,12 @@ internal void TakeSnapshot(bool outputDelta) // As long as the value is not -ve infinity, // the exchange (to 0.0) will never occur, // but we get the original value atomically. - this.primaryValue.SnapshotAsDouble = Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity); + this.primaryValue.Snapshot.AsDouble = Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity); this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (this.primaryValue.SnapshotAsDouble != Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity)) + if (this.primaryValue.Snapshot.AsDouble != Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -393,22 +396,24 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - lock (this.histogramBuckets.LockObject) + var histogramBuckets = this.secondaryValue.HistogramBuckets; + + lock (histogramBuckets.LockObject) { - this.primaryValue.SnapshotAsLong = this.primaryValue.CurrentAsLong; - this.secondaryValue.SnapshotAsDouble = this.secondaryValue.CurrentAsDouble; + this.primaryValue.Snapshot.AsLong = this.primaryValue.Current.AsLong; + histogramBuckets.Sum.Snapshot.AsDouble = histogramBuckets.Sum.Current.AsDouble; if (outputDelta) { - this.primaryValue.CurrentAsLong = 0; - this.secondaryValue.CurrentAsDouble = 0; + this.primaryValue.Current.AsLong = 0; + histogramBuckets.Sum.Current.AsDouble = 0; } - for (int i = 0; i < this.histogramBuckets.BucketCounts.Length; i++) + for (int i = 0; i < histogramBuckets.CurrentBucketCounts.Length; i++) { - this.histogramBuckets.AggregatedBucketCounts[i] = this.histogramBuckets.BucketCounts[i]; + histogramBuckets.SnapshotBucketCounts[i] = histogramBuckets.CurrentBucketCounts[i]; if (outputDelta) { - this.histogramBuckets.BucketCounts[i] = 0; + histogramBuckets.CurrentBucketCounts[i] = 0; } } @@ -420,14 +425,16 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) + var histogramBuckets = this.secondaryValue.HistogramBuckets; + + lock (histogramBuckets.LockObject) { - this.primaryValue.SnapshotAsLong = this.primaryValue.CurrentAsLong; - this.secondaryValue.SnapshotAsDouble = this.secondaryValue.CurrentAsDouble; + this.primaryValue.Snapshot.AsLong = this.primaryValue.Current.AsLong; + histogramBuckets.Sum.Snapshot.AsDouble = histogramBuckets.Sum.Current.AsDouble; if (outputDelta) { - this.primaryValue.CurrentAsLong = 0; - this.secondaryValue.CurrentAsDouble = 0; + this.primaryValue.Current.AsLong = 0; + histogramBuckets.Sum.Current.AsDouble = 0; } this.MetricPointStatus = MetricPointStatus.NoCollectPending; @@ -437,5 +444,21 @@ internal void TakeSnapshot(bool outputDelta) } } } + + private MetricPointDeltaState EnsureDeltaState() + { + var deltaState = this.secondaryValue.DeltaState; + if (deltaState == null) + { + deltaState = new(); + var existing = Interlocked.CompareExchange(ref this.secondaryValue.DeltaState, deltaState, null); + if (existing != null) + { + return existing; + } + } + + return deltaState; + } } } diff --git a/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs b/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs similarity index 53% rename from src/OpenTelemetry/Metrics/MetricPointValueStorage.cs rename to src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs index bed3a431d51..8e80c1c55a4 100644 --- a/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs +++ b/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,19 +18,38 @@ namespace OpenTelemetry.Metrics { + [StructLayout(LayoutKind.Explicit)] + internal struct MetricPointPrimaryValueStorage + { + [FieldOffset(0)] + public MetricPointValueStorage Current; + + [FieldOffset(8)] + public MetricPointValueStorage Snapshot; + } + [StructLayout(LayoutKind.Explicit)] internal struct MetricPointValueStorage { [FieldOffset(0)] - public long CurrentAsLong; + public long AsLong; [FieldOffset(0)] - public double CurrentAsDouble; + public double AsDouble; + } - [FieldOffset(8)] - public long SnapshotAsLong; + [StructLayout(LayoutKind.Explicit)] + internal struct MetricPointSecondaryValueStorage + { + [FieldOffset(0)] + public MetricPointDeltaState DeltaState; - [FieldOffset(8)] - public double SnapshotAsDouble; + [FieldOffset(0)] + public HistogramBuckets HistogramBuckets; + } + + internal sealed class MetricPointDeltaState + { + public MetricPointValueStorage LastValue; } } From a8bcc9b0faf1434b0360d122e1a83a0fd0b0c7a3 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 1 Dec 2021 11:36:47 -0800 Subject: [PATCH 2/5] Smaller storage size for MetricPointStatus. --- src/OpenTelemetry/Metrics/MetricPointStatus.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/MetricPointStatus.cs b/src/OpenTelemetry/Metrics/MetricPointStatus.cs index 0ecd2a0c062..d24a46a8cc9 100644 --- a/src/OpenTelemetry/Metrics/MetricPointStatus.cs +++ b/src/OpenTelemetry/Metrics/MetricPointStatus.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum MetricPointStatus + internal enum MetricPointStatus : byte { /// /// This status is applied to s with status after a Collect. From 9cc8d8370ab114ad1bb8cbe81e8b090d68f5b95c Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 1 Dec 2021 20:54:22 -0800 Subject: [PATCH 3/5] Cleanup and xml comments. --- src/OpenTelemetry/Metrics/AggregationType.cs | 2 +- src/OpenTelemetry/Metrics/HistogramBucket.cs | 10 + src/OpenTelemetry/Metrics/HistogramBuckets.cs | 42 ++- src/OpenTelemetry/Metrics/Metric.cs | 6 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 290 ++++++++++-------- .../Metrics/MetricPointStatus.cs | 2 +- ...eStorage.cs => MetricPointValueStorage.cs} | 27 +- 7 files changed, 218 insertions(+), 161 deletions(-) rename src/OpenTelemetry/Metrics/{MetricPointPrimaryValueStorage.cs => MetricPointValueStorage.cs} (55%) diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index 2ee2b6d1e0e..bd87c9e5b4f 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum AggregationType : sbyte + internal enum AggregationType { /// /// Invalid. diff --git a/src/OpenTelemetry/Metrics/HistogramBucket.cs b/src/OpenTelemetry/Metrics/HistogramBucket.cs index 646d3a2964b..fc876fa4cf1 100644 --- a/src/OpenTelemetry/Metrics/HistogramBucket.cs +++ b/src/OpenTelemetry/Metrics/HistogramBucket.cs @@ -16,6 +16,9 @@ namespace OpenTelemetry.Metrics { + /// + /// Represents a bucket in the histogram metric type. + /// public readonly struct HistogramBucket { internal HistogramBucket(double explicitBound, long bucketCount) @@ -24,8 +27,15 @@ internal HistogramBucket(double explicitBound, long bucketCount) this.BucketCount = bucketCount; } + /// + /// Gets the configured bounds for the bucket or for the catch-all bucket. + /// public double ExplicitBound { get; } + /// + /// Gets the count of items in the bucket. + /// public long BucketCount { get; } } } diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index a5640e85926..a68033d4300 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -16,28 +16,37 @@ namespace OpenTelemetry.Metrics { + /// + /// A collection of s associated with a histogram metric type. + /// + // Note: Does not implement IEnumerable<> to prevent accidental boxing. public class HistogramBuckets { - internal readonly long[] CurrentBucketCounts; + internal readonly double[] ExplicitBounds; - internal readonly long[] SnapshotBucketCounts; + internal readonly long[] RunningBucketCounts; - internal readonly double[] ExplicitBounds; + internal readonly long[] SnapshotBucketCounts; - internal readonly object LockObject; + internal double RunningSum; - internal MetricPointPrimaryValueStorage Sum; + internal double SnapshotSum; - internal HistogramBuckets(double[] histogramBounds) + internal HistogramBuckets(double[] explicitBounds) { - this.ExplicitBounds = histogramBounds; - this.CurrentBucketCounts = histogramBounds != null ? new long[histogramBounds.Length + 1] : null; - this.SnapshotBucketCounts = histogramBounds != null ? new long[histogramBounds.Length + 1] : null; - this.LockObject = new object(); + this.ExplicitBounds = explicitBounds; + this.RunningBucketCounts = explicitBounds != null ? new long[explicitBounds.Length + 1] : null; + this.SnapshotBucketCounts = explicitBounds != null ? new long[explicitBounds.Length + 1] : new long[0]; } + internal object LockObject => this.SnapshotBucketCounts; + public Enumerator GetEnumerator() => new(this); + /// + /// Enumerates the elements of a . + /// + // Note: Does not implement IEnumerator<> to prevent accidental boxing. public struct Enumerator { private readonly int numberOfBuckets; @@ -49,11 +58,22 @@ internal Enumerator(HistogramBuckets histogramMeasurements) this.histogramMeasurements = histogramMeasurements; this.index = 0; this.Current = default; - this.numberOfBuckets = histogramMeasurements.SnapshotBucketCounts == null ? 0 : histogramMeasurements.SnapshotBucketCounts.Length; + this.numberOfBuckets = histogramMeasurements.SnapshotBucketCounts.Length; } + /// + /// Gets the at the current position of the enumerator. + /// public HistogramBucket Current { get; private set; } + /// + /// Advances the enumerator to the next element of the . + /// + /// if the enumerator was + /// successfully advanced to the next element; if the enumerator has passed the end of the + /// collection. public bool MoveNext() { if (this.index < this.numberOfBuckets) diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index e3981667564..983976d5e9e 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -23,7 +23,8 @@ namespace OpenTelemetry.Metrics public sealed class Metric { internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; - private AggregatorStore aggStore; + + private readonly AggregatorStore aggStore; internal Metric( Instrument instrument, @@ -38,7 +39,8 @@ internal Metric( this.Description = metricDescription ?? string.Empty; this.Unit = instrument.Unit ?? string.Empty; this.Meter = instrument.Meter; - AggregationType aggType = default; + + AggregationType aggType; if (instrument.GetType() == typeof(ObservableCounter) || instrument.GetType() == typeof(ObservableCounter) || instrument.GetType() == typeof(ObservableCounter) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 5eb57c540ff..eb42decc17c 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -21,48 +21,68 @@ namespace OpenTelemetry.Metrics { + /// + /// Stores details about a metric data point. + /// public struct MetricPoint { private readonly AggregationType aggType; + private readonly HistogramBuckets histogramBuckets; + + // Represents either "value" for double/long metric types or "count" when histogram + private MetricPointValueStorage runningValue; + // Represents either "value" for double/long metric types or "count" when histogram - private MetricPointPrimaryValueStorage primaryValue; + private MetricPointValueStorage snapshotValue; - // Represents either "lastValue" for double/long metric types when delta or pointer to buckets when histogram - private MetricPointSecondaryValueStorage secondaryValue; + private MetricPointValueStorage deltaLastValue; internal MetricPoint( AggregationType aggType, DateTimeOffset startTime, string[] keys, object[] values, - double[] histogramBounds) + double[] histogramExplicitBounds) { Debug.Assert((keys?.Length ?? 0) == (values?.Length ?? 0), "Key and value array lengths did not match."); + Debug.Assert(histogramExplicitBounds != null, "Histogram explicit Bounds was null."); this.aggType = aggType; this.StartTime = startTime; this.Tags = new ReadOnlyTagCollection(keys, values); this.EndTime = default; - this.primaryValue = default; - this.secondaryValue = default; + this.runningValue = default; + this.snapshotValue = default; + this.deltaLastValue = default; this.MetricPointStatus = MetricPointStatus.NoCollectPending; if (this.aggType == AggregationType.Histogram) { - this.secondaryValue.HistogramBuckets = new HistogramBuckets(histogramBounds); + this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); } else if (this.aggType == AggregationType.HistogramSumCount) { - this.secondaryValue.HistogramBuckets = new HistogramBuckets(null); + this.histogramBuckets = new HistogramBuckets(null); + } + else + { + this.histogramBuckets = null; } } /// /// Gets the tags associated with the metric point. /// - public ReadOnlyTagCollection Tags { get; } + public ReadOnlyTagCollection Tags + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + /// + /// Gets the start time associated with the metric point. + /// public DateTimeOffset StartTime { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -72,6 +92,9 @@ public DateTimeOffset StartTime internal set; } + /// + /// Gets the end time associated with the metric point. + /// public DateTimeOffset EndTime { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -81,90 +104,139 @@ public DateTimeOffset EndTime internal set; } - internal MetricPointStatus MetricPointStatus { get; private set; } + internal MetricPointStatus MetricPointStatus + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private set; + } + /// + /// Gets the sum long value associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Long sum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public long GetSumLong() { - if (this.aggType == AggregationType.LongSumIncomingDelta || this.aggType == AggregationType.LongSumIncomingCumulative) + if (this.aggType != AggregationType.LongSumIncomingDelta && this.aggType != AggregationType.LongSumIncomingCumulative) { - return this.primaryValue.Snapshot.AsLong; - } - else - { - throw new NotSupportedException($"{nameof(this.GetSumLong)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetSumLong)); } + + return this.snapshotValue.AsLong; } + /// + /// Gets the sum double value associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Double sum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetSumDouble() { - if (this.aggType == AggregationType.DoubleSumIncomingDelta || this.aggType == AggregationType.DoubleSumIncomingCumulative) + if (this.aggType != AggregationType.DoubleSumIncomingDelta && this.aggType != AggregationType.DoubleSumIncomingCumulative) { - return this.primaryValue.Snapshot.AsDouble; - } - else - { - throw new NotSupportedException($"{nameof(this.GetSumDouble)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetSumDouble)); } + + return this.snapshotValue.AsDouble; } + /// + /// Gets the last long value of the gauge associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Long gauge value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public long GetGaugeLastValueLong() { - if (this.aggType == AggregationType.LongGauge) + if (this.aggType != AggregationType.LongGauge) { - return this.primaryValue.Snapshot.AsLong; - } - else - { - throw new NotSupportedException($"{nameof(this.GetGaugeLastValueLong)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetGaugeLastValueLong)); } + + return this.snapshotValue.AsLong; } + /// + /// Gets the last double value of the gauge associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Double gauge value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetGaugeLastValueDouble() { - if (this.aggType == AggregationType.DoubleGauge) + if (this.aggType != AggregationType.DoubleGauge) { - return this.primaryValue.Snapshot.AsDouble; - } - else - { - throw new NotSupportedException($"{nameof(this.GetGaugeLastValueDouble)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetGaugeLastValueDouble)); } + + return this.snapshotValue.AsDouble; } + /// + /// Gets the count value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Count value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public long GetHistogramCount() { - if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) { - return this.primaryValue.Snapshot.AsLong; - } - else - { - throw new NotSupportedException($"{nameof(this.GetHistogramCount)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramCount)); } + + return this.snapshotValue.AsLong; } + /// + /// Gets the sum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Sum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetHistogramSum() { - if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) { - return this.secondaryValue.HistogramBuckets.Sum.Snapshot.AsDouble; - } - else - { - throw new NotSupportedException($"{nameof(this.GetHistogramSum)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramSum)); } + + return this.histogramBuckets.SnapshotSum; } + /// + /// Gets the buckets of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public HistogramBuckets GetHistogramBuckets() { - if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) { - return this.secondaryValue.HistogramBuckets; - } - else - { - throw new NotSupportedException($"{nameof(this.GetHistogramBuckets)} is not supported for this metric type."); + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramBuckets)); } + + return this.histogramBuckets; } internal void Update(long number) @@ -173,19 +245,19 @@ internal void Update(long number) { case AggregationType.LongSumIncomingDelta: { - Interlocked.Add(ref this.primaryValue.Current.AsLong, number); + Interlocked.Add(ref this.runningValue.AsLong, number); break; } case AggregationType.LongSumIncomingCumulative: { - Interlocked.Exchange(ref this.primaryValue.Current.AsLong, number); + Interlocked.Exchange(ref this.runningValue.AsLong, number); break; } case AggregationType.LongGauge: { - Interlocked.Exchange(ref this.primaryValue.Current.AsLong, number); + Interlocked.Exchange(ref this.runningValue.AsLong, number); break; } @@ -220,44 +292,42 @@ internal void Update(double number) double initValue, newValue; do { - initValue = this.primaryValue.Current.AsDouble; + initValue = this.runningValue.AsDouble; newValue = initValue + number; } - while (initValue != Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, newValue, initValue)); + while (initValue != Interlocked.CompareExchange(ref this.runningValue.AsDouble, newValue, initValue)); break; } case AggregationType.DoubleSumIncomingCumulative: { - Interlocked.Exchange(ref this.primaryValue.Current.AsDouble, number); + Interlocked.Exchange(ref this.runningValue.AsDouble, number); break; } case AggregationType.DoubleGauge: { - Interlocked.Exchange(ref this.primaryValue.Current.AsDouble, number); + Interlocked.Exchange(ref this.runningValue.AsDouble, number); break; } case AggregationType.Histogram: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - int i; - for (i = 0; i < histogramBuckets.ExplicitBounds.Length; i++) + for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) { // Upper bound is inclusive - if (number <= histogramBuckets.ExplicitBounds[i]) + if (number <= this.histogramBuckets.ExplicitBounds[i]) { break; } } - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { - this.primaryValue.Current.AsLong++; - histogramBuckets.Sum.Current.AsDouble += number; - histogramBuckets.CurrentBucketCounts[i]++; + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + this.histogramBuckets.RunningBucketCounts[i]++; } break; @@ -265,12 +335,10 @@ internal void Update(double number) case AggregationType.HistogramSumCount: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { - this.primaryValue.Current.AsLong++; - histogramBuckets.Sum.Current.AsDouble += number; + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; } break; @@ -300,23 +368,21 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { - MetricPointDeltaState deltaState = this.EnsureDeltaState(); - - long initValue = Interlocked.Read(ref this.primaryValue.Current.AsLong); - this.primaryValue.Snapshot.AsLong = initValue - deltaState.LastValue.AsLong; - deltaState.LastValue.AsLong = initValue; + long initValue = Interlocked.Read(ref this.runningValue.AsLong); + this.snapshotValue.AsLong = initValue - this.deltaLastValue.AsLong; + this.deltaLastValue.AsLong = initValue; this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (initValue != Interlocked.Read(ref this.primaryValue.Current.AsLong)) + if (initValue != Interlocked.Read(ref this.runningValue.AsLong)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } } else { - this.primaryValue.Snapshot.AsLong = Interlocked.Read(ref this.primaryValue.Current.AsLong); + this.snapshotValue.AsLong = Interlocked.Read(ref this.runningValue.AsLong); } break; @@ -327,21 +393,19 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { - MetricPointDeltaState deltaState = this.EnsureDeltaState(); - // TODO: // Is this thread-safe way to read double? // As long as the value is not -ve infinity, // the exchange (to 0.0) will never occur, // but we get the original value atomically. - double initValue = Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity); - this.primaryValue.Snapshot.AsDouble = initValue - deltaState.LastValue.AsDouble; - deltaState.LastValue.AsDouble = initValue; + double initValue = Interlocked.CompareExchange(ref this.runningValue.AsDouble, 0.0, double.NegativeInfinity); + this.snapshotValue.AsDouble = initValue - this.deltaLastValue.AsDouble; + this.deltaLastValue.AsDouble = initValue; this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (initValue != Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity)) + if (initValue != Interlocked.CompareExchange(ref this.runningValue.AsDouble, 0.0, double.NegativeInfinity)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -353,7 +417,7 @@ internal void TakeSnapshot(bool outputDelta) // As long as the value is not -ve infinity, // the exchange (to 0.0) will never occur, // but we get the original value atomically. - this.primaryValue.Snapshot.AsDouble = Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity); + this.snapshotValue.AsDouble = Interlocked.CompareExchange(ref this.runningValue.AsDouble, 0.0, double.NegativeInfinity); } break; @@ -361,12 +425,12 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.LongGauge: { - this.primaryValue.Snapshot.AsLong = Interlocked.Read(ref this.primaryValue.Current.AsLong); + this.snapshotValue.AsLong = Interlocked.Read(ref this.runningValue.AsLong); this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (this.primaryValue.Snapshot.AsLong != Interlocked.Read(ref this.primaryValue.Current.AsLong)) + if (this.snapshotValue.AsLong != Interlocked.Read(ref this.runningValue.AsLong)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -381,12 +445,12 @@ internal void TakeSnapshot(bool outputDelta) // As long as the value is not -ve infinity, // the exchange (to 0.0) will never occur, // but we get the original value atomically. - this.primaryValue.Snapshot.AsDouble = Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity); + this.snapshotValue.AsDouble = Interlocked.CompareExchange(ref this.runningValue.AsDouble, 0.0, double.NegativeInfinity); this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (this.primaryValue.Snapshot.AsDouble != Interlocked.CompareExchange(ref this.primaryValue.Current.AsDouble, 0.0, double.NegativeInfinity)) + if (this.snapshotValue.AsDouble != Interlocked.CompareExchange(ref this.runningValue.AsDouble, 0.0, double.NegativeInfinity)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -396,24 +460,22 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { - this.primaryValue.Snapshot.AsLong = this.primaryValue.Current.AsLong; - histogramBuckets.Sum.Snapshot.AsDouble = histogramBuckets.Sum.Current.AsDouble; + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; if (outputDelta) { - this.primaryValue.Current.AsLong = 0; - histogramBuckets.Sum.Current.AsDouble = 0; + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; } - for (int i = 0; i < histogramBuckets.CurrentBucketCounts.Length; i++) + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) { - histogramBuckets.SnapshotBucketCounts[i] = histogramBuckets.CurrentBucketCounts[i]; + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; if (outputDelta) { - histogramBuckets.CurrentBucketCounts[i] = 0; + this.histogramBuckets.RunningBucketCounts[i] = 0; } } @@ -425,16 +487,14 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.HistogramSumCount: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { - this.primaryValue.Snapshot.AsLong = this.primaryValue.Current.AsLong; - histogramBuckets.Sum.Snapshot.AsDouble = histogramBuckets.Sum.Current.AsDouble; + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; if (outputDelta) { - this.primaryValue.Current.AsLong = 0; - histogramBuckets.Sum.Current.AsDouble = 0; + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; } this.MetricPointStatus = MetricPointStatus.NoCollectPending; @@ -445,20 +505,10 @@ internal void TakeSnapshot(bool outputDelta) } } - private MetricPointDeltaState EnsureDeltaState() + [MethodImpl(MethodImplOptions.NoInlining)] + private void ThrowNotSupportedMetricTypeException(string methodName) { - var deltaState = this.secondaryValue.DeltaState; - if (deltaState == null) - { - deltaState = new(); - var existing = Interlocked.CompareExchange(ref this.secondaryValue.DeltaState, deltaState, null); - if (existing != null) - { - return existing; - } - } - - return deltaState; + throw new NotSupportedException($"{methodName} is not supported for this metric type."); } } } diff --git a/src/OpenTelemetry/Metrics/MetricPointStatus.cs b/src/OpenTelemetry/Metrics/MetricPointStatus.cs index d24a46a8cc9..0ecd2a0c062 100644 --- a/src/OpenTelemetry/Metrics/MetricPointStatus.cs +++ b/src/OpenTelemetry/Metrics/MetricPointStatus.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum MetricPointStatus : byte + internal enum MetricPointStatus { /// /// This status is applied to s with status after a Collect. diff --git a/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs b/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs similarity index 55% rename from src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs rename to src/OpenTelemetry/Metrics/MetricPointValueStorage.cs index 8e80c1c55a4..778e97885bb 100644 --- a/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs +++ b/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,16 +18,6 @@ namespace OpenTelemetry.Metrics { - [StructLayout(LayoutKind.Explicit)] - internal struct MetricPointPrimaryValueStorage - { - [FieldOffset(0)] - public MetricPointValueStorage Current; - - [FieldOffset(8)] - public MetricPointValueStorage Snapshot; - } - [StructLayout(LayoutKind.Explicit)] internal struct MetricPointValueStorage { @@ -37,19 +27,4 @@ internal struct MetricPointValueStorage [FieldOffset(0)] public double AsDouble; } - - [StructLayout(LayoutKind.Explicit)] - internal struct MetricPointSecondaryValueStorage - { - [FieldOffset(0)] - public MetricPointDeltaState DeltaState; - - [FieldOffset(0)] - public HistogramBuckets HistogramBuckets; - } - - internal sealed class MetricPointDeltaState - { - public MetricPointValueStorage LastValue; - } } From e129b15c1732280137bf9ce916b22c195a1e386b Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Thu, 2 Dec 2021 10:19:02 -0800 Subject: [PATCH 4/5] Code review. --- 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 eb42decc17c..e91c1253ace 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -30,7 +30,7 @@ public struct MetricPoint private readonly HistogramBuckets histogramBuckets; - // Represents either "value" for double/long metric types or "count" when histogram + // Represents temporality adjusted "value" for double/long metric types or "count" when histogram private MetricPointValueStorage runningValue; // Represents either "value" for double/long metric types or "count" when histogram From 400fec9209eb81b455b3eff4ad6a39d549987b49 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Tue, 11 Jan 2022 14:41:36 -0800 Subject: [PATCH 5/5] Unit test fix. --- test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index d89b748d582..6656c5b267d 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -777,7 +777,7 @@ private void MultithreadedHistogramTest(long[] expected, T[] values) { foreach (var metricPoint in metric.GetMetricPoints()) { - bucketCounts = metricPoint.GetHistogramBuckets().BucketCounts; + bucketCounts = metricPoint.GetHistogramBuckets().RunningBucketCounts; } } }));