From b094639f728b2aa99bfe74ef4bf691f0c317360c Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Thu, 2 Jan 2025 00:02:31 +0800 Subject: [PATCH 01/11] Implement irate and idelta Signed-off-by: Jon Kartago Lamida --- pkg/streamingpromql/engine_test.go | 2 +- pkg/streamingpromql/functions.go | 2 + .../operators/functions/rate_increase.go | 54 +++++++++++++++++++ .../testdata/upstream/functions.test | 21 ++++---- 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/pkg/streamingpromql/engine_test.go b/pkg/streamingpromql/engine_test.go index 0cce9cc6071..99ee5664c25 100644 --- a/pkg/streamingpromql/engine_test.go +++ b/pkg/streamingpromql/engine_test.go @@ -2763,7 +2763,7 @@ func TestCompareVariousMixedMetricsVectorSelectors(t *testing.T) { for _, labels := range labelCombinations { labelRegex := strings.Join(labels, "|") - for _, function := range []string{"rate", "increase", "changes", "resets", "deriv"} { + for _, function := range []string{"rate", "increase", "changes", "resets", "deriv", "irate", "idelta"} { expressions = append(expressions, fmt.Sprintf(`%s(series{label=~"(%s)"}[45s])`, function, labelRegex)) expressions = append(expressions, fmt.Sprintf(`%s(series{label=~"(%s)"}[1m])`, function, labelRegex)) expressions = append(expressions, fmt.Sprintf(`sum(%s(series{label=~"(%s)"}[2m15s]))`, function, labelRegex)) diff --git a/pkg/streamingpromql/functions.go b/pkg/streamingpromql/functions.go index e4229de9175..99415ccce71 100644 --- a/pkg/streamingpromql/functions.go +++ b/pkg/streamingpromql/functions.go @@ -374,7 +374,9 @@ var instantVectorFunctionOperatorFactories = map[string]InstantVectorFunctionOpe "histogram_stddev": InstantVectorTransformationFunctionOperatorFactory("histogram_stddev", functions.HistogramStdDevStdVar(true)), "histogram_stdvar": InstantVectorTransformationFunctionOperatorFactory("histogram_stdvar", functions.HistogramStdDevStdVar(false)), "histogram_sum": InstantVectorTransformationFunctionOperatorFactory("histogram_sum", functions.HistogramSum), + "idelta": FunctionOverRangeVectorOperatorFactory("idelta", functions.Idelta), "increase": FunctionOverRangeVectorOperatorFactory("increase", functions.Increase), + "irate": FunctionOverRangeVectorOperatorFactory("irate", functions.Irate), "label_replace": LabelReplaceFunctionOperatorFactory(), "last_over_time": FunctionOverRangeVectorOperatorFactory("last_over_time", functions.LastOverTime), "ln": InstantVectorTransformationFunctionOperatorFactory("ln", functions.Ln), diff --git a/pkg/streamingpromql/operators/functions/rate_increase.go b/pkg/streamingpromql/operators/functions/rate_increase.go index fa5e040424f..5b71fe945aa 100644 --- a/pkg/streamingpromql/operators/functions/rate_increase.go +++ b/pkg/streamingpromql/operators/functions/rate_increase.go @@ -29,6 +29,20 @@ var Increase = FunctionOverRangeVectorDefinition{ NeedsSeriesNamesForAnnotations: true, } +var Irate = FunctionOverRangeVectorDefinition{ + StepFunc: irate(true), + SeriesValidationFuncFactory: rateSeriesValidator, + SeriesMetadataFunction: DropSeriesName, + NeedsSeriesNamesForAnnotations: true, +} + +var Idelta = FunctionOverRangeVectorDefinition{ + StepFunc: irate(false), + SeriesValidationFuncFactory: rateSeriesValidator, + SeriesMetadataFunction: DropSeriesName, + NeedsSeriesNamesForAnnotations: true, +} + // isRate is true for `rate` function, or false for `instant` function func rate(isRate bool) RangeVectorStepFunction { return func(step *types.RangeVectorStepData, rangeSeconds float64, emitAnnotation types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { @@ -251,6 +265,46 @@ func calculateFloatRate(isRate bool, rangeStart, rangeEnd int64, rangeSeconds fl return delta * factor } +func irate(isRate bool) RangeVectorStepFunction { + return func(step *types.RangeVectorStepData, rangeSeconds float64, emitAnnotation types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { + fHead, fTail := step.Floats.UnsafePoints() + + // We need at least two samples to calculate irate or idelta. + if len(fHead)+len(fTail) < 2 { + return 0, false, nil, nil + } + + lastSample := fHead[len(fHead)-1] + var previousSample promql.FPoint + // If head at least has 2 points, previousSample is must be in the head too, + // otherwise the previousSample might be in tail. + if len(fHead) >= 2 { + previousSample = fHead[len(fHead)-2] + } else { + previousSample = fTail[len(fTail)-1] + } + + var resultValue float64 + if isRate && lastSample.F < previousSample.F { + // Counter reset. + resultValue = lastSample.F + } else { + resultValue = lastSample.F - previousSample.F + } + sampledInterval := lastSample.T - previousSample.T + if sampledInterval == 0 { + // Avoid dividing by 0. + return 0, false, nil, nil + } + + if isRate { + // Convert to per-second. + resultValue /= float64(sampledInterval) / 1000 + } + return resultValue, true, nil, nil + } +} + func rateSeriesValidator() RangeVectorSeriesValidationFunction { // Most of the time, rate() is performed over many series with the same metric name, so we can save some time // by only checking a name we haven't already checked. diff --git a/pkg/streamingpromql/testdata/upstream/functions.test b/pkg/streamingpromql/testdata/upstream/functions.test index 6d2784c4870..dba21f8db5e 100644 --- a/pkg/streamingpromql/testdata/upstream/functions.test +++ b/pkg/streamingpromql/testdata/upstream/functions.test @@ -224,16 +224,14 @@ load 5m http_requests_total{path="/foo"} 0+10x10 http_requests_total{path="/bar"} 0+10x5 0+10x5 -# Unsupported by streaming engine. -# eval instant at 50m irate(http_requests_total[50m]) -# {path="/foo"} .03333333333333333333 -# {path="/bar"} .03333333333333333333 +eval instant at 50m irate(http_requests_total[50m]) + {path="/foo"} .03333333333333333333 + {path="/bar"} .03333333333333333333 # Counter reset. -# Unsupported by streaming engine. -# eval instant at 30m irate(http_requests_total[50m]) -# {path="/foo"} .03333333333333333333 -# {path="/bar"} 0 +eval instant at 30m irate(http_requests_total[50m]) + {path="/foo"} .03333333333333333333 + {path="/bar"} 0 clear @@ -254,10 +252,9 @@ load 5m http_requests{path="/foo"} 0 50 100 150 http_requests{path="/bar"} 0 50 100 50 -# Unsupported by streaming engine. -# eval instant at 20m idelta(http_requests[20m]) -# {path="/foo"} 50 -# {path="/bar"} -50 +eval instant at 20m idelta(http_requests[20m]) + {path="/foo"} 50 + {path="/bar"} -50 clear From f6cc9ccabfb3eba9d03fcfd0e385da71ea59d829 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Thu, 2 Jan 2025 18:18:24 +0800 Subject: [PATCH 02/11] Fix irate and idelta implementation and move it inside range_vectors.go Signed-off-by: Jon Kartago Lamida --- .../operators/functions/range_vectors.go | 60 +++++++++++++++++++ .../operators/functions/rate_increase.go | 54 ----------------- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index dea48555c67..97c887b8223 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -533,3 +533,63 @@ func linearRegression(head, tail []promql.FPoint, interceptTime int64) (slope, i intercept = sumY/n - slope*sumX/n return slope, intercept } + +var Irate = FunctionOverRangeVectorDefinition{ + StepFunc: irate(true), + SeriesMetadataFunction: DropSeriesName, + NeedsSeriesNamesForAnnotations: true, +} + +var Idelta = FunctionOverRangeVectorDefinition{ + StepFunc: irate(false), + SeriesMetadataFunction: DropSeriesName, + NeedsSeriesNamesForAnnotations: true, +} + +func irate(isRate bool) RangeVectorStepFunction { + return func(step *types.RangeVectorStepData, rangeSeconds float64, _ types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { + fHead, fTail := step.Floats.UnsafePoints() + + // We need at least two samples to calculate irate or idelta. + if len(fHead)+len(fTail) < 2 { + return 0, false, nil, nil + } + + var lastSample promql.FPoint + var previousSample promql.FPoint + + // If tails has more than two samples, we should use the last two samples from tail. + // If tail has only one sample, the last sample is from the tail and the previous sample is last point in the head. + // Otherwise, last two samples are all in the head. + if len(fTail) >= 2 { + lastSample = fTail[len(fTail)-1] + previousSample = fTail[len(fTail)-2] + } else if len(fTail) == 1 { + lastSample = fTail[0] + previousSample = fHead[len(fHead)-1] + } else { + lastSample = fHead[len(fHead)-1] + previousSample = fHead[len(fHead)-2] + } + + var resultValue float64 + if isRate && lastSample.F < previousSample.F { + // Counter reset. + resultValue = lastSample.F + } else { + resultValue = lastSample.F - previousSample.F + } + + sampledInterval := lastSample.T - previousSample.T + if sampledInterval == 0 { + // Avoid dividing by 0. + return 0, false, nil, nil + } + + if isRate { + // Convert to per-second. + resultValue /= float64(sampledInterval) / 1000 + } + return resultValue, true, nil, nil + } +} diff --git a/pkg/streamingpromql/operators/functions/rate_increase.go b/pkg/streamingpromql/operators/functions/rate_increase.go index 5b71fe945aa..fa5e040424f 100644 --- a/pkg/streamingpromql/operators/functions/rate_increase.go +++ b/pkg/streamingpromql/operators/functions/rate_increase.go @@ -29,20 +29,6 @@ var Increase = FunctionOverRangeVectorDefinition{ NeedsSeriesNamesForAnnotations: true, } -var Irate = FunctionOverRangeVectorDefinition{ - StepFunc: irate(true), - SeriesValidationFuncFactory: rateSeriesValidator, - SeriesMetadataFunction: DropSeriesName, - NeedsSeriesNamesForAnnotations: true, -} - -var Idelta = FunctionOverRangeVectorDefinition{ - StepFunc: irate(false), - SeriesValidationFuncFactory: rateSeriesValidator, - SeriesMetadataFunction: DropSeriesName, - NeedsSeriesNamesForAnnotations: true, -} - // isRate is true for `rate` function, or false for `instant` function func rate(isRate bool) RangeVectorStepFunction { return func(step *types.RangeVectorStepData, rangeSeconds float64, emitAnnotation types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { @@ -265,46 +251,6 @@ func calculateFloatRate(isRate bool, rangeStart, rangeEnd int64, rangeSeconds fl return delta * factor } -func irate(isRate bool) RangeVectorStepFunction { - return func(step *types.RangeVectorStepData, rangeSeconds float64, emitAnnotation types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { - fHead, fTail := step.Floats.UnsafePoints() - - // We need at least two samples to calculate irate or idelta. - if len(fHead)+len(fTail) < 2 { - return 0, false, nil, nil - } - - lastSample := fHead[len(fHead)-1] - var previousSample promql.FPoint - // If head at least has 2 points, previousSample is must be in the head too, - // otherwise the previousSample might be in tail. - if len(fHead) >= 2 { - previousSample = fHead[len(fHead)-2] - } else { - previousSample = fTail[len(fTail)-1] - } - - var resultValue float64 - if isRate && lastSample.F < previousSample.F { - // Counter reset. - resultValue = lastSample.F - } else { - resultValue = lastSample.F - previousSample.F - } - sampledInterval := lastSample.T - previousSample.T - if sampledInterval == 0 { - // Avoid dividing by 0. - return 0, false, nil, nil - } - - if isRate { - // Convert to per-second. - resultValue /= float64(sampledInterval) / 1000 - } - return resultValue, true, nil, nil - } -} - func rateSeriesValidator() RangeVectorSeriesValidationFunction { // Most of the time, rate() is performed over many series with the same metric name, so we can save some time // by only checking a name we haven't already checked. From 9fe6d21070e5de9d0dc421e6b1877a1bfa23189f Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Thu, 2 Jan 2025 18:22:27 +0800 Subject: [PATCH 03/11] Remove unneeded arguments Signed-off-by: Jon Kartago Lamida --- .../operators/functions/range_vectors.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index 97c887b8223..626adc4eba8 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -535,15 +535,13 @@ func linearRegression(head, tail []promql.FPoint, interceptTime int64) (slope, i } var Irate = FunctionOverRangeVectorDefinition{ - StepFunc: irate(true), - SeriesMetadataFunction: DropSeriesName, - NeedsSeriesNamesForAnnotations: true, + SeriesMetadataFunction: DropSeriesName, + StepFunc: irate(true), } var Idelta = FunctionOverRangeVectorDefinition{ - StepFunc: irate(false), - SeriesMetadataFunction: DropSeriesName, - NeedsSeriesNamesForAnnotations: true, + SeriesMetadataFunction: DropSeriesName, + StepFunc: irate(false), } func irate(isRate bool) RangeVectorStepFunction { From e4c9f7de98750e463e03bb7bed2436ac02e65b62 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Thu, 2 Jan 2025 18:27:52 +0800 Subject: [PATCH 04/11] Fix lint Signed-off-by: Jon Kartago Lamida --- pkg/streamingpromql/operators/functions/range_vectors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index 626adc4eba8..964301e323b 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -545,7 +545,7 @@ var Idelta = FunctionOverRangeVectorDefinition{ } func irate(isRate bool) RangeVectorStepFunction { - return func(step *types.RangeVectorStepData, rangeSeconds float64, _ types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { + return func(step *types.RangeVectorStepData, _ float64, _ types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { fHead, fTail := step.Floats.UnsafePoints() // We need at least two samples to calculate irate or idelta. From a5e8dd7d238597c2af2a9f72f28c89b8806c3d5b Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Thu, 2 Jan 2025 19:03:23 +0800 Subject: [PATCH 05/11] Fix promql test whitespace Signed-off-by: Jon Kartago Lamida --- pkg/streamingpromql/testdata/upstream/functions.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/streamingpromql/testdata/upstream/functions.test b/pkg/streamingpromql/testdata/upstream/functions.test index dba21f8db5e..9e8edb1bdf0 100644 --- a/pkg/streamingpromql/testdata/upstream/functions.test +++ b/pkg/streamingpromql/testdata/upstream/functions.test @@ -230,8 +230,8 @@ eval instant at 50m irate(http_requests_total[50m]) # Counter reset. eval instant at 30m irate(http_requests_total[50m]) - {path="/foo"} .03333333333333333333 - {path="/bar"} 0 + {path="/foo"} .03333333333333333333 + {path="/bar"} 0 clear @@ -253,8 +253,8 @@ load 5m http_requests{path="/bar"} 0 50 100 50 eval instant at 20m idelta(http_requests[20m]) - {path="/foo"} 50 - {path="/bar"} -50 + {path="/foo"} 50 + {path="/bar"} -50 clear From bac4cbde3990d859e52985a3f4641a2bc2b86a06 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Fri, 3 Jan 2025 10:50:50 +0800 Subject: [PATCH 06/11] Update pkg/streamingpromql/operators/functions/range_vectors.go Co-authored-by: Joshua Hesketh --- pkg/streamingpromql/operators/functions/range_vectors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index 964301e323b..32242ccd938 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -556,7 +556,7 @@ func irate(isRate bool) RangeVectorStepFunction { var lastSample promql.FPoint var previousSample promql.FPoint - // If tails has more than two samples, we should use the last two samples from tail. + // If tail has more than two samples, we should use the last two samples from tail. // If tail has only one sample, the last sample is from the tail and the previous sample is last point in the head. // Otherwise, last two samples are all in the head. if len(fTail) >= 2 { From 4b4827d48c03513aa514b7e02db9bc1841b4cca5 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Fri, 3 Jan 2025 10:51:20 +0800 Subject: [PATCH 07/11] Update pkg/streamingpromql/operators/functions/range_vectors.go Co-authored-by: Joshua Hesketh --- pkg/streamingpromql/operators/functions/range_vectors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index 32242ccd938..9c12fa242f5 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -546,6 +546,7 @@ var Idelta = FunctionOverRangeVectorDefinition{ func irate(isRate bool) RangeVectorStepFunction { return func(step *types.RangeVectorStepData, _ float64, _ types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { + // Histograms are ignored fHead, fTail := step.Floats.UnsafePoints() // We need at least two samples to calculate irate or idelta. From 5383c9cc0dcf10fd046b00314d929a42f753b263 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Fri, 3 Jan 2025 10:53:52 +0800 Subject: [PATCH 08/11] Put len in var Signed-off-by: Jon Kartago Lamida --- .../operators/functions/range_vectors.go | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index 9c12fa242f5..85fd550e530 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -536,39 +536,41 @@ func linearRegression(head, tail []promql.FPoint, interceptTime int64) (slope, i var Irate = FunctionOverRangeVectorDefinition{ SeriesMetadataFunction: DropSeriesName, - StepFunc: irate(true), + StepFunc: irateIdelta(true), } var Idelta = FunctionOverRangeVectorDefinition{ SeriesMetadataFunction: DropSeriesName, - StepFunc: irate(false), + StepFunc: irateIdelta(false), } -func irate(isRate bool) RangeVectorStepFunction { +func irateIdelta(isRate bool) RangeVectorStepFunction { return func(step *types.RangeVectorStepData, _ float64, _ types.EmitAnnotationFunc) (float64, bool, *histogram.FloatHistogram, error) { // Histograms are ignored fHead, fTail := step.Floats.UnsafePoints() - // We need at least two samples to calculate irate or idelta. + // We need at least two samples to calculate irateIdelta or idelta. if len(fHead)+len(fTail) < 2 { return 0, false, nil, nil } var lastSample promql.FPoint var previousSample promql.FPoint + lenTail := len(fTail) + lenHead := len(fHead) // If tail has more than two samples, we should use the last two samples from tail. // If tail has only one sample, the last sample is from the tail and the previous sample is last point in the head. // Otherwise, last two samples are all in the head. - if len(fTail) >= 2 { - lastSample = fTail[len(fTail)-1] - previousSample = fTail[len(fTail)-2] - } else if len(fTail) == 1 { + if lenTail >= 2 { + lastSample = fTail[lenTail-1] + previousSample = fTail[lenTail-2] + } else if lenTail == 1 { lastSample = fTail[0] - previousSample = fHead[len(fHead)-1] + previousSample = fHead[lenHead-1] } else { - lastSample = fHead[len(fHead)-1] - previousSample = fHead[len(fHead)-2] + lastSample = fHead[lenHead-1] + previousSample = fHead[lenHead-2] } var resultValue float64 From edaf8243189fb11d01d550c07bb7ca9c24484659 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Fri, 3 Jan 2025 11:47:50 +0800 Subject: [PATCH 09/11] Add more comprehensive tests Signed-off-by: Jon Kartago Lamida --- .../testdata/ours/functions.test | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/pkg/streamingpromql/testdata/ours/functions.test b/pkg/streamingpromql/testdata/ours/functions.test index a1b669f221c..25e44a39979 100644 --- a/pkg/streamingpromql/testdata/ours/functions.test +++ b/pkg/streamingpromql/testdata/ours/functions.test @@ -557,6 +557,72 @@ eval range from 0 to 20m step 1m deriv(metric[3m1s]) clear +# Testing irate and idelta +# nh stands for native histogram +# nhcb stands for native histogram custom bucket +load 1m + metric{case="1 float"} 9 + metric{case="2 floats"} 1 5 + metric{case="all floats with reset"} 1 7 1 7 1 7 1 7 + metric{case="2 floats with missing middle sample"} 1 _ 5 + metric{case="2 floats with missing 2 middle samples"} 1 _ _ 5 + metric{case="2 floats with missing last sample"} 1 5 _ + metric{case="2 floats with NaN middle sample"} 1 NaN 5 + metric{case="2 floats with NaN 2 middle samples"} 1 NaN NaN 5 + metric{case="2 floats with NaN last sample"} 1 5 NaN + metric{case="2 floats with Inf middle sample"} 1 Inf 5 + metric{case="2 floats with Inf 2 middle samples"} 1 Inf Inf 5 + metric{case="2 floats with Inf last sample"} 1 5 Inf + metric{case="all NaN"} NaN NaN NaN NaN + metric{case="all Inf"} Inf Inf Inf Inf + metric{case="2 floats and nh middle sample"} 1 {{schema:3 sum:0 count:0 buckets:[1 2 1]}} 5 + metric{case="2 floats and nh last sample"} 1 5 {{schema:3 sum:0 count:0 buckets:[1 2 1]}} + metric{case="2 floats and nhcb middle sample"} 1 {{schema:-53 sum:0 count:0 custom_values:[5 10] buckets:[1 4]}} 5 + metric{case="2 floats and nhcb last sample"} 1 5 {{schema:-53 sum:0 count:0 custom_values:[5 10] buckets:[1 4]}} + metric{case="all nh"} {{schema:3 sum:0 count:0 buckets:[1 2 1]}} {{schema:3 sum:0 count:0 buckets:[1 2 1]}} + metric{case="all nhcb"} {{schema:-53 sum:1 count:5 custom_values:[5 10] buckets:[1 4]}} {{schema:-53 sum:15 count:2 custom_values:[5 10] buckets:[0 2]}} {{schema:-53 sum:3 count:15 custom_values:[5 10] buckets:[7 8]}} {{schema:-53 sum:3 count:15 custom_values:[5 10] buckets:[0 0]}} + +eval range from 0 to 8m step 1m idelta(metric[3m1s]) + {case="2 floats"} _ 4 4 4 + {case="2 floats and nh last sample"} _ 4 4 4 + {case="2 floats and nh middle sample"} _ _ 4 4 + {case="2 floats and nhcb last sample"} _ 4 4 4 + {case="2 floats and nhcb middle sample"} _ _ 4 4 + {case="2 floats with Inf 2 middle samples"} _ Inf NaN -Inf -Inf -Inf + {case="2 floats with Inf last sample"} _ 4 Inf Inf Inf + {case="2 floats with Inf middle sample"} _ Inf -Inf -Inf -Inf + {case="2 floats with NaN 2 middle samples"} _ NaN NaN NaN NaN NaN + {case="2 floats with NaN last sample"} _ 4 NaN NaN NaN + {case="2 floats with NaN middle sample"} _ NaN NaN NaN NaN + {case="2 floats with missing last sample"} _ 4 4 4 + {case="2 floats with missing middle sample"} _ _ 4 4 + {case="2 floats with missing 2 middle samples"} _ _ _ 4 + {case="all Inf"} _ NaN NaN NaN NaN NaN + {case="all NaN"} _ NaN NaN NaN NaN NaN + {case="all floats with reset"} _ 6 -6 6 -6 6 -6 6 6 + +eval range from 0 to 8m step 1m irate(metric[3m1s]) + {case="2 floats"} _ 0.06666666666666667 0.06666666666666667 0.06666666666666667 + {case="2 floats and nh last sample"} _ 0.06666666666666667 0.06666666666666667 0.06666666666666667 + {case="2 floats and nh middle sample"} _ _ 0.03333333333333333 0.03333333333333333 + {case="2 floats and nhcb last sample"} _ 0.06666666666666667 0.06666666666666667 0.06666666666666667 + {case="2 floats and nhcb middle sample"} _ _ 0.03333333333333333 0.03333333333333333 + {case="2 floats with Inf 2 middle samples"} _ Inf NaN 0.08333333333333333 0.08333333333333333 0.08333333333333333 + {case="2 floats with Inf last sample"} _ 0.06666666666666667 Inf Inf Inf + {case="2 floats with Inf middle sample"} _ Inf 0.08333333333333333 0.08333333333333333 0.08333333333333333 + {case="2 floats with NaN 2 middle samples"} _ NaN NaN NaN NaN NaN + {case="2 floats with NaN last sample"} _ 0.06666666666666667 NaN NaN NaN + {case="2 floats with NaN middle sample"} _ NaN NaN NaN NaN + {case="2 floats with missing last sample"} _ 0.06666666666666667 0.06666666666666667 0.06666666666666667 + {case="2 floats with missing middle sample"} _ _ 0.03333333333333333 0.03333333333333333 + {case="2 floats with missing 2 middle samples"} _ _ _ 0.022222222222222223 + {case="all Inf"} _ NaN NaN NaN NaN NaN + {case="all NaN"} _ NaN NaN NaN NaN NaN + {case="all floats with reset"} _ 0.1 0.016666666666666666 0.1 0.016666666666666666 0.1 0.016666666666666666 0.1 0.1 + + +clear + load 1m some_metric_count{env="prod", cluster="eu"} _ _ _ 0+1x4 some_metric_count{env="prod", cluster="us"} _ _ _ 0+2x4 From dd07548f40223d510ad27d652e9c94fd1c8d8f2a Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Fri, 3 Jan 2025 11:49:35 +0800 Subject: [PATCH 10/11] Remove extra line Signed-off-by: Jon Kartago Lamida --- pkg/streamingpromql/testdata/ours/functions.test | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/streamingpromql/testdata/ours/functions.test b/pkg/streamingpromql/testdata/ours/functions.test index 25e44a39979..e7cb57c3562 100644 --- a/pkg/streamingpromql/testdata/ours/functions.test +++ b/pkg/streamingpromql/testdata/ours/functions.test @@ -620,7 +620,6 @@ eval range from 0 to 8m step 1m irate(metric[3m1s]) {case="all NaN"} _ NaN NaN NaN NaN NaN {case="all floats with reset"} _ 0.1 0.016666666666666666 0.1 0.016666666666666666 0.1 0.016666666666666666 0.1 0.1 - clear load 1m From 1b1f3591afcf6d12df817ae972a4fb5e0cc4e6c9 Mon Sep 17 00:00:00 2001 From: Jon Kartago Lamida Date: Fri, 3 Jan 2025 11:53:10 +0800 Subject: [PATCH 11/11] Move len var further up Signed-off-by: Jon Kartago Lamida --- pkg/streamingpromql/operators/functions/range_vectors.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/streamingpromql/operators/functions/range_vectors.go b/pkg/streamingpromql/operators/functions/range_vectors.go index 85fd550e530..4593a6694a9 100644 --- a/pkg/streamingpromql/operators/functions/range_vectors.go +++ b/pkg/streamingpromql/operators/functions/range_vectors.go @@ -549,15 +549,16 @@ func irateIdelta(isRate bool) RangeVectorStepFunction { // Histograms are ignored fHead, fTail := step.Floats.UnsafePoints() - // We need at least two samples to calculate irateIdelta or idelta. - if len(fHead)+len(fTail) < 2 { + lenTail := len(fTail) + lenHead := len(fHead) + + // We need at least two samples to calculate irate or idelta + if lenHead+lenTail < 2 { return 0, false, nil, nil } var lastSample promql.FPoint var previousSample promql.FPoint - lenTail := len(fTail) - lenHead := len(fHead) // If tail has more than two samples, we should use the last two samples from tail. // If tail has only one sample, the last sample is from the tail and the previous sample is last point in the head.