feat(promql): evaluate the anchored and smoothed range modifiers (#9888)

I hereby agree to the terms of the [GreptimeDB
CLA](https://github.com/GreptimeTeam/.github/blob/main/CLA.md).

## Refer to a related PR or issue link (optional)

Native operator kernels, NEW-EVAL-MOD (#27).

## What's changed and what's your intention?

Prometheus v3.15.0 adds two experimental range selector modifiers behind
`EnableExtendedRangeSelectors`: `anchored` and `smoothed`. This adds
them to the range evaluator as `RangeWindow.modifier:
Option<RangeModifier>`.

- **What they read.** `anchored` also reads the statement's lookback
before the window start. `smoothed` reads the lookback before the start
and after the end. The evaluator keeps samples that much longer and
widens a smoothed window's end.
- **Kernels** follow `extendedRate`, `pickOrInterpolate*`,
`interpolate`, `correctForCounterResets` and `pickFirstSampleIndices`:
- `rate`, `increase` and `delta` take the start value from the last
sample at or before the start. For `smoothed` they interpolate both
ends, a counter that reset between the two samples restarts from zero,
and nothing is extrapolated.
- `resets` and `changes` (anchored only) count from that anchor sample.
- **Allowed functions.** These match `AnchoredSafeFunctions` /
`SmoothedSafeFunctions`; any other function is rejected with Prometheus'
message. Evaluated input (subqueries) is refused; the parser does not
allow modifiers there either.
- **When a smoothed point is decided.** A smoothed end needs the first
sample at or after the point. A point is therefore decided once every
field holds such a sample, or once the lookback past it has arrived. The
chunk's last row alone is not enough: a stale last row is dropped, and a
field can be empty in it.
- **Not here:**
- Native histogram samples under a modifier are refused with
`NotImplemented`. Prometheus runs `extendedHistogramRate` there, and
returns nothing with a warning for mixed windows.
- No compiler wiring: promql-parser 0.10 lexes the keywords but has no
grammar or AST for them.
- A scan feeding a modified window has to read the extra lookback; the
`RangeWindow` doc says so.
- **Display:** `rate [5m] smoothed lookback 300000ms ...`.

### Tests

- Golden `range_eval/modifier_cases.txt` (43 KB, 100 cases) from
`promql-compat/cmd/narthex-golden-rangemod`. It has 50 random cases and
50 cases with whole-second times that put samples exactly on the window
and lookback bounds. Each case is pushed as one chunk and as one chunk
per sample, and the cases for unsupported functions expect the
rejection.
- A smoothed `delta` whose first chunk ends on a stale row must wait for
the next sample to interpolate the end. This case fails when readiness
comes from the chunk's last row.
- Display of a modified window.

## PR Checklist
Please convert it to a draft if some of the following conditions are not
met.

- [x] I have written the necessary rustdoc comments.
- [x] I have added the necessary unit tests and integration tests.
- [ ] This PR requires documentation updates.
- [x] API changes are backward compatible.
- [x] Schema or data changes are backward compatible.
- [ ] This PR needs to be backported to release branches, and I have
added the `backport-<target>` labels (e.g. `backport-v1.3` targets
`release/v1.3`).
This commit is contained in:
dennis zhuang
2026-10-24 00:03:16 +08:00
committed by GitHub
11 changed files with 699 additions and 18 deletions
@@ -165,6 +165,7 @@ fn rate_tree_of(schema: Arc<SeriesSchema>) -> NativeTree {
range_ms: RANGE_MS,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
// The input is raw samples, so it has no grid of its own.
input_grid: None,
@@ -201,6 +202,7 @@ fn instant_window_tree() -> NativeTree {
range_ms: RANGE_MS,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid: Some(Arc::clone(&grid)),
output_grid: grid,
@@ -248,6 +250,7 @@ fn nested_window_tree() -> NativeTree {
range_ms: 1_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
// The inner window's input is raw samples, so it has no grid of its own.
input_grid: None,
@@ -262,6 +265,7 @@ fn nested_window_tree() -> NativeTree {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
// The outer window reads the inner one's evaluated output, on that output's grid,
// and reports one value per field there like the inner one does.
+5 -1
View File
@@ -196,9 +196,13 @@ fn aggregate_kind(kind: AggregateKind) -> String {
/// A window: what it runs, over which range, and where it lands.
fn window(op: &BoundWindow) -> String {
format!(
"{} [{}ms] offset {} anchor {} on grid {}",
"{} [{}ms]{} offset {} anchor {} on grid {}",
function(op.function),
op.window.range_ms,
match op.window.modifier {
Some(modifier) => format!(" {} lookback {}ms", modifier.name(), modifier.before_ms()),
None => String::new(),
},
op.window.offset_ms,
match op.window.anchor_ms {
Some(anchor_ms) => anchor_ms.to_string(),
+29 -1
View File
@@ -24,7 +24,7 @@ use super::super::plan::{
};
use crate::map::MathOp;
use crate::native::plan::MapOp;
use crate::range_eval::{RangeFunction, RangeWindow};
use crate::range_eval::{RangeFunction, RangeModifier, RangeWindow};
use crate::select::SortOrder;
use crate::vector_match::{BinaryMatching, BinaryOp, Cardinality, FillValues, MatchingLabels};
@@ -81,6 +81,7 @@ fn window_over(
range_ms,
offset_ms,
anchor_ms,
modifier: None,
},
input_grid: None,
output_grid: Arc::clone(&out),
@@ -466,3 +467,30 @@ fn a_vector_operation_names_its_binding() {
assert_eq!(tree.to_string().lines().nth(1), Some(line));
}
}
/// A window read with a range modifier names it and the lookback it reads around the window.
#[test]
fn a_modified_window_names_its_modifier() {
let out = grid(0, 60_000, 4);
let mut node = window_over(
raw_input(),
RangeFunction::Rate,
300_000,
0,
None,
Arc::clone(&out),
);
if let NativeExpr::Window { op, .. } = &mut node.expr {
op.window.modifier = Some(RangeModifier::Smoothed {
lookback_ms: 300_000,
});
}
let tree = NativeTree::try_new(node).unwrap();
assert_eq!(
tree.to_string().lines().nth(1),
Some(
" root Window rate [300000ms] smoothed lookback 300000ms offset 0 anchor - on grid \
0/60000x4"
)
);
}
+5
View File
@@ -172,6 +172,7 @@ fn window_with(
range_ms,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid,
output_grid: Arc::clone(&output_grid),
@@ -195,6 +196,7 @@ fn window_over_fields(count: usize, output_grid: Arc<EvalGrid>) -> NativeNode {
range_ms: 1,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid: None,
output_grid: Arc::clone(&output_grid),
@@ -833,6 +835,7 @@ fn a_window_over_raw_input_evaluates_onto_its_own_grid() {
range_ms: 300_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::LastOverTime,
)
@@ -947,6 +950,7 @@ fn a_window_map_window_chain_keeps_each_layer_on_its_own_grid() {
range_ms: 120_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::LastOverTime,
)
@@ -976,6 +980,7 @@ fn a_window_map_window_chain_keeps_each_layer_on_its_own_grid() {
range_ms: 240_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::LastOverTime,
)
+1
View File
@@ -404,6 +404,7 @@ mod tests {
range_ms: 300_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid: None,
output_grid: Arc::clone(&grid),
+3
View File
@@ -178,6 +178,7 @@ fn window_fields(inner: NativeNode, out: Arc<EvalGrid>, count: usize) -> NativeN
range_ms: 300_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid: None,
output_grid: Arc::clone(&out),
@@ -202,6 +203,7 @@ fn window_on(
range_ms: 300_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid,
output_grid: Arc::clone(&out),
@@ -358,6 +360,7 @@ fn a_window_cannot_change_the_field_count() {
range_ms: 30_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
input_grid: Some(Arc::clone(&out)),
output_grid: Arc::clone(&out),
+184 -13
View File
@@ -42,7 +42,9 @@ pub use function::RangeFunction;
pub(crate) use function::quantile;
/// The samples a range selector reads at evaluation time `T`: source timestamps in
/// `(E - range_ms, E]`, where `E` is `T - offset_ms`, or `anchor_ms - offset_ms` with `@`.
/// `(E - range_ms, E]`, where `E` is `T - offset_ms`, or `anchor_ms - offset_ms` with `@`. A
/// modifier widens that: `anchored` also reads the lookback before `E - range_ms`, `smoothed` the
/// lookback on both sides, and a scan feeding the window has to read that much more.
#[derive(Clone, Copy, Debug)]
pub struct RangeWindow {
/// Positive window length in milliseconds.
@@ -52,6 +54,46 @@ pub struct RangeWindow {
/// The resolved `@` timestamp in milliseconds, with `start()` and `end()` already replaced
/// by the statement's start and end.
pub anchor_ms: Option<i64>,
/// The experimental `anchored` or `smoothed` selector modifier, which also reads samples
/// around the window.
pub modifier: Option<RangeModifier>,
}
/// The experimental range selector modifiers of Prometheus, which read samples beyond the
/// window to pin its boundary values. Not to be confused with an `@` anchor, which fixes the
/// window's end.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RangeModifier {
/// `anchored`: the window also reads the last sample at or before its start, up to the
/// statement's lookback before it, and takes it as the value at the start.
Anchored { lookback_ms: i64 },
/// `smoothed`: the window also reads samples up to the lookback before its start and after its
/// end, and interpolates the values at both boundaries.
Smoothed { lookback_ms: i64 },
}
impl RangeModifier {
/// How far before the window start the window also reads.
pub(crate) fn before_ms(self) -> i64 {
match self {
Self::Anchored { lookback_ms } | Self::Smoothed { lookback_ms } => lookback_ms,
}
}
/// How far after the window end the window also reads.
pub(crate) fn after_ms(self) -> i64 {
match self {
Self::Anchored { .. } => 0,
Self::Smoothed { lookback_ms } => lookback_ms,
}
}
pub(crate) fn name(self) -> &'static str {
match self {
Self::Anchored { .. } => "anchored",
Self::Smoothed { .. } => "smoothed",
}
}
}
/// The valid samples of one field inside one window, in source order.
@@ -63,7 +105,8 @@ pub(crate) struct FloatWindow<'a> {
/// that does not correct counters and for every window of a series that never reset.
pub counter_resets: &'a [CounterReset],
/// Evaluation timestamp `T`. `timestamps` lie in `(T - range_ms, T]`, except for an
/// `@`-anchored `predict_linear`, which evaluates the first point's window at every `T`.
/// `@`-anchored `predict_linear`, which evaluates the first point's window at every `T`, and
/// for a range modifier, which widens the window by the lookback as [`RangeWindow`] says.
pub eval_ts: i64,
pub range_ms: i64,
}
@@ -522,6 +565,9 @@ impl RangeEvaluator {
format!("invalid {name} factor. Expected: 0 < factor < 1, got: {factor}")
});
}
if let Some(modifier) = window.modifier {
check_modifier(input, modifier, function)?;
}
let fold_offset = fold_offset(grid.spec(), window)?;
let step_invariant = !matches!(function, RangeFunction::PredictLinear(_));
if !step_invariant {
@@ -536,20 +582,23 @@ impl RangeEvaluator {
}
}
}
let mut evaluator = Self::with_kernel(
input,
grid,
window,
function.kernel(fold_offset),
step_invariant,
function.indexes_counter_resets(),
)?;
// A modified window corrects counters over the samples it holds rather than through the
// reset index, and has no batch form.
let (kernel, index_resets) = match window.modifier {
Some(modifier) => (function.modified_kernel(modifier), false),
None => (
function.kernel(fold_offset),
function.indexes_counter_resets(),
),
};
let mut evaluator =
Self::with_kernel(input, grid, window, kernel, step_invariant, index_resets)?;
evaluator.drops_metric_name = function.drops_metric_name();
evaluator.window_error = window_error;
evaluator.function = Some(function);
// An anchored selector replays one window at every point, so its windows do not advance
// with the grid and a batch would only repeat the same call.
if matches!(evaluator.replay, Replay::PerPoint) {
if matches!(evaluator.replay, Replay::PerPoint) && window.modifier.is_none() {
evaluator.batch = function.batch_kernel();
}
Ok(evaluator)
@@ -1016,6 +1065,20 @@ impl RangeEvaluator {
self.window.offset_ms
))
})?;
// Refused here rather than when a point is evaluated: a smoothed point can be decided
// before the rest of its window arrives, so whether a later histogram is seen would
// depend on how the input is chunked.
if let Some(modifier) = self.window.modifier
&& row
.iter()
.any(|sample| matches!(sample, SampleRef::Histogram(_)))
&& self.decided_window_reads(shifted)
{
return Err(DataFusionError::NotImplemented(format!(
"the {} range modifier over native histogram samples",
modifier.name()
)));
}
for (field, sample) in self.fields.iter_mut().zip(&row) {
match sample {
SampleRef::Missing => {}
@@ -1039,6 +1102,34 @@ impl RangeEvaluator {
Ok(())
}
/// Whether a sample at `timestamp` on the evaluation timeline lies in the window of a point
/// this evaluator decides: a window ending at `E` reads `(E - range - before, E + after]`, and
/// only the first point's window is read when the result is replayed.
fn decided_window_reads(&self, timestamp: i64) -> bool {
let (before, after) = self.window.modifier.map_or((0, 0), |modifier| {
(
i128::from(modifier.before_ms()),
i128::from(modifier.after_ms()),
)
});
let spec = self.grid.spec();
let ends = match self.replay {
Replay::PerPoint => i128::from(spec.len),
Replay::Once | Replay::EveryPoint => 1,
};
let (start, step) = (i128::from(spec.start_ms), i128::from(spec.step_ms));
// The window ends that read the sample are those in `[timestamp - after, timestamp +
// range + before)`; the first grid point at or after the lower bound decides.
let lowest = i128::from(timestamp) - after;
let highest = i128::from(timestamp) + i128::from(self.window.range_ms) + before;
let first = if lowest <= start {
0
} else {
(lowest - start + step - 1) / step
};
first < ends && start + first * step < highest
}
/// Evaluates grid points up to `ready` on the evaluation timeline, or all remaining points
/// when `ready` is `None`.
fn evaluate(&mut self, ready: Option<i128>) -> Result<()> {
@@ -1046,7 +1137,34 @@ impl RangeEvaluator {
let state = self.series.as_mut().expect("checked by check_chunk");
let spec = self.grid.spec();
let grid = self.grid.timestamps().map_err(external)?;
let range = i128::from(self.window.range_ms);
// A modifier also reads samples up to the lookback ahead of the window start, so they are
// kept that much longer.
let before = self
.window
.modifier
.map_or(0, |modifier| i128::from(modifier.before_ms()));
// `smoothed` interpolates the window end with the first sample at or after it, which can
// arrive up to the lookback later. A point is decided once every field holds a sample at
// or after it, or once the lookback past it has arrived. The input's last row does not say
// that alone: a stale row is dropped, and a field can hold no value in it.
let ready = match (ready, self.window.modifier) {
(Some(ready), Some(RangeModifier::Smoothed { lookback_ms })) => {
let held = self
.fields
.iter()
.map(|field| {
field
.timestamps
.last()
.map_or(i128::MIN, |&t| i128::from(t))
})
.min()
.unwrap_or(i128::MIN);
Some(held.max(ready - i128::from(lookback_ms)))
}
(ready, _) => ready,
};
let range = i128::from(self.window.range_ms) + before;
let mut empty_tail = false;
while state.cursor < points_read {
let eval_ts = grid[state.cursor];
@@ -1079,7 +1197,9 @@ impl RangeEvaluator {
break;
};
if earliest > eval_ts {
// Skip the points whose windows end before the earliest sample.
// Skip the points whose windows end before the earliest sample. A smoothed window
// reads past its end, but without a sample at or before its end it has no result,
// as Prometheus returns nothing when the first sample is after the end.
let step = i128::from(spec.step_ms);
let steps = (i128::from(earliest) - i128::from(spec.start_ms) + step - 1) / step;
state.cursor = usize::try_from(steps).map_or(grid.len(), |i| i.min(grid.len()));
@@ -1095,6 +1215,7 @@ impl RangeEvaluator {
function: self.function,
range_ms: self.window.range_ms,
offset_ms: self.window.offset_ms,
modifier: self.window.modifier,
};
match self.replay {
Replay::PerPoint => {
@@ -1225,6 +1346,7 @@ struct RowEvaluator<'a> {
function: Option<RangeFunction>,
range_ms: i64,
offset_ms: i64,
modifier: Option<RangeModifier>,
}
impl RowEvaluator<'_> {
@@ -1237,6 +1359,8 @@ impl RowEvaluator<'_> {
row: &mut Vec<Option<GridSample>>,
) -> Result<()> {
row.clear();
// A smoothed window also reads the samples after its end.
let window_end = window_end + self.modifier.map_or(0, RangeModifier::after_ms);
for field in self.fields {
let timestamps = &field.timestamps[field.head..];
let len = timestamps.partition_point(|&timestamp| timestamp <= window_end);
@@ -1267,6 +1391,53 @@ impl RowEvaluator<'_> {
}
}
/// Rejects a modifier on a function Prometheus does not allow it with, as Prometheus rejects the
/// query (`AnchoredSafeFunctions`, `SmoothedSafeFunctions`), and on evaluated input, which reads
/// no raw samples around its windows.
fn check_modifier(
input: &SeriesSchema,
modifier: RangeModifier,
function: RangeFunction,
) -> Result<()> {
if input.eval_grid.is_some() {
return Err(DataFusionError::NotImplemented(format!(
"the {} range modifier over evaluated series",
modifier.name()
)));
}
let allowed = match modifier {
RangeModifier::Anchored { .. } => matches!(
function,
RangeFunction::Rate
| RangeFunction::Increase
| RangeFunction::Delta
| RangeFunction::Resets
| RangeFunction::Changes
),
RangeModifier::Smoothed { .. } => matches!(
function,
RangeFunction::Rate | RangeFunction::Increase | RangeFunction::Delta
),
};
if !allowed {
let list = match modifier {
RangeModifier::Anchored { .. } => "changes, delta, increase, rate, resets",
RangeModifier::Smoothed { .. } => "delta, increase, rate",
};
return Err(DataFusionError::Plan(format!(
"{} modifier can only be used with: {list} - not with {function:?}",
modifier.name()
)));
}
if modifier.before_ms() < 0 {
return Err(DataFusionError::Plan(format!(
"lookback must not be negative, got {} ms",
modifier.before_ms()
)));
}
Ok(())
}
/// The offset samples are shifted by: the selector offset, or for `@` the offset that places
/// the anchored window at the first grid point.
fn fold_offset(grid: GridSpec, window: RangeWindow) -> Result<i64> {
+109 -1
View File
@@ -20,7 +20,7 @@
use crate::functions::{EdgeKind, count_edges, extremum, instant_delta, kahan_inc};
use crate::go_sort;
use crate::range_eval::{BatchKernel, FloatWindow, FloatWindows, WindowKernel};
use crate::range_eval::{BatchKernel, FloatWindow, FloatWindows, RangeModifier, WindowKernel};
/// A PromQL range-vector function over float and native histogram samples.
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -170,6 +170,114 @@ impl RangeFunction {
}
}
impl RangeFunction {
/// Returns the kernel computing this function over windows read with `modifier`, for the
/// functions the modifier is allowed with (`RangeEvaluator::try_new` checks that).
///
/// The window holds the samples the modifier reads around it as well, on the evaluation
/// timeline, so the window itself is `(eval_ts - range_ms, eval_ts]`.
pub(crate) fn modified_kernel(self, modifier: RangeModifier) -> WindowKernel {
let smoothed = matches!(modifier, RangeModifier::Smoothed { .. });
match self {
Self::Rate => Box::new(move |window| extended_rate(&window, smoothed, true, true)),
Self::Increase => Box::new(move |window| extended_rate(&window, smoothed, true, false)),
Self::Delta => Box::new(move |window| extended_rate(&window, smoothed, false, false)),
Self::Resets => Box::new(|window| {
anchored_values(&window).map(|values| count_edges(values, EdgeKind::Resets) as f64)
}),
Self::Changes => Box::new(|window| {
anchored_values(&window).map(|values| count_edges(values, EdgeKind::Changes) as f64)
}),
_ => unreachable!("RangeEvaluator::try_new rejects {self:?} with a range modifier"),
}
}
}
/// Go `sort.Search(n, predicate)`: the first index in `[0, n)` the predicate holds at, or `n`.
fn search(n: usize, predicate: impl Fn(usize) -> bool) -> usize {
(0..n).find(|&i| predicate(i)).unwrap_or(n)
}
/// Prometheus `extendedRate`: `rate`, `increase` or `delta` over an `anchored` or `smoothed`
/// window. The value at the window start is the last sample at or before it, or for `smoothed`
/// the interpolation between it and the next one; the end is picked or interpolated the same way.
/// Nothing is extrapolated.
fn extended_rate(
window: &FloatWindow<'_>,
smoothed: bool,
is_counter: bool,
is_rate: bool,
) -> Option<f64> {
let (timestamps, values) = (window.timestamps, window.values);
let range_start = window.eval_ts - window.range_ms;
let range_end = window.eval_ts;
let mut last = timestamps.len() - 1;
let first = search(last, |i| timestamps[i] > range_start).saturating_sub(1);
if smoothed {
last = search(last, |i| timestamps[i] >= range_end);
}
if timestamps[last] <= range_start || (smoothed && timestamps[first] > range_end) {
return None;
}
let left = if smoothed && timestamps[first] < range_start {
interpolate(window, first, range_start, is_counter)
} else {
values[first]
};
let right = if smoothed && last > 0 && timestamps[last] > range_end {
interpolate(window, last - 1, range_end, is_counter)
} else {
values[last]
};
let mut result = right - left;
if is_counter {
// Prometheus `correctForCounterResets` over the samples strictly inside the window; the
// boundary values already account for the resets at the edges.
let inner_start = first + usize::from(timestamps[first] <= range_start);
let inner_end = last + 1 - usize::from(timestamps[last] >= range_end);
let mut correction = 0.0;
let mut previous = left;
for &value in &values[inner_start..inner_end] {
if value < previous {
correction += previous;
}
previous = value;
}
if right < previous {
correction += previous;
}
result += correction;
}
if is_rate {
result /= window.range_ms as f64 / 1000.0;
}
Some(result)
}
/// Prometheus `interpolate` between the samples at `index` and `index + 1`, at `t`: a counter
/// that reset between them restarts from zero.
fn interpolate(window: &FloatWindow<'_>, index: usize, t: i64, is_counter: bool) -> f64 {
let (t1, t2) = (window.timestamps[index], window.timestamps[index + 1]);
let (mut y1, y2) = (window.values[index], window.values[index + 1]);
if is_counter && y2 < y1 {
y1 = 0.0;
}
y1 + (y2 - y1) * (t - t1) as f64 / (t2 - t1) as f64
}
/// Prometheus `pickFirstSampleIndices` for an `anchored` window of floats: the values from the
/// last sample at or before the window start on, or `None` when no sample lies after the start.
fn anchored_values<'a>(window: &FloatWindow<'a>) -> Option<&'a [f64]> {
let range_start = window.eval_ts - window.range_ms;
let after = window
.timestamps
.partition_point(|&timestamp| timestamp <= range_start);
if after >= window.timestamps.len() {
return None;
}
Some(&window.values[after.saturating_sub(1)..])
}
/// Prometheus `funcSumOverTime`.
fn sum(values: &[f64]) -> f64 {
let (sum, c) = values
@@ -0,0 +1,105 @@
# Generated by promql-compat cmd/narthex-golden-rangemod built for amd64 (Prometheus v3.15.0 engine
# with EnableExtendedRangeSelectors): seed 1, then `-aligned -seed 2`, whose whole-second times put
# samples on the window and lookback bounds. Each line: function modifier range_ms offset_ms
# start_ms step_ms points lookback_ms anchor_ms ; samples ; result, where anchor_ms is `-` without
# `@`, every point is `timestamp:hex value bits`, and `error` means the engine rejected the query.
rate anchored 3203 4376 10729 3203 8 10000 - ; 12166:4058b98f850e2f55 13861:405d7ba9e3a40d84 15136:4062fc5e07225a19 17632:4068605a85491805 20580:406dc8e3bdf1e0b9 21122:7ff0000000000002 23954:4017cad70ce12290 40439:40408064e23c76a0 42003:4046d70da3c88e06 43163:404e44925e1bc410 45363:4001c87cbd1748e6 46067:4043a85d21d8de1b 46224:40550a8e60b3b97e ; 17135:0 20338:40308aff454a8f11 23541:402aed7808077661 26744:402b0432383430e9 29947:3ffdb66b45b6c48a
rate anchored 2872 -9435 50589 2871 1 10000 31476 ; 9950:4088c577ca0544e9 11984:7e37e43c8800759c 13321:c0838c0ff7fa2fa4 13874:c0666b5684a00464 15226:407ca5c8836eaa59 17637:c0110e1a977efd76 18191:7ff0000000000002 28575:405db23bc56aacea 29470:c08d9bc1f16f2de9 30537:c0846581a8f6ae40 31519:fe37e43c8800759c 31907:c085d09345924b70 32811:c009b0f1252e9e5c 41427:408ad9c94240aa8c 42504:c030c9035fcdf245 42810:c06aafefa0ee2712 45069:c08919dc00149b6b 45892:8000000000000000 48861:4061b6810ffb521f 50766:407348a4f0f2a765 52806:7ff0000000000002 77506:c0730a2f7176b9cf ;
rate anchored 16686 1719 33222 805 3 10000 51827 ; 17293:405c1d0f5d641851 19693:4022e765ad246949 41304:4040e82e34369c40 48323:405453b76ca69c8f 48505:4019cd32af581925 50976:404659b3cb82c1b5 56236:4048295f2ec78f13 57657:40567bb8246dafd6 59209:405e5994aa021930 61249:40175a77bee6ba18 ; 33222:4009dd0699f90728 34027:4009dd0699f90728 34832:4009dd0699f90728
rate anchored 18683 129 16259 3266 16 300000 - ; 18018:7ff8000000000001 19355:7ff8000000000001 19900:7ff8000000000001 20138:7ff8000000000001 20745:7ff8000000000001 22166:7ff8000000000001 24284:7ff8000000000001 ; 19525:7ff8000000000001 22791:7ff8000000000001 26057:7ff8000000000001 29323:7ff8000000000001 32589:7ff8000000000001 35855:7ff8000000000001 39121:7ff8000000000001 42387:7ff8000000000001
rate anchored 984 7477 28191 984 12 1000 - ; 17575:c08be36e438e16c6 19860:c0788654f3c58b54 21147:c078b98624c6904c 21694:408c5423db7f2f64 24069:c025473bd7a419aa ; 28191:0 29175:408cca0fa0a07902 32127:0
rate anchored 3049 0 24692 3049 12 10000 12965 ; 15108:c0548eca36e7fce0 16527:4033bb18646943a3 16648:408a977cb2edf5db 19115:fff0000000000000 32592:c07e5e3a84b6b89d 32973:4050b9c91b3eec4d 35858:c07f3431cdb5821b 38831:7ff0000000000002 39359:7ff0000000000002 ;
increase anchored 3652 0 56275 3651 19 300000 - ; 14671:408007b799a7068a 16070:c07135648a137a30 17565:4073af026bd58d22 19610:c085e508445a12a7 21464:4078f940a79eb460 42278:c0890ee08fb7b676 43330:c07fc6a84f0b701f 45423:408517746ccd1de8 47397:408c50b6e5ccea61 48603:c063130f2a05b0b9 49498:c07f6d596949100c 51529:4036ada8c2e53540 ;
increase anchored 1000 864 35990 702 20 1000 - ; 8509:7ff0000000000002 9359:7ff0000000000000 10734:7ff0000000000000 13708:7ff0000000000000 13784:7ff0000000000000 14698:7ff0000000000000 20023:7ff0000000000000 20268:7ff0000000000000 31755:7ff0000000000000 32681:7ff0000000000000 33882:7ff0000000000000 36059:7ff0000000000002 36494:7ff0000000000000 38408:7ff0000000000000 41051:7ff0000000000000 41273:7ff0000000000000 ; 37394:fff8000000000000 38096:fff8000000000000 39500:fff8000000000000 40202:fff8000000000000 42308:fff8000000000000 43010:fff8000000000000
increase anchored 3010 3589 5854 3010 5 300000 - ; 4072:404c5786206217b8 5305:404fec6e9f26cf56 5933:3feed8311674bd24 8581:4047597793a96b6d ; 8864:0 11874:402041250c7a2a4c 14884:4046de16cf4f9878
increase anchored 3095 -159 28739 3094 6 10000 - ; 12939:405106063c601e24 13697:4053640429d37487 30047:7ff0000000000002 31540:405c87fa6db241f8 33248:3feee0aecb6cd578 33532:40475e9a0dd074e3 33631:40499bc5882ea420 34002:404b30619b7735d0 34199:40501f9731ee8e02 36451:405232e1d399ed19 ; 31833:0 34927:40501f9731ee8e02 38021:40209a550d5af8b8
increase anchored 16153 3237 17656 3097 19 1000 - ; 8074:4056c32d197ee8c2 9174:c054eef94ff0a9c8 9267:406b015f694bfd8e 10403:c074f9e9d073eb4b 10794:408600422bdad53f 12305:7ff8000000000001 15028:c06182bd90109d71 15927:c07a7d97bc49ad13 18146:c074b2b2cf7968e2 36723:4073251adbf2bb0a 37874:c0656981fa308e2e 39123:7ff0000000000002 39686:7ff8000000000001 39894:c089fd410d9d58f4 42090:7ff8000000000001 44390:4084037caf5129e6 45334:406cdf06eec2b178 46886:c05137cbb9b8ed13 49066:406388f088c867c4 49381:c062f22ccf8c35ec 52218:4073c66f856aec38 53831:c088ed39e788a744 56364:7ff8000000000001 62554:c03a5c83c0a9e86d 63363:c075da093f572de8 ; 17656:7ff8000000000001 20753:c075be46cfabfd04 23850:c06fe6c3c5b771a5 26947:c06fe6c3c5b771a5 30044:c060f44f8e1b989f 33141:c074b2b2cf7968e2 36238:40572b93b34110c4 42432:c0656981fa308e2e 45529:7ff8000000000001 48626:408b3b3e6b01d644 51723:40891444f3cab8a0 54820:408b60ef5950e2b8 57917:40866dd8e6ece298 61014:7ff8000000000001 64111:7ff8000000000001 67208:4064b21279b71de0 70305:c0777fd17b61cc6f 73402:407a5aa253af8219
increase anchored 4779 -3547 11378 2386 13 300000 - ; 13142:407388c20b1f60e3 15581:c08450c9e87aab65 18253:7ff0000000000002 18781:c0890d4247d29b41 37018:c07b344d71457301 48380:c085ef9cbbec8ca7 69462:4050039c58050c54 69535:c071c1c0650bbecf 70456:c0873aa0ff053489 70517:c08ac1945f452863 ; 11378:0 13764:c08450c9e87aab64 16150:c096af061826a353 18536:c0890d4247d29b41 35238:4076e6371e5fc381 37624:4076e6371e5fc381
delta anchored 13557 9317 17957 2297 4 10000 - ; 19253:c087688906d0f106 28225:407f4c6570265486 28469:c07cede62fadf795 30270:c08aab4bc806bf9d 31462:8000000000000000 33907:c0848b2e8e8c5b1f 35643:c08e40aeaca18a72 36445:8000000000000000 ;
delta anchored 17673 0 11429 1908 18 300000 25517 ; 16107:405100e57b0127cc 17355:4053ad9b60e18d20 18813:4057433bbb3c92af 31277:405f01809168d81e 31863:40652ba3b1c0b567 34068:4069996733cd3d94 35279:406c37f5a80bf33d ; 11429:4039095900edab8c 13337:4039095900edab8c 15245:4039095900edab8c 17153:4039095900edab8c 19061:4039095900edab8c 20969:4039095900edab8c 22877:4039095900edab8c 24785:4039095900edab8c 26693:4039095900edab8c 28601:4039095900edab8c 30509:4039095900edab8c 32417:4039095900edab8c 34325:4039095900edab8c 36233:4039095900edab8c 38141:4039095900edab8c 40049:4039095900edab8c 41957:4039095900edab8c 43865:4039095900edab8c
delta anchored 294 -8152 22932 294 15 10000 - ; 548:fe37e43c8800759c 3527:7ff0000000000002 5741:fe37e43c8800759c 8652:fe37e43c8800759c 23924:fe37e43c8800759c 24912:fe37e43c8800759c 26031:fe37e43c8800759c 27015:fe37e43c8800759c ;
delta anchored 766 -1763 5382 765 12 3000 - ; 4859:404ace691f296edb 6438:405529673ffab928 7361:4057e30929de1df7 7967:405a25020d7f621e 9193:4061991006732df2 10675:4065a7c551401118 ; 5382:403f08cac19806ea 6147:4025cd0f4f1b2678 6912:40220fc71d0a2138 7677:40421a3bfecdf38c 9207:40403ad52b338c98
delta anchored 1008 6825 50791 1007 17 10000 - ; 8269:fe37e43c8800759c 8332:fe37e43c8800759c 11296:fe37e43c8800759c 13754:fe37e43c8800759c 16207:fe37e43c8800759c 17655:fe37e43c8800759c 18640:fe37e43c8800759c 20958:fe37e43c8800759c 21931:fe37e43c8800759c 22630:fe37e43c8800759c 23776:fe37e43c8800759c 24582:fe37e43c8800759c 24874:fe37e43c8800759c 26270:fe37e43c8800759c 26413:fe37e43c8800759c 26957:7ff0000000000002 28162:fe37e43c8800759c 36702:fe37e43c8800759c 38056:fe37e43c8800759c 40102:fe37e43c8800759c 56894:fe37e43c8800759c 57297:fe37e43c8800759c 69885:fe37e43c8800759c 70124:fe37e43c8800759c ; 63882:0 64889:0
delta anchored 1108 8341 16331 1108 5 3000 - ; 8913:40812367fb9f30ce 11574:c082258b8b2a353e 11993:408d362594c1118b 14077:40544e25caf4418d 14449:407e1d08eb0fd16d 14941:c0656182b8771c97 16651:c0698c1d179f2be3 17433:c08df8da7ed48b84 ; 17439:0 20763:4078257b3243c17a
resets anchored 18490 7481 42633 3404 17 10000 35488 ; 20392:40533bbbf3113a16 22755:3ffe206649edeacf 22890:403d528aea4598a2 25669:404f085ef12b2fb7 28490:40599f1c08bee535 29193:405befe8d24365f9 31110:405ca131c8b453c6 34075:40620ee83cb6a14b 35031:4067f66c71468df4 35862:40699ffed6969d50 36384:406b1760abf58a51 38670:407074cc20831a18 40983:4070c79b6dd2aa5b 42525:4071bd7eefabe2d2 45463:40725109e136071f 46050:4074734077b2b99f 47347:40765041f78561f6 47462:4079550eee2d8f70 ; 42633:3ff0000000000000 46037:3ff0000000000000 49441:3ff0000000000000 52845:3ff0000000000000 56249:3ff0000000000000 59653:3ff0000000000000 63057:3ff0000000000000 66461:3ff0000000000000 69865:3ff0000000000000 73269:3ff0000000000000 76673:3ff0000000000000 80077:3ff0000000000000 83481:3ff0000000000000 86885:3ff0000000000000 90289:3ff0000000000000 93693:3ff0000000000000 97097:3ff0000000000000
resets anchored 3755 0 69281 3755 13 300000 41459 ; 24837:408d16addd5395e6 26179:c0795033bdcbcbbb 28214:c07392e499eebf17 30075:c08a1e619ce1fce0 31147:c062c58546d1bbce 33465:c0715a73ed3e0b73 35042:c065fa91a4078529 36045:40764c56cc3b83b2 38078:408a05db3ca1c196 38557:7ff0000000000002 41118:4087ab0118b51e55 41788:c06efeabf2cccfb4 44714:c043e2b46e484032 44984:408667aaf035b2ae 46406:4067725048e78556 63654:c053eb297910e474 65672:405a55d5ee29e787 67823:c08d96a76b2e04e0 69071:c08dedffc6fc34b0 70934:c07c9f2d394c2225 72606:c053e7ad7c91fa1d 72901:c08d7906a0728643 ; 69281:3ff0000000000000 73036:3ff0000000000000 76791:3ff0000000000000 80546:3ff0000000000000 84301:3ff0000000000000 88056:3ff0000000000000 91811:3ff0000000000000 95566:3ff0000000000000 99321:3ff0000000000000 103076:3ff0000000000000 106831:3ff0000000000000 110586:3ff0000000000000 114341:3ff0000000000000
resets anchored 1000 0 11810 1502 8 300000 41867 ; 10086:4086ded57a657b31 12944:fff0000000000000 15051:408bb11ba7be6c59 16762:408ace6a598f2384 18778:c073ee200ca5c302 21567:c086ae5de878332f 22557:407e29bd181a51e0 25112:c04c894a1a7b72db 27244:c07ac9e04deefda7 27585:fff0000000000000 45755:c0769eea3ee7e3b7 46054:8000000000000000 ;
resets anchored 7935 4627 15168 3964 10 10000 19782 ; 13096:fe37e43c8800759c 15971:fe37e43c8800759c 17283:fe37e43c8800759c ; 15168:0 19132:0 23096:0 27060:0 31024:0 34988:0 38952:0 42916:0 46880:0 50844:0
resets anchored 8007 0 37919 413 12 10000 - ; 16783:fe37e43c8800759c 19749:fe37e43c8800759c 20608:fe37e43c8800759c 23184:fe37e43c8800759c 24874:fe37e43c8800759c 26528:fe37e43c8800759c 26984:fe37e43c8800759c 39907:fe37e43c8800759c 42633:fe37e43c8800759c 44748:fe37e43c8800759c 45663:fe37e43c8800759c 45876:fe37e43c8800759c 47512:fe37e43c8800759c 47609:fe37e43c8800759c 48864:fe37e43c8800759c 49544:fe37e43c8800759c 50383:fe37e43c8800759c 69492:fe37e43c8800759c 72290:fe37e43c8800759c ; 39984:0 40397:0 40810:0 41223:0 41636:0 42049:0 42462:0
resets anchored 1000 0 98349 2519 3 3000 - ; 7924:404aee9e667122d2 8906:40591c6267cf0406 10201:405d086041847788 12064:4061f7db64e71c70 31693:40637fc998483aa1 33083:4067f5f25b70a1f8 46772:3fb7629b3ff3a32a 66479:401bbb516ea3256d 68056:40302e19c80338dd 81776:403b4e73fc1a5868 81931:4051839be68d2596 104863:4052f2c42a4e364a 106828:4057778fc242ff28 107146:405ed3221f8e55aa 107972:4062216e7d7eabe7 108538:4063ce864309025d 108670:3ff813f0af5d8448 110613:4033aa6188e6125e 113345:404281024fe016cf ;
changes anchored 2464 0 28925 2463 6 10000 - ; 21308:fff0000000000000 21941:fff0000000000000 22599:fff0000000000000 24601:fff0000000000000 37984:fff0000000000000 39854:fff0000000000000 40151:fff0000000000000 ; 38777:0 41240:0
changes anchored 18173 5164 35889 3595 8 3000 76564 ; 18680:7ff8000000000001 20322:406da29152dc62a3 20464:7ff8000000000001 22421:4069de8e632c7f90 23624:c0836950478a9396 23858:40825d98791ee38e 26037:c07036842a8ccaf7 28943:c08962c97cff1e88 52768:7ff8000000000001 54002:407703398404780c 54931:4084c178eecf0c04 55924:c08df8d0c188bc43 66406:7ff8000000000001 67727:40551c0bddf3f9b8 68321:7ff8000000000001 90437:c06b45efc89b8802 92226:4089d248760eb798 93446:c076632114fd86ea 94260:c079ef5d398c3011 94842:4040206f11798515 95097:c058e38b009c9c60 95245:408020c5d310834c 97066:40732c5f2ff10249 99763:c072f8b4ca71312a 101491:408f2413a059dcfa ; 35889:4018000000000000 39484:4018000000000000 43079:4018000000000000 46674:4018000000000000 50269:4018000000000000 53864:4018000000000000 57459:4018000000000000 61054:4018000000000000
changes anchored 1000 3855 18659 2347 10 1000 18341 ; 4869:405b0c3643d3053e 7189:405e4041de12bbec 9806:406281d022cce15a 11123:40637a7fcd8e1614 14094:4067573e8dc4e0f0 16443:4067dc8c10a62f50 18665:406ddf9f65a1556e 20015:7ff0000000000002 20748:4071ea2d8cec025e 20887:4073631161d60148 21215:40758f6413fbf5ce 22762:4075d30ba19304bf 23231:40789216c23a9381 25552:4003af66cc7d531d 26761:7ff0000000000002 ; 18659:0 21006:0 23353:0 25700:0 28047:0 30394:0 32741:0 35088:0 37435:0 39782:0
changes anchored 3230 0 40590 3229 20 300000 - ; 14699:4060808ccab4cda7 17264:4062c15c45798849 17713:40184db6bc862150 20013:401c3449ae531ff7 20938:4038be27f2a16169 21766:404490fd36e9f800 22816:402223eec1b9bd0b 24937:4006cfc7b9bd2876 25575:40385966e5055933 26734:405034885f9034a1 29012:4057512cc6218d00 29559:405a7be33c57f3c4 46964:4060e28cb6631471 47406:4063892653050253 49874:4069b5dcdcc757ae 57072:406d438e2ff5ce78 59452:406e1fd025a1faca 61053:4070ec3f26f26bf2 79549:4072914517b270c9 ; 47048:3ff0000000000000 50277:4000000000000000 59964:4000000000000000 63193:3ff0000000000000 82567:3ff0000000000000
changes anchored 1000 2288 41045 3224 7 1000 - ; 15114:c08ba8f4511a0d5f 21538:408aa3e1c2b205b8 22859:7ff0000000000002 22936:c06e19fc15a274fc 25769:c058cf99a6ec031c 26500:40822d86898f226d 27941:c051c067aa73296a 30166:c061e3344fbae689 30385:c08da191f218c254 30561:7ff0000000000002 51874:c084dd878ba59d87 53505:c0651d6087baae4c 54685:408111156824479c 56075:c00034e8110a1930 58004:403e2fb89d32de98 61000:4085cc6c8ab6dce7 62986:c02673e34579d94a 64308:7ff8000000000001 65667:4056fca64bd22248 66705:c048262f83ddb522 69229:407ae51eca5c5d35 70162:7ff8000000000001 70964:406a2f5166055d5d ; 57165:3ff0000000000000 60389:0
changes anchored 1000 0 23116 3340 12 300000 - ; 4317:4037ac331b362eb7 5033:40405ea2a0a14f65 7082:404c6a9981eac166 8005:4054d2a4c8de62bb 9268:405eff0b1b6c2ede 9599:406592e71d0e401f 11704:4069068e3b4c957a 14161:4069be10f6348e92 16422:406a17913396134e 18303:406aa38b743b7422 18818:406f354823c8718b ;
rate smoothed 2641 -3060 62992 1317 17 1000 - ; 13843:4048aa20aac4e5b2 14902:40536a9fe02a2427 17617:4058d41ee7f207c9 17665:7ff0000000000002 19644:40624827ececeef3 22260:4065c89e1fa6fec8 25189:40677b30be5a7698 27338:402394305daef0e1 28510:4047dc7b2178c214 31085:40515eb71857be94 33364:405c1d08ff69a980 34983:4062fa9c58ee13e8 35803:406923fb21f25cdd 56682:406ef830f695e1f9 59660:407155bda622511a ;
rate smoothed 1000 0 58189 2919 19 10000 34157 ; 3056:4021c659bead8de8 4214:4018ed3e75f57383 4692:4033056429f94c46 7624:40405a1df1de0c37 9411:4045d39d38104d08 9704:404b0df115706e80 10386:4056240827f243b6 12933:406040607174720e 15543:4060ac407612be9f 17242:406551b49e4098b5 19917:4066cd9c323bdd42 20348:406c055cae1333ed 22625:406d4f239d72c949 24662:4070ca7d85441104 26340:4071fdc90de172b5 28650:4073546dcf20cd78 28793:40760f0fe4627e83 47525:407895e4d4c29fb2 60894:407a78d2e342759d ;
rate smoothed 2073 0 65868 2073 14 300000 - ; 16224:7e37e43c8800759c 17907:7e37e43c8800759c 18889:7e37e43c8800759c 34939:7e37e43c8800759c 49338:7e37e43c8800759c 51345:7e37e43c8800759c 53804:7e37e43c8800759c 54159:7e37e43c8800759c 55577:7e37e43c8800759c 57288:7e37e43c8800759c 59493:7e37e43c8800759c 61347:7e37e43c8800759c 61349:7e37e43c8800759c 63967:7e37e43c8800759c ; 65868:0
rate smoothed 1333 0 3332 1333 9 300000 - ; 1591:405815b60ec6eeba 3238:405e2eeb1282b1ec ; 3332:402b8885a1581390
rate smoothed 1210 4490 56269 1209 12 3000 - ; 13780:403ae3c88d046e8c 14708:404c6d1f75cdf3de 17683:3ffc5297bf295353 19068:4041cac3ed43be56 20903:4051a4252fb0de3f 22866:4054104988fca2f8 45595:405d75ec23e6fb93 48130:405ec5907c114ab1 50736:40145025e5185532 52876:40466e35b6ecb041 55604:40510db5dd722d76 56522:405b244ebf017bb0 58619:400b2cdfb1e49b50 60679:40306b1d168b4ae1 ; 56269:40304b1480014bac 57478:4031a96642554fc2 58687:40211f01e047dcfa 59896:40211f01e047dcf7 61105:404170e7128c50d0 62314:3ff9eb12a19b67d1 63523:4009d3c86bb1c34d 64732:401948d2f6a7c2b2 65941:40024e1c53c96d38
rate smoothed 1000 -9390 17461 445 3 300000 - ; 19157:fe37e43c8800759c 20516:fe37e43c8800759c 20620:fe37e43c8800759c 21069:fe37e43c8800759c 22233:fe37e43c8800759c 22497:fe37e43c8800759c 23383:fe37e43c8800759c 25129:fe37e43c8800759c 25480:fe37e43c8800759c 27336:fe37e43c8800759c 45541:fe37e43c8800759c 48082:fe37e43c8800759c 48339:fe37e43c8800759c 49706:fe37e43c8800759c 50910:fe37e43c8800759c 52542:fe37e43c8800759c ; 17461:0 17906:0 18351:0
increase smoothed 15878 -3594 18719 3372 14 300000 - ; 20984:4023a5694d957eda 22032:404bd3b84cc970c2 22167:40528322b7f12189 22843:4054d8f46288acba 24798:401e9547684ab04c 26636:4044aaa19f063f10 29423:40562f712874c381 ; 18719:40508f92eeec0cb6 22091:40585e10972af8e8 25463:406382a2205593fa 28835:406449dc30a56030 32207:406449dc30a56030 35579:4055be4ed54575dc 38951:404770c14ea279aa
increase smoothed 1000 3793 37613 2756 6 300000 - ; 10703:7ff8000000000001 11754:7ff8000000000001 14566:7ff8000000000001 14767:c071cdfeed175e81 15725:c076f0318692b593 17090:c06325e66ce9af38 17633:408823acda58cc1e 18368:c0707e5a211769cd 19659:40802c50505b36f9 40799:40868a558e77f4ff 42791:7ff8000000000001 44380:c0756e879019dedc 45049:7ff8000000000001 46201:408a2bec75684b04 46469:7ff8000000000001 47853:407128fb7e3b1044 48757:c03a82e6920159be 51124:c06fb775c8193bda 53844:402ddea22d03978f 54193:7ff8000000000001 56671:4089db33bfca4e00 59145:408a4cbf1d882edb 61792:407d3da46554f3cc ; 37613:402346c86c99dc80 40369:402346c86c99dc40 43125:402346c86c99dc80 45881:7ff8000000000001 48637:7ff8000000000001 51393:7ff8000000000001
increase smoothed 2294 0 7513 2294 16 300000 13069 ; 11100:c062d70b85a57a47 11529:7ff8000000000001 12596:c0805d2b4a7c9ba2 13506:4087d296e5e48d5d 14357:c05ceebaa128b0ca ; 7513:407277ee5c34663a 9807:407277ee5c34663a 12101:407277ee5c34663a 14395:407277ee5c34663a 16689:407277ee5c34663a 18983:407277ee5c34663a 21277:407277ee5c34663a 23571:407277ee5c34663a 25865:407277ee5c34663a 28159:407277ee5c34663a 30453:407277ee5c34663a 32747:407277ee5c34663a 35041:407277ee5c34663a 37335:407277ee5c34663a 39629:407277ee5c34663a 41923:407277ee5c34663a
increase smoothed 1926 -8951 30308 1926 3 3000 40176 ; 20628:4052cd31e2e51649 27763:4055b55102ac613d 30175:4059e01b9aedd676 30477:405f87948ce974e4 32468:40650eeb5cebbf5a 33870:40673725d635fe46 36656:4067a130a67a75b7 37982:406be2f2eb28c3aa 39221:406faaf465135686 41583:40708adb66cf7104 56266:40737bd079e7b4c2 73079:40747ac2bb0b3e35 74323:4076422cc2b2168a 74909:4077278a87b66f48 75539:40785334b3e53932 78525:4079d76564ad9b9a 99936:3fc7c6178f064348 101044:403a9bd0f177f659 ;
increase smoothed 1000 3775 26754 3808 2 3000 15710 ; 16547:7ff0000000000000 18932:7ff0000000000000 19186:7ff0000000000000 20523:7ff0000000000000 20667:7ff0000000000000 22174:7ff0000000000000 23797:7ff0000000000000 24223:7ff0000000000000 26841:7ff0000000000000 28847:7ff0000000000000 ;
increase smoothed 5365 9707 88208 2679 1 3000 - ; 35143:404dee7707474228 49752:4056cefb44d25b26 50963:4061428d133c6898 52373:40655f5b33150d32 54971:406561ff8ed502d5 75697:4069359bea315f63 78559:406a1ffaa22f2cce 89287:4070053285279c32 92242:4071033d81775f7e 92498:40739df826397e40 94850:4074167ed5da1ce0 116615:4076a09d16ec9b78 117448:4076f4ba8754a5a0 ; 88208:401cb3d9fa019660
delta smoothed 1000 -3564 2504 373 12 1000 - ; 6638:40525ba066c333dc 9202:4054976005516cdf 11513:405870dbacb8576a 12417:4061ccb65e13e4d5 ; 3250:0 3623:0 3996:0 4742:400bdfb4f58f8f20 5861:0 6234:0 6607:0
delta smoothed 3041 8573 21775 3120 14 1000 - ; 22028:404f7e185631c28f 23492:405ad425c6615c80 25667:405d46d925f98268 25809:401e86447412dd42 25830:4041c860c6a40584 26550:40516dc3b4d2da7a 28690:4055cb0c2f79dd36 28971:405672266cc7417b 30278:405dc9a78874e772 32609:40637f6cf3ec904d 34777:4065e1a9ea38f36a 35655:4068a42fbe0af0b4 38500:406d7643be5eef44 38647:40712348086cac88 ; 31135:40302b601d509236 34255:4037fef927d32a18 37375:4045c9c239ea4ea0 40495:404c1700580f64c6 43615:4039bbdc1bf9d520 46735:4047b4af259d9c50 49855:4043413149e9a730
delta smoothed 1000 -1686 50687 747 5 10000 32894 ; 21209:40126d6052a7b04c 21248:4022247f5eaf1daa 39868:404189b414758ff7 42214:404b884c6c6563fb 44571:404ed649e70c7496 46670:404fc3dc2dd45330 47888:4055ff815ec65ce9 49022:405f15c38717b9bb 49878:405ff77d121f8f13 52406:40617568fd3746ee 53653:40651bc64c9675dc 54893:4067abbdf2bb4b74 57744:406a277420c62369 71738:406f6d17ec66a5ca 73847:407178dfbdde6136 73860:4071b396866af87a ;
delta smoothed 1000 -3942 28077 1354 6 10000 - ; 7240:4051613c02526715 9604:40533f6801f44f52 11984:40534738b1cbd487 12676:4055366fd535200a 14568:7ff0000000000002 14844:405dc52d791ba11a 23835:40643dbc0985e0f3 25559:40680258afb118c6 31895:406b60e9861d1f32 32981:406cf0cf96118efe 34354:40714bb6454d7469 36908:40730291a994c471 37106:3ff3fad34d4a6c4a 37572:4047ba4175e7d8c5 ; 28077:40149d570b1bdf00 29431:4033e735f2c927b0 30785:4038a66baff3e400 32139:40257a998e6a7520 33493:c070935bfe17acfe
delta smoothed 7463 -6766 31881 3728 8 1000 6607 ; 6043:c070594b557dbfa4 6383:0 8587:407077a400322464 11249:408ec38f0085b73f 13413:c08d111e13518ae1 13996:405b49ab555a807d 14894:c07edb0289931910 15014:406ade5b9e90d9c0 15217:0 16823:406b829b257684cf 18067:408d84381395cca1 20015:7ff0000000000002 20581:8000000000000000 23250:7ff8000000000001 25177:40791bc3217324e1 26090:c088678cebb69297 26092:c080bc423d2195ac 27719:4080384cd9e633b6 29522:7e37e43c8800759c 31165:406b1f19a0ed697e 33453:7ff0000000000000 36451:408b6a11ae86772a ; 31881:c083c95a3cac070f 35609:c083c95a3cac070f 39337:c083c95a3cac070f 43065:c083c95a3cac070f 46793:c083c95a3cac070f 50521:c083c95a3cac070f 54249:c083c95a3cac070f 57977:c083c95a3cac070f
delta smoothed 5667 0 42617 2830 4 300000 - ; 19722:8000000000000000 21896:8000000000000000 23766:8000000000000000 26118:8000000000000000 29093:8000000000000000 31289:8000000000000000 33210:8000000000000000 35697:8000000000000000 37027:8000000000000000 54472:8000000000000000 56997:8000000000000000 58301:8000000000000000 60676:8000000000000000 67813:8000000000000000 69664:7ff0000000000002 93023:8000000000000000 93897:8000000000000000 ; 42617:0 45447:0 48277:0 51107:0
sum_over_time anchored 3779 -574 28241 3779 14 1000 - ; 15394:c061b01094917d95 16648:c0861f6a686b8c3b 18394:c0872a3cd06c992f 42598:405f66bcd94c5961 43882:c076ab32a25abba3 44341:c07ee08826dd081c 58799:c043c325a091b9ba 61393:c0840cd2371ce78d 63675:c075943b78713618 66360:4088c87cecc89510 ; error
resets smoothed 833 0 8763 3010 13 300000 - ; 9735:fff0000000000000 11303:fff0000000000000 13598:fff0000000000000 15646:7ff0000000000002 16023:fff0000000000000 17267:fff0000000000000 18848:fff0000000000000 19760:fff0000000000000 21507:fff0000000000000 23287:fff0000000000000 25726:fff0000000000000 28537:fff0000000000000 29804:fff0000000000000 31635:fff0000000000000 32316:fff0000000000000 34045:fff0000000000000 35812:fff0000000000000 37193:fff0000000000000 38650:fff0000000000000 39727:fff0000000000000 42296:fff0000000000000 42964:fff0000000000000 ; error
rate anchored 4000 1000 27000 4000 18 1000 24000 ; 2000:40406cd5f32ded5e 3000:404ff7def921b249 5000:7ff0000000000002 7000:4056e88d49582654 8000:405b44524b2b568e 10000:405f4a68564ad85e 26000:40624f0602309700 28000:4063677dc66fe737 31000:406615fa9678287e 34000:400019a3d6ac026b ;
rate anchored 4000 -5000 37000 4000 6 3000 - ; 16000:40424ab6bf684d3b 18000:4072a855eff91b89 21000:c07da9e8e547b025 22000:7ff0000000000000 24000:406fa25d56ba1b44 25000:c07c0ec31f14b6a7 27000:c08b3d1b1e820b52 29000:4082383033147c57 30000:fe37e43c8800759c 31000:c07a9890b63f2240 34000:40877176baa7d8e8 54000:408bb890f19ce56f 69000:c08815021b69709e 71000:406c33b30353621c 74000:c07da6a4342a812b 98000:c062ea3c7ae50cfa 101000:8000000000000000 104000:408b0497c0da6af7 107000:fff0000000000000 115000:408c24066ee148c0 124000:c061bd640cd60b26 125000:c074c60742a53a57 139000:c081b4700d58291e 141000:fe37e43c8800759c ; 49000:0
rate anchored 1000 0 24000 3000 9 3000 51000 ; 10000:7e37e43c8800759c 11000:7e37e43c8800759c 12000:7e37e43c8800759c 15000:7e37e43c8800759c 17000:7e37e43c8800759c 20000:7e37e43c8800759c 23000:7e37e43c8800759c 24000:7e37e43c8800759c 25000:7e37e43c8800759c 26000:7e37e43c8800759c 29000:7e37e43c8800759c 32000:7e37e43c8800759c 34000:7e37e43c8800759c 37000:7e37e43c8800759c 38000:7e37e43c8800759c 39000:7e37e43c8800759c 57000:7e37e43c8800759c 60000:7e37e43c8800759c 63000:7e37e43c8800759c 65000:7e37e43c8800759c 66000:7e37e43c8800759c ;
rate anchored 7000 0 23000 1000 19 1000 - ; 16000:40582eab53f62334 18000:405d2431217b68f4 19000:4061f108c67d5c3b 40000:4063b88309703cab ; 23000:401abea082539e4e 24000:400ed1b8c6d846e5 25000:400ed1b8c6d846e5 40000:0 41000:0
rate anchored 17000 7000 23000 1000 5 2000 25000 ; 20000:c0884ff71177f5cb 33000:c08ce6b9c872146c 34000:c0797fe42d6805ff 35000:c079ddba0d25f16c 36000:7ff0000000000002 39000:40826813b78c30df 42000:c08df243db27df23 43000:c079c5ba6281fd77 44000:4086f4e20c54d3d6 ;
rate anchored 8000 0 47000 4000 11 1000 - ; 19000:3ff4b5790ccefc38 20000:3ffc05c7d9a2693b 21000:4041a92dcbb6fc5f 30000:404a090359d11ddd 31000:40557796d236e3e2 32000:405730b9013735f8 35000:405ef8c95be83fda 38000:40606a8082ca838a 40000:4060b8c6b41ef8f1 43000:4066c86d4e84c269 45000:406971076143b482 ; 47000:402170815a497722 51000:400544d095f790c8
increase anchored 4000 6000 13000 2000 17 1000 10000 ; 7000:40654bfe87cf9193 8000:7ff8000000000001 16000:7ff8000000000001 18000:407e2d1fbb482afa 19000:c0832ab2681800be 22000:7ff8000000000001 23000:4076ac93651c05b7 24000:c085c98d9b5b47e7 ;
increase anchored 1000 -6000 22000 3000 3 2000 - ; 9000:4044c4def4849d8f 11000:404e5602cb75c1b4 13000:405b4173bf45321a 16000:405f68ab6c2ac263 19000:4060fd33880a67aa ;
increase anchored 4000 0 44000 4000 19 3000 - ; 13000:fff0000000000000 14000:fff0000000000000 16000:fff0000000000000 18000:fff0000000000000 20000:fff0000000000000 21000:fff0000000000000 24000:fff0000000000000 25000:fff0000000000000 45000:fff0000000000000 46000:fff0000000000000 49000:fff0000000000000 51000:fff0000000000000 54000:fff0000000000000 66000:fff0000000000000 68000:fff0000000000000 69000:fff0000000000000 71000:fff0000000000000 72000:fff0000000000000 ; 48000:fff8000000000000 52000:fff8000000000000 56000:fff8000000000000 68000:fff8000000000000 72000:fff8000000000000
increase anchored 3000 4000 53000 3000 14 10000 - ; 9000:40524b843508cc7a 10000:405c60954a2f3288 13000:405e33ea0c7ec982 16000:4061196e039c836c 36000:40654cb6a199a0dc 37000:406a7f8831660c58 39000:406b47bb9eb0a97f 42000:406f55daf68bcc1a 57000:4070a273de027eac 60000:40734d10bb92164d 66000:4074513e914be5d4 67000:407591ae175095f2 70000:4075d20dcade9e0a 71000:40783e56799289ca 72000:407941e7e4a90cb9 ; 62000:0 65000:404554e6ec7cbd08 71000:404224eaddf3fd28 74000:401017ece3820600 77000:404b7ed0ce537578
increase anchored 3000 0 36000 3000 18 1000 - ; 5000:7e37e43c8800759c 7000:7e37e43c8800759c 10000:7e37e43c8800759c 31000:7ff0000000000002 34000:7e37e43c8800759c 35000:7e37e43c8800759c 37000:7e37e43c8800759c 39000:7e37e43c8800759c ; 36000:0 39000:0
increase anchored 2000 4000 101000 1000 3 3000 - ; 25000:405cb7f7f72612fe 28000:40032d1edc1fd09c 30000:4048eb956dcc0390 33000:404a51867aadf906 36000:4051f2788eca2aac 37000:40597d07b9bab6b9 40000:40603965673aa390 41000:406407a9a6e65aed 62000:40645d4399cec612 72000:4066208f16ed4502 74000:4067c056decc1a50 92000:3fd836e7310b4fed 93000:40468f65df6d1ea4 116000:4053f99d47b7e510 122000:4056d31d4b2d6dbd 124000:40585b4e983d709d 125000:405950649489a8b6 128000:405bed7b1c8d3f25 131000:405cef64312dcbc4 133000:405dbe9fa2d1d7a2 134000:4063b5f29e81eb2c ;
delta anchored 1000 2000 11000 2000 20 10000 - ; 9000:c05d8503ad939600 15000:407982de81a545a9 18000:c08def07c5545504 ; 11000:0 17000:4080720fb6851594
delta anchored 2000 -8000 28000 2000 10 1000 - ; 3000:c089eeaace69a57c 6000:c07da43eb8895e22 8000:40766a96af09d1f5 10000:408111209e82984d 13000:40850590b03dd3e2 15000:407578c8fc7cfe32 18000:40421fb9552e1e95 21000:c08024df4b348da2 24000:408b2eef969f4056 27000:4075809fd821aba9 ;
delta anchored 3000 0 25000 3000 3 1000 - ; 16000:7ff0000000000000 18000:7ff0000000000000 21000:7ff0000000000000 24000:7ff0000000000000 26000:7ff0000000000000 ; 25000:fff8000000000000 28000:fff8000000000000
delta anchored 3000 8000 56000 1000 9 10000 - ; 19000:c08d9588899e8748 42000:c0839ab0f6a62637 45000:c05f5e9ff1aa5947 58000:0 60000:c0608df231cdf5f1 63000:4071e6651c74986a 64000:4052828fb70b4f37 65000:c07816ff79a33b06 68000:c0760b1b9802c818 69000:408d4e17e78c7bce 70000:4056a1dc22356f7d ;
delta anchored 8000 0 21000 1000 18 10000 - ; 5000:408c1abd21df83bd 6000:c032af48e414790b 8000:c08cee812f848e40 10000:c080868c7bb85f76 13000:408c901d7fb6f120 15000:7ff0000000000002 16000:40832331bb09ecc9 18000:406dd26de9e48460 21000:c0570975ca7f8fb3 23000:c04960809e523cc6 30000:408ec6fcf7e562f8 33000:c086d1e30e1a3b90 34000:c06db6e8dff41c1e 35000:c08bd16b42a8df59 37000:c071c65401c4e989 39000:c04bea00d85563ee 40000:7ff0000000000000 63000:c0897a6c439e8efb 64000:c088fd8f95488c09 66000:c07453eb235ab6f5 ; 21000:c08f714c3906e316 22000:c08f714c3906e316 23000:c08e2625899c14ec 24000:c084b939c4ef1095 25000:c084b939c4ef1095 26000:c072154708bc89c9 27000:c072154708bc89c9 28000:c072154708bc89c9 29000:4044b26af6ace2a0 30000:4090d415d89aaa77 31000:40902e8280e54362 32000:40902e8280e54362 33000:c0853bdb043517c4 34000:c0675ec8b85f8cec 35000:c08a3b6338c3bb8d 36000:c08a3b6338c3bb8d 37000:c06d3487dbf543e0 38000:c093d5137c63ebde
delta anchored 12000 4000 18000 1000 4 10000 14000 ; 6000:405440298f9f0500 7000:7ff0000000000002 10000:4055cf70785c680e 13000:405fbcd785f68717 14000:4065d91d9008b7c4 17000:40686d4d9bdb96e5 18000:4069bb70f4491255 21000:406fbea42fe50259 24000:40726894cce41315 27000:407472b106df46ac 30000:407732fc75e31b44 32000:40787161935e143d 34000:407a7f0f7fb1ff2b 35000:407d94f536474ed4 38000:407ead2328c72c6d ; 18000:4018f46e8bd630e0 19000:4018f46e8bd630e0 20000:4018f46e8bd630e0 21000:4018f46e8bd630e0
resets anchored 1000 -3000 26000 2000 8 10000 28000 ; 17000:fe37e43c8800759c 19000:fe37e43c8800759c 20000:fe37e43c8800759c 21000:fe37e43c8800759c 24000:fe37e43c8800759c 26000:fe37e43c8800759c 28000:fe37e43c8800759c ;
resets anchored 9000 9000 -1000 1000 7 1000 - ; 3000:4046c704279c72b3 4000:404ca616b22de091 5000:405764e1c936cfaa 8000:4061ee995735a2b6 9000:4067d1216a6a8a7a ;
resets anchored 1000 0 10000 3000 5 2000 - ; 13000:fe37e43c8800759c 24000:fe37e43c8800759c 25000:fe37e43c8800759c 26000:fe37e43c8800759c 27000:fe37e43c8800759c ; 13000:0
resets anchored 2000 0 60000 2000 16 10000 15000 ; 13000:c0795554fd9f4646 16000:fe37e43c8800759c 17000:c05718a4f8bf229e 19000:40458870bf33cb46 20000:c072b8103aab708a 23000:c07e5150f7cf8a77 25000:c081add687fd50dd 26000:407f4f40e4b9aa71 29000:408423b4e4ade483 30000:c0602d5d80909295 32000:407946d1f5d9202f 34000:c08d67714b579a36 37000:407e93189bc737f4 40000:fe37e43c8800759c 43000:c07e8de139ee23af 46000:40771368aeccaa7f 48000:4062200bd9fdf36f 50000:405be563a33c3f41 52000:c08901bd7511618f 53000:c076e8bcda3d4912 54000:c081a85c69cfe861 56000:c08bb3889b39687e 59000:c07f10ece6b63caf 61000:c073b1971a969c20 62000:408ac5ff2505c160 ;
resets anchored 1000 1000 28000 3000 17 1000 - ; 3000:4089d2d854555af1 4000:c0450daefc6bbb55 6000:40509bb96d768405 7000:7ff8000000000001 10000:c06a400af929bdc4 11000:c07819a9a50bdd13 13000:402f0e8bc5f0f400 16000:4087a8044c02c270 19000:7e37e43c8800759c 20000:c08899a3128e6be9 22000:0 32000:7ff0000000000002 35000:408b88de6756aa14 37000:4085e2c2bee19698 40000:408e1d69dce2bdef ;
resets anchored 3000 0 15000 3000 2 2000 - ; 17000:40519c286a70b98d 19000:4058d71c5dee08c9 21000:405ee5549f5e4ddd 22000:406391b5c447bc47 ; 18000:0
changes anchored 20000 -7000 47000 1000 11 3000 - ; 13000:c076e396aa61d8e3 16000:c084724f80ced482 18000:408b15141a243b0b 21000:7ff0000000000002 22000:c08dceafcf03c5eb 25000:c0888d6477098fd2 28000:40875392cb95208c 29000:4072d331defb5985 32000:c0712edfca2cba63 34000:40890d69c65cad25 37000:c0745f9a85cca161 38000:7ff8000000000001 40000:408c586a51004a72 43000:c06d10f6cd1254a0 44000:40740c0538dc7cb7 45000:7ff0000000000002 47000:7ff8000000000001 48000:40865a2f0ac18233 50000:c07c5967907c4db9 51000:c06e88c312990fb7 52000:c08c9827646edbec 54000:7ff8000000000001 55000:7ff8000000000001 56000:408365020bb6631c ; 47000:4026000000000000 48000:4026000000000000 49000:4028000000000000 50000:4026000000000000 51000:4024000000000000 52000:4024000000000000 53000:4022000000000000 54000:4022000000000000 55000:4022000000000000 56000:4020000000000000 57000:401c000000000000
changes anchored 3000 0 20000 3000 15 3000 - ; 16000:4056f369bfd3ccc4 19000:405e58ccc4809bfa 21000:40642bc752cde74a ; 20000:3ff0000000000000 23000:3ff0000000000000
changes anchored 8000 0 47000 4000 18 1000 - ; 17000:404310404aeb78ca 19000:404d2affef50ae06 21000:404e5ce902ea5bde 23000:405a8675a589af18 25000:405f545627530bd4 28000:4063f7e073e77ef1 29000:40646e8be58bd5d0 30000:4067dc5f2a8927bd 31000:4068330c85346bdf 34000:406c27d1c7246a2c 35000:406fb6847dc261e2 38000:40716801201b72c0 39000:4071b9e64af05e03 42000:407289b022a1ab84 64000:4072be4bae621a28 65000:4075cb4848adbf18 67000:4009a31efa509e3a 68000:402e2d2f55df24a4 69000:401ca2b9a59851a1 71000:40490465d1f8f601 74000:40538d2b46afbe6e 77000:405be54400b8c909 80000:4062a9740b28284e ; 47000:3ff0000000000000 67000:4000000000000000 71000:4014000000000000 75000:4010000000000000 79000:4000000000000000 83000:3ff0000000000000 87000:0
changes anchored 6000 -9000 21000 1000 2 3000 - ; 7000:7ff8000000000001 8000:7ff8000000000001 9000:7ff8000000000001 32000:7ff8000000000001 33000:7ff8000000000001 36000:7ff8000000000001 ;
changes anchored 3000 -3000 27000 3000 8 10000 - ; 21000:4040228a01e3a7a3 22000:408592d318571d07 23000:c08e32da768b60e0 25000:408a56b6806baef1 26000:407c7d0d3bed82f4 29000:c08d3c72eceb6f1e 32000:40747d9475c27a02 ; 27000:3ff0000000000000 30000:3ff0000000000000
changes anchored 1000 5000 39000 1000 13 1000 - ; 33000:40611a8ee39c52bb 35000:406226e01cc066b5 36000:406361639494d980 39000:40685d54dc02607d 40000:406b3bfc13a8e7e4 42000:406cb7f25a9ba427 44000:406dfed18569e20d 46000:406ff8715eb720b7 47000:4071619057f74530 49000:407169a6476013a2 50000:4006f8cbb368eff2 69000:40395afab2e074be 75000:405049b6677b9d98 77000:4053450cd70bdc5f 78000:405995ff9bd69ac9 79000:405eb34c15b858fb 80000:40638a9bf7ae0f92 ; 40000:0 41000:3ff0000000000000 44000:0 45000:3ff0000000000000 47000:0 49000:0 51000:0
rate smoothed 8000 7000 30000 1000 8 3000 - ; 12000:40605eac2e9fe8e4 14000:406285fb9cbc7609 28000:401a301ce64fe526 30000:403ac192995a47f2 ; 35000:0 36000:3ff4358b5fc64ea9 37000:4004358b5fc64ea8
rate smoothed 8000 -8000 13000 4000 6 3000 - ; 11000:fe37e43c8800759c 14000:fe37e43c8800759c ; 13000:0
rate smoothed 8000 4000 134000 3000 17 2000 - ; 39000:40548d58eedd4a5a 54000:4060653ef5b63223 56000:4061a51c550966cd 59000:4063257ee903cda7 62000:4019ed5c5f259db0 63000:402e68b7146de8f7 64000:4038d7a2fe627d10 66000:40476964896e2f25 69000:40500d846da5b557 71000:405963ee9d80ccb8 73000:405bb88f9b0f9dbe 75000:405c208fda69d776 78000:405e87a02bc1fa33 80000:4062d93401c94466 82000:40669e3b3e92b14a 103000:406923050c3ab449 106000:406c4f6a24e40b87 109000:4020487ee57323ad 126000:4040ad0fccdf3384 128000:404f6e1dea9e45b6 130000:4051929895f0bf5c ; 134000:401278215f024b34 137000:401278215f024b34 140000:3fedb89a0a19c810
rate smoothed 2000 9000 27000 4000 11 2000 - ; 21000:c0820020e89e5a1e 22000:408dd8fe18bf82cb 23000:c08ae14221abb881 26000:c06c90e7c7ee8d95 28000:c05f7d8e6563eef6 29000:406129448bbe05ed 32000:4089d62eacd9220a ; 31000:4087ec8f80aeee74 35000:406a51603f95717a 39000:406ed1443b29146a
rate smoothed 4000 -3000 15000 2000 6 10000 9000 ; 10000:7ff8000000000001 11000:408232d425ec7df8 13000:40578fc51240e9f5 ; 15000:7ff8000000000001 17000:7ff8000000000001 19000:7ff8000000000001 21000:7ff8000000000001 23000:7ff8000000000001 25000:7ff8000000000001
rate smoothed 3000 0 37000 3000 13 2000 - ; 7000:c0807e0133901042 12000:407d6c6d2d9997e7 15000:7ff0000000000002 18000:7ff8000000000001 19000:c067818922a6174f 22000:40850d143623c6d0 24000:7ff0000000000002 25000:7ff8000000000001 26000:7ff8000000000001 29000:40872365ca9a9d19 30000:407a46b8a9cb5b8a 31000:4082b3e2d5801ee1 32000:407815b2dfc0dc11 35000:c068926d4bb2c8f0 37000:c070b0fdfddb77b7 38000:4080ae0997bde787 41000:c082fe4eead5adb4 44000:408bfe1db58a5549 47000:c08ecba650721ed2 49000:c08e2a3aa30729ee ; 37000:c0564152a7cf4a49 40000:40607bfe310a7855 43000:4074e1f763b8e4e2 46000:c06b5fb04781e281 49000:401ae74791d37b55
increase smoothed 7000 6000 31000 2000 14 1000 - ; 15000:8000000000000000 16000:8000000000000000 17000:8000000000000000 20000:8000000000000000 23000:8000000000000000 25000:8000000000000000 28000:8000000000000000 31000:8000000000000000 33000:8000000000000000 34000:8000000000000000 49000:8000000000000000 50000:8000000000000000 52000:8000000000000000 55000:8000000000000000 57000:8000000000000000 59000:8000000000000000 60000:8000000000000000 63000:8000000000000000 65000:8000000000000000 66000:8000000000000000 ; 31000:0 33000:0 35000:0 37000:0 39000:0 41000:0 43000:0 45000:0 55000:0 57000:0
increase smoothed 1000 0 42000 3000 12 10000 30000 ; 11000:fff0000000000000 13000:fff0000000000000 15000:fff0000000000000 17000:fff0000000000000 18000:fff0000000000000 21000:fff0000000000000 23000:fff0000000000000 24000:fff0000000000000 27000:fff0000000000000 28000:fff0000000000000 30000:fff0000000000000 32000:fff0000000000000 34000:7ff0000000000002 35000:fff0000000000000 36000:fff0000000000000 39000:fff0000000000000 40000:fff0000000000000 41000:fff0000000000000 42000:fff0000000000000 45000:fff0000000000000 ; 42000:fff8000000000000 45000:fff8000000000000 48000:fff8000000000000 51000:fff8000000000000 54000:fff8000000000000 57000:fff8000000000000 60000:fff8000000000000 63000:fff8000000000000 66000:fff8000000000000 69000:fff8000000000000 72000:fff8000000000000 75000:fff8000000000000
increase smoothed 16000 0 32000 1000 2 10000 32000 ; 17000:c0634d306d68d18b 18000:7ff8000000000001 21000:c08f2025be7eada1 24000:40711a573a7a0f2b 27000:407f9a897e07173d 29000:c04ce1b55220086a 32000:c08546e99950ad49 35000:c08723f2fb082970 36000:408a5d4c587db59b 45000:c08b0b2666e607fd 47000:406237910cc595c2 50000:40754fa3bfc2805e 52000:c06a1aaa84e836e1 54000:c0878649c253c6db 56000:c07362e0a345b506 59000:7e37e43c8800759c ; 32000:c053a3a0a0a76e70 33000:c053a3a0a0a76e70
increase smoothed 1000 -6000 61000 1000 20 10000 - ; 7000:c07b8af008fec86d 10000:4082d94be5a11bba 12000:c08489df6e2fe3a8 14000:408a3161368b06c9 16000:c0603d960152e964 17000:c082b4eccc283557 39000:c059daefc7040b48 41000:40647b53ac693309 44000:c0875e542f136dd4 46000:c0753d3a149894eb 49000:c06fb0612689e8e7 51000:c077399afc9850c2 54000:c07340dc4cd751d6 55000:4081a073ccc98e08 58000:c08c7be2bf18126c ;
increase smoothed 1000 -3000 23000 1000 1 10000 91000 ; 6000:4054396a10776bf8 8000:40557a68d920e118 9000:4013b71979b64cba 30000:4040696d2ef66bcd 32000:4054443988337fc9 35000:405881fa3122f065 36000:405bef2e57844214 38000:4060c2f2da829e38 56000:40635cc9cc5b79c0 59000:406861e34591932e 72000:406d66b77c5e41be 75000:40206e9cc3b90538 77000:4026b140627e8f22 80000:404e9173bcca4604 81000:405504df5b379130 84000:4056905dc1715bb6 86000:4023d98e79c6b072 92000:404d0bbda11100f0 94000:4051474014d812a9 97000:405dc45e5c2922fc 98000:405fa716ef3c6a68 101000:3fee178968962127 104000:4042af5bf26b2f1b 128000:4050e68d016658f5 ; 23000:40160b0a227c9188
increase smoothed 2000 0 45000 1000 10 10000 - ; 16000:40562af6aac4536a 19000:405aa97c40f78c50 22000:3ff22f538269c50f 23000:4039fff3686ffa77 24000:4047f68e589e3db4 25000:4050053ed416a43d 26000:40557497be604856 28000:405bf2f071c1eba9 31000:40610694894ca539 34000:406332fb54fd59a5 35000:40635caa0fc1fdc4 48000:4066054ee9c09cad 49000:406bbc11ef2b93f4 52000:407069f902b2876a 57000:4072a0a3d9b70dd2 58000:4014726d436eb91e 61000:402de5bb2a3f5f4d ; 45000:400a2db99d7c4400 46000:400a2db99d7c4400 48000:0 49000:4046db0c15abdd1c 50000:404da58c334dd648 51000:403b2a007687e4a8 52000:403b2a007687e4a8 53000:4034aa561e85a078 54000:402c55578d06b860
delta smoothed 2000 -9000 32000 1000 18 2000 - ; 17000:408c65bd3c2245c2 37000:4066c3081c643352 39000:7ff0000000000002 41000:c0759d738f23c30d 42000:7ff0000000000000 44000:c063e5fa7d05ab4f 46000:408bdab60d097eca 49000:c0834df035d3ba87 ; 32000:0 33000:7ff0000000000000 34000:fff8000000000000 35000:fff0000000000000 36000:fff8000000000000 37000:40906a1a562574cf 38000:40363c5d50cc3690 39000:c08f706ed73e2635 40000:c08f706ed73e2636 41000:0
delta smoothed 1000 -1000 6000 2000 8 1000 14000 ; 5000:7e37e43c8800759c 26000:7e37e43c8800759c 28000:7e37e43c8800759c 30000:7e37e43c8800759c 33000:7e37e43c8800759c 35000:7e37e43c8800759c 36000:7e37e43c8800759c 44000:7e37e43c8800759c 46000:7e37e43c8800759c 49000:7e37e43c8800759c 51000:7e37e43c8800759c ;
delta smoothed 1000 0 27000 1000 13 2000 19000 ; 22000:404b915586fba7b9 23000:4051584b0fccc123 ;
delta smoothed 1000 1000 38000 1000 9 1000 68000 ; 11000:4084438a06ca1209 12000:408e42caba9fbbad 13000:c081dfec40e0c343 16000:c041b75ead0e6248 18000:4078e1537b3df263 21000:c08e122e7713b614 24000:40606d898919f696 26000:c041dbf6d0acd9d5 29000:c086b141fc51005f 30000:406c1ed3bb7a7784 32000:7ff8000000000001 34000:7ff8000000000001 37000:7ff8000000000001 39000:408af6130ff1df64 42000:408617ebd0998a1d 45000:4083c4262d0621a2 46000:4087ca9394810f6e 49000:407795e71f384399 50000:404a6b82cc45a31f 62000:4087696823946f5c 63000:c07dd21e9f099c93 64000:405d7cd019ad3a82 66000:c08ea6eab1fbdaa9 ;
delta smoothed 5000 0 44000 1000 7 2000 - ; 14000:7ff8000000000001 15000:7ff8000000000001 16000:7ff8000000000001 32000:7ff8000000000001 35000:7ff8000000000001 37000:7ff8000000000001 54000:7ff8000000000001 55000:7ff8000000000001 58000:7ff8000000000001 59000:7ff8000000000001 62000:7ff8000000000001 63000:7ff8000000000001 65000:7ff8000000000001 67000:7ff8000000000001 91000:7ff8000000000001 93000:7ff8000000000001 95000:7ff8000000000001 ;
delta smoothed 2000 8000 1000 1000 14 3000 - ; 6000:c07fbab882d565c9 7000:c05f00806903debb 8000:8000000000000000 11000:fff0000000000000 14000:c076f997069dfd25 16000:c076f769d5d1c420 18000:4084f08d7118eda5 38000:7ff0000000000000 ; 14000:0
sum_over_time anchored 2000 3000 36000 2000 18 3000 - ; 10000:4053192f704357ca 11000:405dc834c382e588 14000:40646db7892deb54 15000:40668f319496236a 16000:4017e34efe7f6577 19000:403465a6ba815223 20000:7ff0000000000002 22000:404ccc8d885c356a 24000:40536325643a3575 25000:400d633dafcc61cd 32000:400fb879f879edb8 42000:402380a54d79d914 44000:403c0791714ba724 45000:40447ec39b2a6eed 48000:400516cff8130018 51000:40365b5c06a01bb1 52000:404c42c122b09838 55000:7ff0000000000002 57000:40596af11fe20f24 58000:405ef9ff7ec0035d 61000:4060b3c01a3ba108 ; error
resets smoothed 6000 4000 8000 3000 16 1000 - ; 5000:40611da7aa37842d 8000:c054425e84827c15 9000:7ff0000000000002 ; error
+252 -2
View File
@@ -39,8 +39,8 @@ use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use super::{
CounterReset, FloatWindow, RangeEvaluator, RangeFunction, RangeWindow, WindowKernel,
subquery_grid,
CounterReset, FloatWindow, RangeEvaluator, RangeFunction, RangeModifier, RangeWindow,
WindowKernel, subquery_grid,
};
use crate::evaluated::EvaluatedChunk;
use crate::functions::{
@@ -653,6 +653,7 @@ fn random_window(rng: &mut StdRng) -> (Arc<EvalGrid>, RangeWindow) {
range_ms,
offset_ms,
anchor_ms,
modifier: None,
},
)
}
@@ -917,6 +918,7 @@ fn an_ordinary_float_chunk_is_appended_in_bulk() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
);
assert!(evaluator.push(&chunk(&rows, 2, 0, true)).unwrap().is_some());
@@ -959,6 +961,7 @@ fn a_chunk_with_histograms_is_not_appended_in_bulk() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::PresentOverTime,
)
@@ -1099,6 +1102,7 @@ fn a_selected_histogram_keeps_its_start_timestamp() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
function,
)
@@ -1157,6 +1161,7 @@ fn a_computed_histogram_drops_its_start_timestamp() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::SumOverTime,
)
@@ -1208,6 +1213,7 @@ fn a_retained_histogram_is_charged_for_its_buckets() {
range_ms: 600_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
// A function that counts the histogram, so what the row holds is a float: the two
// figures then differ in the payload of the retained sample alone, not in what the row
@@ -1259,6 +1265,7 @@ fn an_evicted_histogram_releases_its_payload() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::CountOverTime,
)
@@ -1313,6 +1320,7 @@ fn a_fixed_window_over_histograms_keeps_the_estimate_bounded() {
range_ms: 1,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::CountOverTime,
)
@@ -1348,6 +1356,7 @@ fn a_batch_spanning_fields_and_the_flush_threshold_matches_the_per_window_path()
range_ms: 30_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
// Counter-like values, each field resetting at a different point, growing at a different
// rate, and missing at a different interval. The gaps are what make the fields' windows
@@ -1455,6 +1464,7 @@ fn a_histogram_window_keeps_rate_on_the_per_window_path() {
range_ms: 30_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::Rate,
)
@@ -1480,6 +1490,7 @@ fn a_function_without_a_batch_form_stays_on_the_per_window_path() {
range_ms: 30_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
},
RangeFunction::SumOverTime,
)
@@ -1494,6 +1505,7 @@ fn empty_input_and_series_without_results() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
probe_evaluator(1, grid(0, 10, 4), window).finish().unwrap();
@@ -1541,6 +1553,7 @@ fn a_push_that_completes_nothing_hands_out_no_chunk() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(10, 10, 3), window);
// The only sample sits inside the first window, so the first point cannot be settled yet: no
@@ -1587,6 +1600,7 @@ fn a_series_that_ends_early_still_closes() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(0, 10, 5), window);
let first = chunk(&[(0, vec![Some(1.0)]), (10, vec![Some(2.0)])], 1, 0, false);
@@ -1626,6 +1640,7 @@ fn decided_missing_positions_cost_no_rows_and_do_not_delay_the_close() {
range_ms: 1_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = RangeEvaluator::try_new(
&raw_schema(1),
@@ -1681,6 +1696,7 @@ fn the_closing_chunk_is_labelled_like_the_chunks_before_it() {
range_ms: 20,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator =
RangeEvaluator::try_new(&raw_schema(1), grid(0, 10, 6), window, RangeFunction::Rate)
@@ -1762,6 +1778,7 @@ fn one_ms() -> RangeWindow {
range_ms: 1,
offset_ms: 0,
anchor_ms: None,
modifier: None,
}
}
@@ -1921,6 +1938,7 @@ fn a_sparse_series_folds_like_the_same_data_with_explicit_nulls() {
range_ms: 3_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let rows = [
(0, vec![Some(1.0)]),
@@ -1967,6 +1985,7 @@ fn a_window_reads_across_the_gap_between_runs_of_one_series() {
range_ms: 11,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator =
RangeEvaluator::try_new(&schema, grid(10, 1, 1), window, RangeFunction::SumOverTime)
@@ -2008,6 +2027,7 @@ fn raw_chunk_boundaries_do_not_change_the_rows() {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let rows = [
(0, vec![Some(1.0)]),
@@ -2136,6 +2156,7 @@ fn an_anchored_replay_stays_one_contiguous_piece() {
range_ms: 10,
offset_ms: 0,
anchor_ms: Some(5),
modifier: None,
};
for step_invariant in [true, false] {
let mut evaluator = if step_invariant {
@@ -2202,6 +2223,7 @@ fn rejects_invalid_parameters() {
range_ms: 0,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
assert!(matches!(
RangeEvaluator::try_new(
@@ -2217,6 +2239,7 @@ fn rejects_invalid_parameters() {
range_ms: 10,
offset_ms: i64::MAX - 20,
anchor_ms: None,
modifier: None,
};
assert!(matches!(
RangeEvaluator::try_new(
@@ -2232,6 +2255,7 @@ fn rejects_invalid_parameters() {
range_ms: 10,
offset_ms: 1,
anchor_ms: Some(i64::MIN),
modifier: None,
};
assert!(matches!(
RangeEvaluator::try_new(
@@ -2257,6 +2281,7 @@ fn rejects_invalid_chunk_sequences() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let new = || probe_evaluator(1, grid(0, 10, 4), window);
let row = |timestamp| (timestamp, vec![Some(1.0)]);
@@ -2295,6 +2320,7 @@ fn offset_overflow_fails_unless_the_sample_is_stale() {
range_ms: 10,
offset_ms: 10,
anchor_ms: None,
modifier: None,
};
let late = i64::MAX - 5;
let mut evaluator = probe_evaluator(1, grid(0, 10, 4), window);
@@ -2343,6 +2369,7 @@ fn histogram_samples_need_a_function_and_drop_stale_markers() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
assert!(matches!(
probe_evaluator(1, grid(0, 10, 4), window).push(&piece),
@@ -2369,6 +2396,7 @@ fn retains_only_samples_later_windows_need() {
range_ms: 50,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(0, 10, 1_000), window);
let rows: Vec<Row> = (0..10_000).map(|i| (i, vec![Some(1.0)])).collect();
@@ -2389,6 +2417,7 @@ fn reset_index_is_released_with_the_samples_it_reaches_back_to() {
range_ms: 50,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(0, 10, 1_000), window);
// A sawtooth that resets every 10 samples.
@@ -2435,6 +2464,7 @@ fn counter_resets_follow_the_window_and_survive_chunking() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
// Every chunk starts on a sample an earlier window corrected, so the index has to reach
// across the chunk boundary.
@@ -2558,6 +2588,7 @@ fn nulls_change_the_reset_positions_of_each_field_independently() {
range_ms: 100_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
// One entry per kernel call, in field order within each grid point.
@@ -2780,6 +2811,7 @@ fn rejects_input_of_the_other_kind() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let evaluated = SeriesSchema {
fields: raw_schema(1).fields,
@@ -2878,6 +2910,7 @@ fn range_functions_match_prometheus() {
range_ms,
offset_ms,
anchor_ms,
modifier: None,
};
let mut expected = vec![vec![None]; points as usize];
for (timestamp, value) in &expected_points {
@@ -2917,6 +2950,7 @@ fn rejects_double_exponential_smoothing_factors_outside_the_unit_interval() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
for (smoothing, trend) in [(0.0, 0.5), (1.0, 0.5), (0.5, 0.0), (0.5, 1.5)] {
let evaluator = || {
@@ -2967,6 +3001,7 @@ fn range_functions_drop_metadata_labels() {
range_ms: 10_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let rows: Vec<Row> = vec![(1_000, vec![Some(1.0)]), (2_000, vec![Some(2.0)])];
let nameless = MetricName::try_new(None, labels(&["host"])).unwrap();
@@ -2998,6 +3033,7 @@ fn ts_of_extremum_moves_past_a_leading_nan() {
range_ms: 10_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let rows: Vec<Row> = [(1_000, f64::NAN), (2_000, 5.0), (3_000, 7.0)]
.map(|(ts, value)| (ts, vec![Some(value)]))
@@ -3030,6 +3066,7 @@ fn waiting_for_a_point_drops_samples_behind_its_window() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(0, 100_000, 2), window);
for chunk_index in 0..900 {
@@ -3058,6 +3095,7 @@ fn ts_of_last_over_time_reports_zero_for_negative_timestamps() {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let rows: Vec<Row> = vec![(-1_000, vec![Some(7.0)])];
for (function, expected) in [
@@ -3087,6 +3125,7 @@ fn quantile_picks_the_signed_zero_go_picks() {
range_ms: 20_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let (z, n) = (0.0, -0.0);
let values = [
@@ -3146,6 +3185,7 @@ fn samples_after_the_last_window_are_validated_but_not_retained() {
range_ms: 10,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(0, 10, 2), window);
for chunk_index in 0..900 {
@@ -3160,6 +3200,7 @@ fn samples_after_the_last_window_are_validated_but_not_retained() {
range_ms: 10,
offset_ms: 10,
anchor_ms: None,
modifier: None,
};
let late = i64::MAX - 5;
let mut evaluator = probe_evaluator(1, grid(0, 10, 4), window);
@@ -3190,6 +3231,7 @@ fn anchored_predict_linear_regresses_around_each_point() {
range_ms: 30,
offset_ms,
anchor_ms: Some(50),
modifier: None,
};
let mut evaluator = RangeEvaluator::try_new(
&raw_schema(1),
@@ -3225,6 +3267,7 @@ fn rejects_a_subquery_grid_longer_than_u64() {
range_ms: 7,
offset_ms: -6,
anchor_ms: None,
modifier: None,
};
assert!(matches!(
subquery_grid(outer, window, 1),
@@ -3240,6 +3283,7 @@ fn anchored_window_before_the_series_retains_nothing() {
range_ms: 10,
offset_ms: 0,
anchor_ms: Some(5),
modifier: None,
};
let mut evaluator = probe_evaluator(1, grid(100, 10, 3), window);
for chunk_index in 0..100 {
@@ -3293,6 +3337,7 @@ fn absent_over_time_is_absent_over_present_over_time() {
range_ms,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut present = Vec::new();
let mut expected = None;
@@ -3448,6 +3493,7 @@ fn histogram_range_functions_match_prometheus() {
range_ms: case.spec[1].parse().unwrap(),
offset_ms: case.spec[2].parse().unwrap(),
anchor_ms: None,
modifier: None,
};
// One chunk per sample also checks that histograms survive across chunks.
for split in [false, true] {
@@ -3535,6 +3581,7 @@ fn evaluated_histograms_drop_counter_reset_hints() {
range_ms: 30,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let mut evaluator =
RangeEvaluator::try_new(&schema, grid(10, 10, 1), window, RangeFunction::Resets).unwrap();
@@ -3617,6 +3664,7 @@ fn a_valued_prefix_composes_with_an_empty_closing_chunk() {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let points = Points::from([
(0, f64::to_bits(1.0)),
@@ -3707,6 +3755,7 @@ fn one_step_window(step_ms: i64) -> RangeWindow {
range_ms: step_ms,
offset_ms: 0,
anchor_ms: None,
modifier: None,
}
}
@@ -4183,6 +4232,7 @@ fn a_window_at_a_later_run_reads_the_earlier_run() {
range_ms: 12_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let outer = grid(11_000, 1_000, 1);
let mut evaluator =
@@ -4383,11 +4433,13 @@ fn two_composed_evaluators_agree_with_the_dense_reference() {
range_ms: 3_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let outer_window = RangeWindow {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: None,
};
let rows = vec![
(0, vec![Some(1.0)]),
@@ -4490,3 +4542,201 @@ fn two_composed_evaluators_agree_with_the_dense_reference() {
"the composition lost or invented a value"
);
}
/// The `anchored` and `smoothed` range modifiers evaluated by the Prometheus v3.15.0 engine; see
/// the header of `modifier_cases.txt`. Each case is pushed as one chunk and as one chunk per
/// sample, so a smoothed point is only decided once the samples after its window have arrived.
#[test]
fn range_modifiers_match_prometheus() {
let parse_points = |points: &str| -> Vec<(i64, f64)> {
points
.split_whitespace()
.map(|point| {
let (timestamp, bits) = point.split_once(':').unwrap();
(
timestamp.parse().unwrap(),
f64::from_bits(u64::from_str_radix(bits, 16).unwrap()),
)
})
.collect()
};
let (mut checked, mut rejected) = (0, 0);
for line in include_str!("modifier_cases.txt").lines() {
if line.starts_with('#') {
continue;
}
let mut parts = line.split(';');
let header: Vec<_> = parts.next().unwrap().split_whitespace().collect();
let samples = parse_points(parts.next().unwrap());
let result = parts.next().unwrap().trim();
let function = range_function(header[0], &[]);
let numbers: Vec<i64> = header[2..8].iter().map(|n| n.parse().unwrap()).collect();
let [range_ms, offset_ms, start_ms, step_ms, points, lookback_ms] = numbers[..] else {
panic!("bad header {line}");
};
let modifier = match header[1] {
"anchored" => RangeModifier::Anchored { lookback_ms },
"smoothed" => RangeModifier::Smoothed { lookback_ms },
other => panic!("unknown modifier {other}"),
};
let window = RangeWindow {
range_ms,
offset_ms,
anchor_ms: (header[8] != "-").then(|| header[8].parse().unwrap()),
modifier: Some(modifier),
};
let grid = grid(start_ms, step_ms, points as u64);
if result == "error" {
assert!(
RangeEvaluator::try_new(&raw_schema(1), grid, window, function).is_err(),
"{line}"
);
rejected += 1;
continue;
}
let mut expected = vec![vec![None]; points as usize];
for (timestamp, value) in parse_points(result) {
expected[((timestamp - start_ms) / step_ms) as usize][0] = Some(value);
}
let rows: Vec<Row> = samples
.iter()
.map(|(timestamp, value)| (*timestamp, vec![Some(*value)]))
.collect();
let one_chunk = vec![chunk(&rows, 1, 0, true)];
let per_sample: Vec<_> = rows
.iter()
.enumerate()
.map(|(index, row)| chunk(std::slice::from_ref(row), 1, 0, index + 1 == rows.len()))
.collect();
for pieces in [one_chunk, per_sample] {
let mut evaluator =
RangeEvaluator::try_new(&raw_schema(1), Arc::clone(&grid), window, function)
.unwrap();
let chunks = collect_chunks(&mut evaluator, &pieces);
let output = fold_chunks(&chunks, evaluator.output_schema());
assert_series_eq_any_nan(
output.as_ref(),
&expected,
&output_metric(function, 0),
line,
);
}
checked += 1;
}
assert!(checked >= 80 && rejected == 4, "{checked} {rejected}");
}
/// A smoothed window interpolates its end with the first sample after it, which can arrive in a
/// later chunk even when the chunk before ends at the point: here that chunk's last row is stale
/// and dropped, so `delta(m[2s] smoothed)` at 61s must wait for the sample at 63s and interpolate
/// 3 at the end, as Prometheus does, rather than take the 2 at 59s.
#[test]
fn smoothed_waits_for_the_sample_after_a_point_its_chunk_ended_on() {
let window = RangeWindow {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: Some(RangeModifier::Smoothed { lookback_ms: 3_000 }),
};
let mut evaluator = RangeEvaluator::try_new(
&raw_schema(1),
grid(61_000, 1_000, 1),
window,
RangeFunction::Delta,
)
.unwrap();
let first: Vec<Row> = vec![
(57_000, vec![Some(1.0)]),
(59_000, vec![Some(2.0)]),
(61_000, vec![Some(stale())]),
];
let pieces = [
chunk(&first, 1, 0, false),
chunk(&[(63_000, vec![Some(4.0)])], 1, 0, true),
];
let chunks = collect_chunks(&mut evaluator, &pieces);
let output = fold_chunks(&chunks, evaluator.output_schema());
assert_series_eq_any_nan(
output.as_ref(),
&vec![vec![Some(1.0)]],
&output_metric(RangeFunction::Delta, 0),
"smoothed delta at 61s",
);
}
/// `delta(m[2s] smoothed)` with a 3s lookback at 61s: floats at 59s and 61s, then `histogram` at
/// `histogram_ts`, either as one chunk or with the histogram in a closing chunk of its own.
fn smoothed_delta_with_histogram(
histogram_ts: i64,
one_chunk: bool,
) -> datafusion::error::Result<Vec<EvaluatedChunk>> {
let window = RangeWindow {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
modifier: Some(RangeModifier::Smoothed { lookback_ms: 3_000 }),
};
let schema = raw_schema(1);
let mut evaluator = RangeEvaluator::try_new(
&schema,
grid(61_000, 1_000, 1),
window,
RangeFunction::Delta,
)
.unwrap();
let floats: Vec<Row> = vec![(59_000, vec![Some(2.0)]), (61_000, vec![Some(4.0)])];
let histogram = histogram_chunk(&schema, 1, histogram_ts);
let pieces = if one_chunk {
let float_chunk = chunk(&floats, 1, 0, false);
let field = Samples::try_from_chunks(vec![
float_chunk.fields.as_slice()[0].clone(),
histogram.fields.as_slice()[0].clone(),
])
.unwrap();
let time =
RawTimestamps::try_new(ScalarBuffer::from(vec![59_000, 61_000, histogram_ts])).unwrap();
vec![
RawSeriesChunk::try_new(
&schema,
float_chunk.primary_key.clone(),
float_chunk.metric.clone(),
time,
SeriesFields::try_from_vec(vec![field]).unwrap(),
true,
)
.unwrap(),
]
} else {
let mut closing = histogram;
closing.is_last = true;
vec![chunk(&floats, 1, 0, false), closing]
};
let mut chunks = Vec::new();
for piece in &pieces {
chunks.extend(evaluator.push(piece)?);
}
Ok(chunks)
}
/// The smoothed point at 61s is decided by the float at 61s, before a histogram at 62s inside its
/// extended window arrives. The histogram is still refused, however the input is chunked, rather
/// than refused in one chunk and swallowed after the point was handed over in another.
#[test]
fn a_smoothed_window_refuses_a_histogram_whatever_the_chunking() {
for one_chunk in [true, false] {
let error = smoothed_delta_with_histogram(62_000, one_chunk).unwrap_err();
assert!(
matches!(error, DataFusionError::NotImplemented(_)),
"one chunk: {one_chunk}: {error}"
);
}
}
/// A histogram past the extended window of every point is not read by any of them, so it is
/// accepted: the 61s window with a 3s lookback reads up to 64s.
#[test]
fn a_histogram_outside_every_smoothed_window_is_accepted() {
for one_chunk in [true, false] {
smoothed_delta_with_histogram(65_000, one_chunk).unwrap();
}
}
+2
View File
@@ -946,6 +946,7 @@ fn window_selection(
range_ms,
offset_ms,
anchor_ms,
modifier: None,
},
// The input is raw samples, so it has no grid of its own.
input_grid: None,
@@ -1024,6 +1025,7 @@ fn subquery_window(
range_ms,
offset_ms,
anchor_ms,
modifier: None,
};
let child_spec = subquery_grid(context.grid.spec(), window, step_ms)?.ok_or_else(|| {
not_implemented(&format!(