mirror of https://github.com/prometheus/prometheus
promql: make avg_over_time faster and more precise
Same idea as for the avg aggregator before: Most of the time, there is no overflow, so we don't have to revert to the more expensive and less precise incremental calculation of the mean value. Signed-off-by: beorn7 <beorn@grafana.com>pull/14413/head
parent
3a908d8e08
commit
cff0429b1a
|
@ -573,9 +573,28 @@ func funcAvgOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||||
return vec, nil
|
return vec, nil
|
||||||
}
|
}
|
||||||
return aggrOverTime(vals, enh, func(s Series) float64 {
|
return aggrOverTime(vals, enh, func(s Series) float64 {
|
||||||
var mean, count, c float64
|
var (
|
||||||
|
sum, mean, count, kahanC float64
|
||||||
|
incrementalMean bool
|
||||||
|
)
|
||||||
for _, f := range s.Floats {
|
for _, f := range s.Floats {
|
||||||
count++
|
count++
|
||||||
|
if !incrementalMean {
|
||||||
|
newSum, newC := kahanSumInc(f.F, sum, kahanC)
|
||||||
|
// Perform regular mean calculation as long as
|
||||||
|
// the sum doesn't overflow and (in any case)
|
||||||
|
// for the first iteration (even if we start
|
||||||
|
// with ±Inf) to not run into division-by-zero
|
||||||
|
// problems below.
|
||||||
|
if count == 1 || !math.IsInf(newSum, 0) {
|
||||||
|
sum, kahanC = newSum, newC
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Handle overflow by reverting to incremental calculation of the mean value.
|
||||||
|
incrementalMean = true
|
||||||
|
mean = sum / (count - 1)
|
||||||
|
kahanC /= count - 1
|
||||||
|
}
|
||||||
if math.IsInf(mean, 0) {
|
if math.IsInf(mean, 0) {
|
||||||
if math.IsInf(f.F, 0) && (mean > 0) == (f.F > 0) {
|
if math.IsInf(f.F, 0) && (mean > 0) == (f.F > 0) {
|
||||||
// The `mean` and `f.F` values are `Inf` of the same sign. They
|
// The `mean` and `f.F` values are `Inf` of the same sign. They
|
||||||
|
@ -593,14 +612,13 @@ func funcAvgOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
correctedMean := mean + c
|
correctedMean := mean + kahanC
|
||||||
mean, c = kahanSumInc(f.F/count-correctedMean/count, mean, c)
|
mean, kahanC = kahanSumInc(f.F/count-correctedMean/count, mean, kahanC)
|
||||||
}
|
}
|
||||||
|
if incrementalMean {
|
||||||
if math.IsInf(mean, 0) {
|
return mean + kahanC
|
||||||
return mean
|
|
||||||
}
|
}
|
||||||
return mean + c
|
return (sum + kahanC) / count
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -737,7 +737,6 @@ eval instant at 1m avg_over_time(metric6c[1m])
|
||||||
eval instant at 1m sum_over_time(metric6c[1m])/count_over_time(metric6c[1m])
|
eval instant at 1m sum_over_time(metric6c[1m])/count_over_time(metric6c[1m])
|
||||||
{} NaN
|
{} NaN
|
||||||
|
|
||||||
|
|
||||||
eval instant at 1m avg_over_time(metric7[1m])
|
eval instant at 1m avg_over_time(metric7[1m])
|
||||||
{} NaN
|
{} NaN
|
||||||
|
|
||||||
|
@ -772,6 +771,9 @@ load 10s
|
||||||
eval instant at 1m sum_over_time(metric[1m])
|
eval instant at 1m sum_over_time(metric[1m])
|
||||||
{} 2
|
{} 2
|
||||||
|
|
||||||
|
eval instant at 1m avg_over_time(metric[1m])
|
||||||
|
{} 0.5
|
||||||
|
|
||||||
# Tests for stddev_over_time and stdvar_over_time.
|
# Tests for stddev_over_time and stdvar_over_time.
|
||||||
clear
|
clear
|
||||||
load 10s
|
load 10s
|
||||||
|
|
Loading…
Reference in New Issue