From 401898dd5d9a87e75db1d936108f8ea8cc264e1c Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Sat, 27 Nov 2021 10:49:18 -0800 Subject: [PATCH] Added explicit layout struct MetricPointValueStorage to store values for MetricPoint. --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 8 -- src/OpenTelemetry/Metrics/MetricPoint.cs | 108 ++++++++---------- .../Metrics/MetricPointValueStorage.cs | 36 ++++++ 3 files changed, 85 insertions(+), 67 deletions(-) create mode 100644 src/OpenTelemetry/Metrics/MetricPointValueStorage.cs diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index c37da01f37d..8b4464c2ac4 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -26,14 +26,6 @@ public class HistogramBuckets internal readonly object LockObject; - internal long CountVal; - - internal long Count; - - internal double SumVal; - - internal double Sum; - internal HistogramBuckets(double[] histogramBounds) { this.ExplicitBounds = histogramBounds; diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 754960abf40..ac3e8f04c18 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -27,12 +27,12 @@ public struct MetricPoint private readonly AggregationType aggType; private readonly HistogramBuckets histogramBuckets; - private long longVal; - private long longValue; - private long lastLongSum; - private double doubleVal; - private double doubleValue; - private double lastDoubleSum; + + // Represents either "value" for double/long metric types or "count" when histogram + private MetricPointValueStorage primaryValue; + + // Represents either "lastValue" for double/long metric types when delta or "sum" when histogram + private MetricPointValueStorage secondaryValue; internal MetricPoint( AggregationType aggType, @@ -47,12 +47,8 @@ internal MetricPoint( this.StartTime = startTime; this.Tags = new ReadOnlyTagCollection(keys, values); this.EndTime = default; - this.longValue = default; - this.longVal = default; - this.lastLongSum = default; - this.doubleValue = default; - this.doubleVal = default; - this.lastDoubleSum = default; + this.primaryValue = default; + this.secondaryValue = default; this.MetricPointStatus = MetricPointStatus.NoCollectPending; if (this.aggType == AggregationType.Histogram) @@ -76,21 +72,15 @@ internal MetricPoint( internal MetricPointStatus MetricPointStatus { get; private set; } - public DateTimeOffset GetStartTime() - { - return this.StartTime; - } + public DateTimeOffset GetStartTime() => this.StartTime; - public DateTimeOffset GetEndTime() - { - return this.EndTime; - } + public DateTimeOffset GetEndTime() => this.EndTime; public long GetCounterSumLong() { if (this.aggType == AggregationType.LongSumIncomingDelta || this.aggType == AggregationType.LongSumIncomingCumulative) { - return this.longValue; + return this.primaryValue.SnapshotAsLong; } else { @@ -102,7 +92,7 @@ public double GetCounterSumDouble() { if (this.aggType == AggregationType.DoubleSumIncomingDelta || this.aggType == AggregationType.DoubleSumIncomingCumulative) { - return this.doubleValue; + return this.primaryValue.SnapshotAsDouble; } else { @@ -114,7 +104,7 @@ public long GetGaugeLastValueLong() { if (this.aggType == AggregationType.LongGauge) { - return this.longValue; + return this.primaryValue.SnapshotAsLong; } else { @@ -126,7 +116,7 @@ public double GetGaugeLastValueDouble() { if (this.aggType == AggregationType.DoubleGauge) { - return this.doubleValue; + return this.primaryValue.SnapshotAsDouble; } else { @@ -138,7 +128,7 @@ public long GetHistogramCount() { if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) { - return this.histogramBuckets.Count; + return this.primaryValue.SnapshotAsLong; } else { @@ -150,7 +140,7 @@ public double GetHistogramSum() { if (this.aggType == AggregationType.Histogram || this.aggType == AggregationType.HistogramSumCount) { - return this.histogramBuckets.Sum; + return this.secondaryValue.SnapshotAsDouble; } else { @@ -176,19 +166,19 @@ internal void Update(long number) { case AggregationType.LongSumIncomingDelta: { - Interlocked.Add(ref this.longVal, number); + Interlocked.Add(ref this.primaryValue.CurrentAsLong, number); break; } case AggregationType.LongSumIncomingCumulative: { - Interlocked.Exchange(ref this.longVal, number); + Interlocked.Exchange(ref this.primaryValue.CurrentAsLong, number); break; } case AggregationType.LongGauge: { - Interlocked.Exchange(ref this.longVal, number); + Interlocked.Exchange(ref this.primaryValue.CurrentAsLong, number); break; } @@ -223,22 +213,22 @@ internal void Update(double number) double initValue, newValue; do { - initValue = this.doubleVal; + initValue = this.primaryValue.CurrentAsDouble; newValue = initValue + number; } - while (initValue != Interlocked.CompareExchange(ref this.doubleVal, newValue, initValue)); + while (initValue != Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, newValue, initValue)); break; } case AggregationType.DoubleSumIncomingCumulative: { - Interlocked.Exchange(ref this.doubleVal, number); + Interlocked.Exchange(ref this.primaryValue.CurrentAsDouble, number); break; } case AggregationType.DoubleGauge: { - Interlocked.Exchange(ref this.doubleVal, number); + Interlocked.Exchange(ref this.primaryValue.CurrentAsDouble, number); break; } @@ -256,8 +246,8 @@ internal void Update(double number) lock (this.histogramBuckets.LockObject) { - this.histogramBuckets.CountVal++; - this.histogramBuckets.SumVal += number; + this.primaryValue.CurrentAsLong++; + this.secondaryValue.CurrentAsDouble += number; this.histogramBuckets.BucketCounts[i]++; } @@ -268,8 +258,8 @@ internal void Update(double number) { lock (this.histogramBuckets.LockObject) { - this.histogramBuckets.CountVal++; - this.histogramBuckets.SumVal += number; + this.primaryValue.CurrentAsLong++; + this.secondaryValue.CurrentAsDouble += number; } break; @@ -299,21 +289,21 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { - long initValue = Interlocked.Read(ref this.longVal); - this.longValue = initValue - this.lastLongSum; - this.lastLongSum = initValue; + long initValue = Interlocked.Read(ref this.primaryValue.CurrentAsLong); + this.primaryValue.SnapshotAsLong = initValue - this.secondaryValue.CurrentAsLong; + this.secondaryValue.CurrentAsLong = 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.longVal)) + if (initValue != Interlocked.Read(ref this.primaryValue.CurrentAsLong)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } } else { - this.longValue = Interlocked.Read(ref this.longVal); + this.primaryValue.SnapshotAsLong = Interlocked.Read(ref this.primaryValue.CurrentAsLong); } break; @@ -329,14 +319,14 @@ 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. - double initValue = Interlocked.CompareExchange(ref this.doubleVal, 0.0, double.NegativeInfinity); - this.doubleValue = initValue - this.lastDoubleSum; - this.lastDoubleSum = initValue; + double initValue = Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity); + this.primaryValue.SnapshotAsDouble = initValue - this.secondaryValue.CurrentAsDouble; + this.secondaryValue.CurrentAsDouble = 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.doubleVal, 0.0, double.NegativeInfinity)) + if (initValue != Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -348,7 +338,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.doubleValue = Interlocked.CompareExchange(ref this.doubleVal, 0.0, double.NegativeInfinity); + this.primaryValue.SnapshotAsDouble = Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity); } break; @@ -356,12 +346,12 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.LongGauge: { - this.longValue = Interlocked.Read(ref this.longVal); + this.primaryValue.SnapshotAsLong = Interlocked.Read(ref this.primaryValue.CurrentAsLong); this.MetricPointStatus = MetricPointStatus.NoCollectPending; // Check again if value got updated, if yes reset status. // This ensures no Updates get Lost. - if (this.longValue != Interlocked.Read(ref this.longVal)) + if (this.primaryValue.SnapshotAsLong != Interlocked.Read(ref this.primaryValue.CurrentAsLong)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -376,12 +366,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.doubleValue = Interlocked.CompareExchange(ref this.doubleVal, 0.0, double.NegativeInfinity); + this.primaryValue.SnapshotAsDouble = Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 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.doubleValue != Interlocked.CompareExchange(ref this.doubleVal, 0.0, double.NegativeInfinity)) + if (this.primaryValue.SnapshotAsDouble != Interlocked.CompareExchange(ref this.primaryValue.CurrentAsDouble, 0.0, double.NegativeInfinity)) { this.MetricPointStatus = MetricPointStatus.CollectPending; } @@ -393,12 +383,12 @@ internal void TakeSnapshot(bool outputDelta) { lock (this.histogramBuckets.LockObject) { - this.histogramBuckets.Count = this.histogramBuckets.CountVal; - this.histogramBuckets.Sum = this.histogramBuckets.SumVal; + this.primaryValue.SnapshotAsLong = this.primaryValue.CurrentAsLong; + this.secondaryValue.SnapshotAsDouble = this.secondaryValue.CurrentAsDouble; if (outputDelta) { - this.histogramBuckets.CountVal = 0; - this.histogramBuckets.SumVal = 0; + this.primaryValue.CurrentAsLong = 0; + this.secondaryValue.CurrentAsDouble = 0; } for (int i = 0; i < this.histogramBuckets.BucketCounts.Length; i++) @@ -420,12 +410,12 @@ internal void TakeSnapshot(bool outputDelta) { lock (this.histogramBuckets.LockObject) { - this.histogramBuckets.Count = this.histogramBuckets.CountVal; - this.histogramBuckets.Sum = this.histogramBuckets.SumVal; + this.primaryValue.SnapshotAsLong = this.primaryValue.CurrentAsLong; + this.secondaryValue.SnapshotAsDouble = this.secondaryValue.CurrentAsDouble; if (outputDelta) { - this.histogramBuckets.CountVal = 0; - this.histogramBuckets.SumVal = 0; + this.primaryValue.CurrentAsLong = 0; + this.secondaryValue.CurrentAsDouble = 0; } this.MetricPointStatus = MetricPointStatus.NoCollectPending; diff --git a/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs b/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs new file mode 100644 index 00000000000..bed3a431d51 --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs @@ -0,0 +1,36 @@ +// +// 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.Runtime.InteropServices; + +namespace OpenTelemetry.Metrics +{ + [StructLayout(LayoutKind.Explicit)] + internal struct MetricPointValueStorage + { + [FieldOffset(0)] + public long CurrentAsLong; + + [FieldOffset(0)] + public double CurrentAsDouble; + + [FieldOffset(8)] + public long SnapshotAsLong; + + [FieldOffset(8)] + public double SnapshotAsDouble; + } +}