From 85dbc3cc76a32cc9537303b8ed40e0886be1e045 Mon Sep 17 00:00:00 2001 From: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Date: Thu, 16 Apr 2026 13:40:48 +0200 Subject: [PATCH 1/2] promql: fix smoothSeries() @ modifier timestamp mismatch smoothSeries() was stamping output points at offset-adjusted timestamps instead of evaluator timestamps. When the @ modifier is used, this causes gatherVector() to miss the points because it matches by exact timestamp equality against evaluator step timestamps. Fix by iterating over evaluator timestamps and deriving data timestamps by subtracting the offset, so output points align with what gatherVector() expects. Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> --- promql/engine.go | 26 +++++++++---------- .../promqltest/testdata/extended_vectors.test | 8 ++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 7039adfc9f..d7c0c7edf1 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1712,8 +1712,6 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration) it := storage.NewBuffer(dur + 2*durationMilliseconds(ev.lookbackDelta)) offMS := offset.Milliseconds() - start := ev.startTimestamp - offMS - end := ev.endTimestamp - offMS step := ev.interval lb := durationMilliseconds(ev.lookbackDelta) @@ -1729,9 +1727,11 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration) var floats []FPoint var hists []HPoint - for ts := start; ts <= end; ts += step { - matrixStart := ts - lb - matrixEnd := ts + lb + for evalTS := ev.startTimestamp; evalTS <= ev.endTimestamp; evalTS += step { + // Apply offset to get the data timestamp. + dataTS := evalTS - offMS + matrixStart := dataTS - lb + matrixEnd := dataTS + lb floats, hists = ev.matrixIterSlice(it, matrixStart, matrixEnd, floats, hists) if len(floats) == 0 && len(hists) == 0 { @@ -1743,28 +1743,28 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration) ev.errorf("smoothed and anchored modifiers do not work with native histograms") } - // Binary search for the first index with T >= ts. - i := sort.Search(len(floats), func(i int) bool { return floats[i].T >= ts }) + // Binary search for the first index with T >= dataTS. + i := sort.Search(len(floats), func(i int) bool { return floats[i].T >= dataTS }) switch { - case i < len(floats) && floats[i].T == ts: + case i < len(floats) && floats[i].T == dataTS: // Exact match. - ss.Floats = append(ss.Floats, floats[i]) + ss.Floats = append(ss.Floats, FPoint{F: floats[i].F, T: evalTS}) case i > 0 && i < len(floats): // Interpolate between prev and next. // TODO: detect if the sample is a counter, based on __type__ or metadata. prev, next := floats[i-1], floats[i] - val := interpolate(prev, next, ts, false) - ss.Floats = append(ss.Floats, FPoint{F: val, T: ts}) + val := interpolate(prev, next, dataTS, false) + ss.Floats = append(ss.Floats, FPoint{F: val, T: evalTS}) case i > 0: // No next point yet; carry forward previous value. prev := floats[i-1] - ss.Floats = append(ss.Floats, FPoint{F: prev.F, T: ts}) + ss.Floats = append(ss.Floats, FPoint{F: prev.F, T: evalTS}) default: - // i == 0 and floats[0].T > ts: there is no previous data yet; skip. + // i == 0 and floats[0].T > dataTS: there is no previous data yet; skip. } } diff --git a/promql/promqltest/testdata/extended_vectors.test b/promql/promqltest/testdata/extended_vectors.test index 06f70913b7..416945aada 100644 --- a/promql/promqltest/testdata/extended_vectors.test +++ b/promql/promqltest/testdata/extended_vectors.test @@ -434,3 +434,11 @@ eval instant at 15s increase(metric[10s] smoothed) eval instant at 60s rate(metric[5s] smoothed) eval instant at 60s increase(metric[5s] smoothed) + +# Smoothed vector selector with @ modifier with binary op. +clear +load 10s + metric 0+1x20 + +eval range from 0s to 60s step 15s metric @ 100 smoothed + 0 + {} 10 10 10 10 10 From 4c50ef989d4ba53a435d16c12b686d3fa7b5d711 Mon Sep 17 00:00:00 2001 From: Julien <291750+roidelapluie@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:38:36 +0200 Subject: [PATCH 2/2] Update promql/promqltest/testdata/extended_vectors.test Co-authored-by: George Krajcsovits Signed-off-by: Julien <291750+roidelapluie@users.noreply.github.com> --- .../promqltest/testdata/extended_vectors.test | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/promql/promqltest/testdata/extended_vectors.test b/promql/promqltest/testdata/extended_vectors.test index 416945aada..da7cd29f49 100644 --- a/promql/promqltest/testdata/extended_vectors.test +++ b/promql/promqltest/testdata/extended_vectors.test @@ -435,10 +435,25 @@ eval instant at 60s rate(metric[5s] smoothed) eval instant at 60s increase(metric[5s] smoothed) -# Smoothed vector selector with @ modifier with binary op. +# Smoothed vector selector with @ and offset modifier and binop clear load 10s metric 0+1x20 +eval range from 0s to 60s step 15s metric @ 100 + metric 10 10 10 10 10 + +eval range from 0s to 60s step 15s metric @ 100 smoothed + metric 10 10 10 10 10 + eval range from 0s to 60s step 15s metric @ 100 smoothed + 0 {} 10 10 10 10 10 + +eval range from 0s to 60s step 15s metric offset -100 + metric 10 11 13 14 16 + +eval range from 0s to 60s step 15s metric offset -100 smoothed + metric 10 11.5 13 14.5 16 + +eval range from 0s to 60s step 15s metric offset -100 smoothed + 0 + {} 10 11.5 13 14.5 16