/// <inheritdoc />
 public IReservoirSnapshot GetSnapshot()
 {
     return(new WavefrontHistogramSnapshot(
                wavefrontHistogram.GetSnapshot(),
                WavefrontHistogramImpl.Serialize(wavefrontHistogram.FlushDistributions())
                ));
 }
        public void TestSnapshot()
        {
            var currentTime = DateTime.UtcNow;

            long clockMillis() => DateTimeUtils.UnixTimeMilliseconds(currentTime);

            var powHistogram           = CreatePowHistogram(clockMillis);
            var rangeHistogram         = CreateRangeHistogram(clockMillis);
            var multiThreadedHistogram = CreateMultiThreadedHistogram(clockMillis);
            var emptyHistogram         = new WavefrontHistogramImpl(clockMillis);

            currentTime = currentTime.AddMinutes(1);

            var powSnapshot           = powHistogram.GetSnapshot();
            var rangeSnapshot         = rangeHistogram.GetSnapshot();
            var multiThreadedSnapshot = multiThreadedHistogram.GetSnapshot();
            var emptySnapshot         = emptyHistogram.GetSnapshot();

            // Test snapshot for the pow histogram

            Assert.Equal(9, powSnapshot.Count);
            Assert.Equal(100000, powSnapshot.Max);
            Assert.Equal(13457.9, powSnapshot.Mean, 1);
            Assert.Equal(0.1, powSnapshot.Min);
            Assert.Equal(7, powSnapshot.Size);
            Assert.Equal(121121.1, powSnapshot.Sum);
            Assert.Equal(
                PowDict.SelectMany(entry => Enumerable.Repeat(entry.Key, entry.Value)),
                powSnapshot.Values
                );
            Assert.Equal(100, powSnapshot.GetValue(0.5d));

            // Test snapshot for the range histogram

            Assert.Equal(1000, rangeSnapshot.Count);
            Assert.Equal(1000, rangeSnapshot.Max);
            Assert.Equal(500.5, rangeSnapshot.Mean);
            Assert.Equal(1, rangeSnapshot.Min);
            Assert.Equal(288.6749902572095, rangeSnapshot.StdDev, 0);
            Assert.Equal(500500, rangeSnapshot.Sum);
            Assert.InRange(rangeSnapshot.GetValue(0.5d), 490.5, 510.5);
            Assert.InRange(rangeSnapshot.GetValue(0.75d), 745.5, 755.5);
            Assert.InRange(rangeSnapshot.GetValue(0.95d), 949, 952);
            Assert.InRange(rangeSnapshot.GetValue(0.98d), 980, 981);
            Assert.InRange(rangeSnapshot.GetValue(0.99d), 990, 991);
            Assert.InRange(rangeSnapshot.GetValue(0.999d), 999, 1000);

            // Test snapshot for multi-threaded histogram

            Assert.Equal(100, multiThreadedSnapshot.Count);
            Assert.Equal(28.86607004772212, multiThreadedSnapshot.StdDev, 0);
            Assert.Equal(5050, multiThreadedSnapshot.Sum);
            Assert.Equal(100, multiThreadedSnapshot.GetValue(0.999d), 1);

            // Test snapshot for empty histogram

            Assert.Equal(0, emptySnapshot.StdDev);
        }
Example #3
0
        private static WavefrontHistogramImpl CreateMultiThreadedHistogram(Func <long> clockMillis)
        {
            var wavefrontHistogram = new WavefrontHistogramImpl(clockMillis);

            // Update the histogram in parallel
            Parallel.For(1, 101, wavefrontHistogram.Update);

            return(wavefrontHistogram);
        }
Example #4
0
        private void WriteHistogram(string context, string name, IDictionary <string, object> data,
                                    MetricTags tags, DateTime timestamp)
        {
            // Report Wavefront Histograms using an API that is specific to Wavefront Histograms.
            if (WavefrontHistogramOptions.IsWavefrontHistogram(tags))
            {
                name = Concat(context, name);

                // Wavefront Histograms are reported as a distribution, so we must extract the
                // distribution from a HistogramValue that is carrying it in a serialized format.
                string keyFieldName   = fields.Histogram[HistogramFields.UserMaxValue];
                string valueFieldName = fields.Histogram[HistogramFields.UserMinValue];

                if (data.ContainsKey(keyFieldName) && data.ContainsKey(valueFieldName))
                {
                    string key   = (string)data[keyFieldName];
                    string value = (string)data[valueFieldName];

                    // Deserialize the distributions into the right format for reporting.
                    var distributions = WavefrontHistogramImpl.Deserialize(
                        new KeyValuePair <string, string>(key, value));

                    foreach (var distribution in distributions)
                    {
                        wavefrontSender.SendDistribution(
                            name,
                            distribution.Centroids,
                            histogramGranularities,
                            distribution.Timestamp,
                            source,
                            FilterTags(tags)
                            );
                    }
                }
            }
            else
            {
                foreach (var field in fields.Histogram)
                {
                    // Do not report non-numerical metrics
                    if (field.Key == HistogramFields.UserLastValue ||
                        field.Key == HistogramFields.UserMaxValue ||
                        field.Key == HistogramFields.UserMinValue)
                    {
                        continue;
                    }

                    if (data.ContainsKey(field.Value))
                    {
                        WriteInternal(context, name, field.Value, data[field.Value], tags,
                                      timestamp);
                    }
                }
            }
        }
Example #5
0
        private static WavefrontHistogramImpl CreateRangeHistogram(Func <long> clockMillis)
        {
            var wavefrontHistogram = new WavefrontHistogramImpl(clockMillis);

            for (int i = 1; i <= 1000; ++i)
            {
                wavefrontHistogram.Update(i);
            }

            return(wavefrontHistogram);
        }
Example #6
0
        private static WavefrontHistogramImpl CreatePowHistogram(Func <long> clockMillis)
        {
            var means  = new List <double>();
            var counts = new List <int>();

            foreach (var entry in PowDict)
            {
                means.Add(entry.Key);
                counts.Add(entry.Value);
            }

            var wavefrontHistogram = new WavefrontHistogramImpl(clockMillis);

            wavefrontHistogram.BulkUpdate(means, counts);

            return(wavefrontHistogram);
        }
Example #7
0
        public void TestFlushDistributions()
        {
            var currentTime = DateTime.UtcNow;

            long clockMillis() => DateTimeUtils.UnixTimeMilliseconds(currentTime);

            var  wavefrontHistogram = CreatePowHistogram(clockMillis);
            long minute0ClockMillis = clockMillis() / 60000 * 60000;

            // Test that nothing in the current minute bin gets flushed
            var distributions = wavefrontHistogram.FlushDistributions();

            Assert.Equal(0, distributions.Count);

            // Test that prior minute bins get flushed
            currentTime = currentTime.AddMinutes(1);
            long minute1ClockMillis = clockMillis() / 60000 * 60000;

            wavefrontHistogram.Update(0.01);

            currentTime = currentTime.AddMinutes(1);

            distributions = wavefrontHistogram.FlushDistributions();
            var actualDict = DistributionsToDictionary(distributions);

            var expectedDict = new Dictionary <long, Dictionary <double, int> > {
                { minute0ClockMillis, new Dictionary <double, int> {
                      { 0.1, 1 }, { 1, 1 }, { 10, 2 }, { 100, 1 }, { 1000, 1 }, { 10000, 2 }, { 100000, 1 }
                  } },
                { minute1ClockMillis, new Dictionary <double, int> {
                      { 0.01, 1 }
                  } }
            };

            Assert.Equal(expectedDict, actualDict);

            // Test serialization
            var serializedPair = WavefrontHistogramImpl.Serialize(distributions);

            string expectedTimestamps = distributions
                                        .Select(distribution => distribution.Timestamp.ToString())
                                        .Aggregate((result, item) => result + ';' + item);

            string expectedCentroids = distributions
                                       .Select(distribution => distribution.Centroids
                                               .Select(centroid => centroid.Key.ToString() + ' ' + centroid.Value)
                                               .Aggregate((result, item) => result + ',' + item))
                                       .Aggregate((result, item) => result + ';' + item);

            Assert.Equal(expectedTimestamps, serializedPair.Key);
            Assert.Equal(expectedCentroids, serializedPair.Value);

            // Test deserialization
            var deserializedDistributions = WavefrontHistogramImpl.Deserialize(serializedPair);

            Assert.Equal(actualDict, DistributionsToDictionary(deserializedDistributions));

            // Test that prior minute bins get cleared
            distributions = wavefrontHistogram.FlushDistributions();
            Assert.Equal(0, distributions.Count);
        }
 /// <summary>
 ///     Initializes a new instance of the <see cref="WavefrontHistogramReservoir"/> class.
 ///     Backed by a <see cref="WavefrontHistogramImpl"/>.
 /// </summary>
 /// <param name="clockMillis">
 ///     A delegate function that simulates a clock for taking timestamps in milliseconds.
 /// </param>
 public WavefrontHistogramReservoir(Func <long> clockMillis)
 {
     wavefrontHistogram = new WavefrontHistogramImpl(clockMillis);
 }
 /// <summary>
 ///     Initializes a new instance of the <see cref="WavefrontHistogramReservoir"/> class.
 ///     Backed by a <see cref="WavefrontHistogramImpl"/>.
 /// </summary>
 public WavefrontHistogramReservoir()
 {
     wavefrontHistogram = new WavefrontHistogramImpl();
 }