Base2ExponentialHistogramAggregator
using System.Runtime.CompilerServices;
namespace System.Diagnostics.Metrics
{
internal sealed class Base2ExponentialHistogramAggregator : Aggregator
{
private const int MinScale = -11;
private const int MaxScale = 20;
private const int MinBuckets = 2;
private const long FractionMask = 4503599627370495;
private const long ExponentMask = 9218868437227405312;
private const int FractionWidth = 52;
private int _scale;
private double _maxMeasurement;
private double _minMeasurement;
private double _sum;
private long _count;
private bool _reportDeltas;
private double _scalingFactor;
internal CircularBufferBuckets PositiveBuckets { get; }
internal int Scale {
get {
return _scale;
}
set {
_scale = value;
_scalingFactor = BitConverter.Int64BitsToDouble(1993721221186302 | (1023 + (long)value << 52));
}
}
internal long Count => _count;
internal double Sum => _sum;
internal double MinMeasurement => _minMeasurement;
internal double MaxMeasurement => _maxMeasurement;
internal double ScalingFactor => _scalingFactor;
internal long ZeroCount { get; set; }
private unsafe static ReadOnlySpan<byte> LeadingZeroLookupTable => new ReadOnlySpan<byte>(&global::<PrivateImplementationDetails>.85E702D46B2D96545206C3189AE524100555AAF96DF8EEBDD944CAFE6437ADAB, 256);
public Base2ExponentialHistogramAggregator(int maxBuckets = 160, int scale = 20, bool reportDeltas = false)
{
if (scale < -11 || scale > 20)
throw new ArgumentOutOfRangeException("scale", System.SR.Format(System.SR.InvalidHistogramScale, scale, -11, 20));
if (maxBuckets < 2)
throw new ArgumentOutOfRangeException("maxBuckets", System.SR.Format(System.SR.InvalidHistogramMaxBuckets, maxBuckets, 2));
Scale = scale;
_reportDeltas = reportDeltas;
_minMeasurement = 1.7976931348623157E+308;
_maxMeasurement = -1.7976931348623157E+308;
PositiveBuckets = new CircularBufferBuckets(maxBuckets);
}
public override IAggregationStatistics Collect()
{
lock (this) {
Base2ExponentialHistogramStatistics result = new Base2ExponentialHistogramStatistics(Scale, ZeroCount, _sum, _count, _minMeasurement, _maxMeasurement, PositiveBuckets.ToArray());
if (_reportDeltas) {
_sum = 0;
_minMeasurement = 1.7976931348623157E+308;
_maxMeasurement = -1.7976931348623157E+308;
ZeroCount = 0;
_count = 0;
PositiveBuckets.Clear();
}
return result;
}
}
public override void Update(double measurement)
{
if (IsFinite(measurement)) {
int num = measurement.CompareTo(0);
if (num >= 0) {
lock (this) {
_maxMeasurement = Math.Max(_maxMeasurement, measurement);
_minMeasurement = Math.Min(_minMeasurement, measurement);
_count++;
if (num == 0)
ZeroCount++;
else {
_sum += measurement;
int num2 = MapToIndex(measurement);
int num3 = PositiveBuckets.TryIncrement(num2, 1);
if (num3 != 0) {
PositiveBuckets.ScaleDown(num3);
Scale -= num3;
if (Scale < -11)
Scale = -11;
else if (Scale > 20) {
Scale = 20;
}
num3 = PositiveBuckets.TryIncrement(num2 >> num3, 1);
}
}
}
}
}
}
public int MapToIndex(double value)
{
long num = BitConverter.DoubleToInt64Bits(value);
long num2 = num & 4503599627370495;
if (Scale > 0) {
if (num2 == 0)
return ((int)((num & 9218868437227405312) >> 52) - 1023 << Scale) - 1;
return (int)Math.Ceiling(Math.Log(value) * _scalingFactor) - 1;
}
int num3 = (int)((num & 9218868437227405312) >> 52);
if (num3 == 0)
num3 -= LeadingZero64(num2 - 1) - 12;
else if (num2 == 0) {
num3--;
}
return num3 - 1023 >> -Scale;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsFinite(double value)
{
if (!double.IsInfinity(value))
return !double.IsNaN(value);
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LeadingZero64(long value)
{
int num = (int)(value >> 32);
if (num != 0)
return LeadingZero32(num);
return LeadingZero32((int)value) + 32;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LeadingZero32(int value)
{
short num = (short)(value >> 16);
if (num != 0)
return LeadingZero16(num);
return LeadingZero16((short)value) + 16;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LeadingZero16(short value)
{
byte b = (byte)(value >> 8);
if (b != 0)
return LeadingZero8(b);
return LeadingZero8((byte)value) + 8;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LeadingZero8(byte value)
{
return LeadingZeroLookupTable[value];
}
}
}