computeStats method
Extracts useful statistics out of this timeseries.
See TimeseriesStats for more details.
Implementation
TimeseriesStats computeStats() {
final int finalWarmUpFrameCount = warmUpFrameCount;
assert(finalWarmUpFrameCount >= 0 && finalWarmUpFrameCount < count);
// The first few values we simply discard and never look at. They're from the warm-up phase.
final List<double> warmUpValues = _allValues.sublist(
0,
finalWarmUpFrameCount,
);
// Values we analyze.
final List<double> candidateValues = _allValues.sublist(
finalWarmUpFrameCount,
);
// The average that includes outliers.
final double dirtyAverage = _computeAverage(name, candidateValues);
// The standard deviation that includes outliers.
final double dirtyStandardDeviation =
_computeStandardDeviationForPopulation(name, candidateValues);
// Any value that's higher than this is considered an outlier.
final double outlierCutOff = dirtyAverage + dirtyStandardDeviation;
// Candidates with outliers removed.
final Iterable<double> cleanValues = candidateValues.where(
(double value) => value <= outlierCutOff,
);
// Outlier candidates.
final Iterable<double> outliers = candidateValues.where(
(double value) => value > outlierCutOff,
);
// Final statistics.
final double cleanAverage = _computeAverage(name, cleanValues);
final double standardDeviation = _computeStandardDeviationForPopulation(
name,
cleanValues,
);
final double noise = cleanAverage > 0.0
? standardDeviation / cleanAverage
: 0.0;
// Compute outlier average. If there are no outliers the outlier average is
// the same as clean value average. In other words, in a perfect benchmark
// with no noise the difference between average and outlier average is zero,
// which the best possible outcome. Noise produces a positive difference
// between the two.
final double outlierAverage = outliers.isNotEmpty
? _computeAverage(name, outliers)
: cleanAverage;
// Compute percentile values (e.g. p50, p90, p95).
final Map<double, double> percentiles = computePercentiles(
name,
PercentileMetricComputation.percentilesAsDoubles,
candidateValues,
);
final List<AnnotatedSample> annotatedValues = <AnnotatedSample>[
for (final double warmUpValue in warmUpValues)
AnnotatedSample(
magnitude: warmUpValue,
isOutlier: warmUpValue > outlierCutOff,
isWarmUpValue: true,
),
for (final double candidate in candidateValues)
AnnotatedSample(
magnitude: candidate,
isOutlier: candidate > outlierCutOff,
isWarmUpValue: false,
),
];
return TimeseriesStats(
name: name,
average: cleanAverage,
outlierCutOff: outlierCutOff,
outlierAverage: outlierAverage,
standardDeviation: standardDeviation,
noise: noise,
percentiles: percentiles,
cleanSampleCount: cleanValues.length,
outlierSampleCount: outliers.length,
samples: annotatedValues,
);
}