mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
add helper function to compare native histograms in testing
Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>
This commit is contained in:
parent
8f828d45c1
commit
c7c4a5c347
|
@ -17,12 +17,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/util/almost"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultEpsilon = 0.000001
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FloatHistogram is similar to Histogram but uses float64 for all
|
// FloatHistogram is similar to Histogram but uses float64 for all
|
||||||
|
@ -462,8 +456,8 @@ func (h *FloatHistogram) Equals(h2 *FloatHistogram) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.Schema != h2.Schema ||
|
if h.Schema != h2.Schema ||
|
||||||
!almost.Equal(h.Count, h2.Count, defaultEpsilon) ||
|
math.Float64bits(h.Count) != math.Float64bits(h2.Count) ||
|
||||||
!almost.Equal(h.Sum, h2.Sum, defaultEpsilon) {
|
math.Float64bits(h.Sum) != math.Float64bits(h2.Sum) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +468,7 @@ func (h *FloatHistogram) Equals(h2 *FloatHistogram) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.ZeroThreshold != h2.ZeroThreshold ||
|
if h.ZeroThreshold != h2.ZeroThreshold ||
|
||||||
!almost.Equal(h.ZeroCount, h2.ZeroCount, defaultEpsilon) {
|
math.Float64bits(h.ZeroCount) != math.Float64bits(h2.ZeroCount) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1316,7 +1310,7 @@ func FloatBucketsMatch(b1, b2 []float64) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i, b := range b1 {
|
for i, b := range b1 {
|
||||||
if !almost.Equal(b, b2[i], defaultEpsilon) {
|
if math.Float64bits(b) != math.Float64bits(b2[i]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -769,7 +769,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
return fmt.Errorf("expected histogram value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s))
|
return fmt.Errorf("expected histogram value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !actual.H.Compact(0).Equals(expected.H.Compact(0)) {
|
if !compareNativeHistogram(expected.H.Compact(0), actual.H.Compact(0)) {
|
||||||
return fmt.Errorf("expected histogram value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.H, actual.H, formatSeriesResult(s))
|
return fmt.Errorf("expected histogram value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.H, actual.H, formatSeriesResult(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -804,7 +804,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
if expH != nil && v.H == nil {
|
if expH != nil && v.H == nil {
|
||||||
return fmt.Errorf("expected histogram %s for %s but got float value %v", HistogramTestExpression(expH), v.Metric, v.F)
|
return fmt.Errorf("expected histogram %s for %s but got float value %v", HistogramTestExpression(expH), v.Metric, v.F)
|
||||||
}
|
}
|
||||||
if expH != nil && !expH.Compact(0).Equals(v.H.Compact(0)) {
|
if expH != nil && !compareNativeHistogram(expH.Compact(0), v.H.Compact(0)) {
|
||||||
return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H))
|
return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H))
|
||||||
}
|
}
|
||||||
if !almost.Equal(exp0.Value, v.F, defaultEpsilon) {
|
if !almost.Equal(exp0.Value, v.F, defaultEpsilon) {
|
||||||
|
@ -837,6 +837,121 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compareNativeHistogram is helper function to compare two native histograms
|
||||||
|
// which can tolerate some differ in the field of float type, such as Count, Sum
|
||||||
|
func compareNativeHistogram(exp, cur *histogram.FloatHistogram) bool {
|
||||||
|
if exp == nil || cur == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp.Schema != cur.Schema ||
|
||||||
|
!almost.Equal(exp.Count, cur.Count, defaultEpsilon) ||
|
||||||
|
!almost.Equal(exp.Sum, cur.Sum, defaultEpsilon) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp.UsesCustomBuckets() {
|
||||||
|
if !histogram.FloatBucketsMatch(exp.CustomValues, cur.CustomValues) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp.ZeroThreshold != cur.ZeroThreshold ||
|
||||||
|
!almost.Equal(exp.ZeroCount, cur.ZeroCount, defaultEpsilon) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !spansMatch(exp.NegativeSpans, cur.NegativeSpans) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !floatBucketsMatch(exp.NegativeBuckets, cur.NegativeBuckets) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !spansMatch(exp.PositiveSpans, cur.PositiveSpans) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !floatBucketsMatch(exp.PositiveBuckets, cur.PositiveBuckets) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func floatBucketsMatch(b1, b2 []float64) bool {
|
||||||
|
if len(b1) != len(b2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, b := range b1 {
|
||||||
|
if !almost.Equal(b, b2[i], defaultEpsilon) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func spansMatch(s1, s2 []histogram.Span) bool {
|
||||||
|
if len(s1) == 0 && len(s2) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
s1idx, s2idx := 0, 0
|
||||||
|
for {
|
||||||
|
if s1idx >= len(s1) {
|
||||||
|
return allEmptySpans(s2[s2idx:])
|
||||||
|
}
|
||||||
|
if s2idx >= len(s2) {
|
||||||
|
return allEmptySpans(s1[s1idx:])
|
||||||
|
}
|
||||||
|
|
||||||
|
currS1, currS2 := s1[s1idx], s2[s2idx]
|
||||||
|
s1idx++
|
||||||
|
s2idx++
|
||||||
|
if currS1.Length == 0 {
|
||||||
|
// This span is zero length, so we add consecutive such spans
|
||||||
|
// until we find a non-zero span.
|
||||||
|
for ; s1idx < len(s1) && s1[s1idx].Length == 0; s1idx++ {
|
||||||
|
currS1.Offset += s1[s1idx].Offset
|
||||||
|
}
|
||||||
|
if s1idx < len(s1) {
|
||||||
|
currS1.Offset += s1[s1idx].Offset
|
||||||
|
currS1.Length = s1[s1idx].Length
|
||||||
|
s1idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if currS2.Length == 0 {
|
||||||
|
// This span is zero length, so we add consecutive such spans
|
||||||
|
// until we find a non-zero span.
|
||||||
|
for ; s2idx < len(s2) && s2[s2idx].Length == 0; s2idx++ {
|
||||||
|
currS2.Offset += s2[s2idx].Offset
|
||||||
|
}
|
||||||
|
if s2idx < len(s2) {
|
||||||
|
currS2.Offset += s2[s2idx].Offset
|
||||||
|
currS2.Length = s2[s2idx].Length
|
||||||
|
s2idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if currS1.Length == 0 && currS2.Length == 0 {
|
||||||
|
// The last spans of both set are zero length. Previous spans match.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if currS1.Offset != currS2.Offset || currS1.Length != currS2.Length {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func allEmptySpans(s []histogram.Span) bool {
|
||||||
|
for _, ss := range s {
|
||||||
|
if ss.Length > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (ev *evalCmd) checkExpectedFailure(actual error) error {
|
func (ev *evalCmd) checkExpectedFailure(actual error) error {
|
||||||
if ev.expectedFailMessage != "" {
|
if ev.expectedFailMessage != "" {
|
||||||
if ev.expectedFailMessage != actual.Error() {
|
if ev.expectedFailMessage != actual.Error() {
|
||||||
|
|
|
@ -24,6 +24,8 @@ var minNormal = math.Float64frombits(0x0010000000000000) // The smallest positiv
|
||||||
// Equal returns true if a and b differ by less than their sum
|
// Equal returns true if a and b differ by less than their sum
|
||||||
// multiplied by epsilon.
|
// multiplied by epsilon.
|
||||||
func Equal(a, b, epsilon float64) bool {
|
func Equal(a, b, epsilon float64) bool {
|
||||||
|
// StaleNaN is a special value that is used as staleness maker, so
|
||||||
|
// the two values are equal when both are exactly equals to stale NaN
|
||||||
if value.IsStaleNaN(a) || value.IsStaleNaN(b) {
|
if value.IsStaleNaN(a) || value.IsStaleNaN(b) {
|
||||||
return value.IsStaleNaN(a) && value.IsStaleNaN(b)
|
return value.IsStaleNaN(a) && value.IsStaleNaN(b)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue