public static void TryRecycle_PersistentAggregator(IMetricSeriesAggregator accumulatorAggregator) { var startTS = new DateTimeOffset(2017, 9, 25, 17, 0, 0, TimeSpan.FromHours(-8)); var endTS = new DateTimeOffset(2017, 9, 25, 17, 1, 0, TimeSpan.FromHours(-8)); long periodStringDef = (long)(endTS - default(DateTimeOffset)).TotalMilliseconds; long periodStringStart = (long)(endTS - startTS).TotalMilliseconds; { accumulatorAggregator.TrackValue(10); MetricAggregate aggregate = accumulatorAggregator.CreateAggregateUnsafe(endTS); TestUtil.Util.ValidateNumericAggregateValues(aggregate, name: "null", count: 0, sum: 10.0, max: 10.0, min: 10.0, stdDev: 0, timestamp: default(DateTimeOffset), periodMs: periodStringDef, aggKindMoniker: "Microsoft.Azure.Accumulator"); accumulatorAggregator.Reset(startTS, valueFilter: null); accumulatorAggregator.TrackValue(0); accumulatorAggregator.TrackValue(10); accumulatorAggregator.TrackValue(20); aggregate = accumulatorAggregator.CreateAggregateUnsafe(endTS); TestUtil.Util.ValidateNumericAggregateValues(aggregate, name: "null", count: 0, sum: 30.0, max: 30.0, min: 0.0, stdDev: 0, timestamp: startTS, periodMs: periodStringStart, aggKindMoniker: "Microsoft.Azure.Accumulator"); bool canRecycle = accumulatorAggregator.TryRecycle(); Assert.IsFalse(canRecycle); aggregate = accumulatorAggregator.CreateAggregateUnsafe(endTS); TestUtil.Util.ValidateNumericAggregateValues(aggregate, name: "null", count: 2, sum: 30.0, max: 30.0, min: 0.0, stdDev: 5.0, timestamp: startTS, periodMs: periodStringStart, aggKindMoniker: "Microsoft.Azure.Accumulator"); } }
/// <summary> /// The lifetime of an aggragator can easily be a minute or so. So, it is a relatively small object that can easily get into Gen-2 GC heap, /// but then will need to be reclaimed from there relatively quickly. This can lead to a fragmentation of Gen-2 heap. To avoid this we employ /// a simple form of object pooling: Each data series keeps an instance of a past aggregator and tries to reuse it. /// Aggregator implementations which believe that they are too expensive to recycle for this, can opt out of this strategy by returning FALSE from /// their CanRecycle property. /// </summary> /// <param name="aggregationCycleKind">The kind of the metric aggregation cycle.</param> /// <returns>An empty aggregator.</returns> private IMetricSeriesAggregator GetRecycledAggregatorInstance(MetricAggregationCycleKind aggregationCycleKind) { if (this.requiresPersistentAggregator) { return(null); } IMetricSeriesAggregator aggregator = null; switch (aggregationCycleKind) { case CycleKind.Default: aggregator = Interlocked.Exchange(ref this.aggregatorRecycleCacheDefault, null); break; case CycleKind.QuickPulse: aggregator = Interlocked.Exchange(ref this.aggregatorRecycleCacheQuickPulse, null); break; case CycleKind.Custom: aggregator = Interlocked.Exchange(ref this.aggregatorRecycleCacheCustom, null); break; } if (aggregator == null) { return(null); } if (aggregator.TryRecycle()) { return(aggregator); } return(null); }