diff --git a/src/Datadog.Trace/Agent/MovingAverageKeepRateCalculator.cs b/src/Datadog.Trace/Agent/MovingAverageKeepRateCalculator.cs index 55df23eb15d6..d8746a5a169f 100644 --- a/src/Datadog.Trace/Agent/MovingAverageKeepRateCalculator.cs +++ b/src/Datadog.Trace/Agent/MovingAverageKeepRateCalculator.cs @@ -26,7 +26,9 @@ internal class MovingAverageKeepRateCalculator : IKeepRateCalculator private readonly TaskCompletionSource _processExit = new TaskCompletionSource(); private int _index = 0; - private long _totals = 0; + private ulong _sumDrops = 0; + private ulong _sumCreated = 0; + private double _keepRate = 0; private long _latestDrops = 0; private long _latestKeeps = 0; @@ -84,14 +86,8 @@ public void IncrementDrops(int count) /// public double GetKeepRate() { - var totals = Interlocked.Read(ref _totals); - UnpackBits(totals, out var totalDropped, out var totalCreated); - if (totalCreated == 0) - { - return 0; - } - - return 1 - ((double)totalDropped / totalCreated); + // Essentially Interlock.Read(double) + return Volatile.Read(ref _keepRate); } /// @@ -111,21 +107,23 @@ internal void UpdateBucket() var previousDropped = _dropped[index]; var previousCreated = _created[index]; - var latestDropped = Math.Min(Interlocked.Exchange(ref _latestDrops, 0), uint.MaxValue); - var latestCreated = Math.Min(Interlocked.Exchange(ref _latestKeeps, 0) + latestDropped, uint.MaxValue); + // Cap at uint.MaxValue events. Very unlikely to reach this value! + var latestDropped = (uint)Math.Min(Interlocked.Exchange(ref _latestDrops, 0), uint.MaxValue); + var latestCreated = (uint)Math.Min(Interlocked.Exchange(ref _latestKeeps, 0) + latestDropped, uint.MaxValue); - var totals = _totals; - UnpackBits(totals, out var previousTotalDropped, out var previousTotalCreated); + var newSumDropped = _sumDrops - previousDropped + latestDropped; + var newSumCreated = _sumCreated - previousCreated + latestCreated; - var newTotalDropped = (uint)Math.Min(((long)previousTotalDropped) - previousDropped + latestDropped, uint.MaxValue); - var newTotalCreated = (uint)Math.Min(((long)previousTotalCreated) - previousCreated + latestCreated, uint.MaxValue); + var keepRate = newSumCreated == 0 + ? 0 + : 1 - ((double)newSumDropped / newSumCreated); - // Pack the totals into a single value we can read and write atomically - var packedTotal = PackBits(newTotalDropped, newTotalCreated); - Interlocked.Exchange(ref _totals, packedTotal); + Volatile.Write(ref _keepRate, keepRate); - _dropped[index] = (uint)latestDropped; - _created[index] = (uint)latestCreated; + _sumDrops = newSumDropped; + _sumCreated = newSumCreated; + _dropped[index] = latestDropped; + _created[index] = latestCreated; _index = (index + 1) % _windowSize; } @@ -156,20 +154,5 @@ await Task.WhenAny( #endif } } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private long PackBits(uint hits, uint total) - { - long result = hits; - result = result << 32; - return result | (long)total; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UnpackBits(long bits, out uint hits, out uint total) - { - hits = (uint)(bits >> 32); - total = (uint)(bits & 0xffffffffL); - } } }