test(perf): fix rate-fusion input and complete-result controls

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
This commit is contained in:
discord9
2026-10-09 12:28:45 +08:00
parent e4872ec1a2
commit ca62f4280b
2 changed files with 194 additions and 0 deletions
@@ -0,0 +1,50 @@
# PromQL series rate-fusion regression fixture
This native Query Regression case isolates the candidate shape `SUM(Float64)` by
`dc` over one direct `prom_rate` expression, projected as Float64 with a
millisecond timestamp and zero offset. The immutable input uses the previously qualified dictionary-tag A direct-SST
generator, schema, and layout. All parameters are specified in this case; no
private or gitignored source file is required. It uses seed 25652, 4,096
instances × 512 samples = 2,097,152 rows, 16 `dc` values, 4 devices, and two flat
non-overlapping SSTs of 1,048,576 rows each, 8,192-row groups, 15-second
millisecond timestamps, primary key `(instance, dc, device)`, and deterministic
wave values from 0 through 100. It uses the same data generator, not the
original 127-slope counter or an archived original input.
The range window is 1704069900–1704071715 seconds at 15-second steps (122
evaluations), fully covered by fixture timestamps from 1704067200 through
1704074865. The first SST ends at 1704071025; the 5-minute lookback begins at
1704069600, so this range crosses the actual two-SST boundary and requests data
from both files. Actual scanned row counts must be audited from runtime plans;
the full 2,097,152-row fixture size is not an expected scan count for this query.
The primary range query expects 16 `dc` output groups per evaluation (1,952
result rows) and evaluates 4,096 series per evaluation (499,712
evaluation-points). The instant query at 1704071715 expects 16 output rows.
Primary `TQL EVAL` entries preserve complete response data and use 3 warmups/20
range iterations and 3 warmups/9 instant iterations; the range EVAL is also the
runner's untimed first-query validation. Separate one-shot `TQL ANALYZE VERBOSE`
entries capture runtime gate, actual plan, scan/index, and work-count diagnostics
without adding analyze overhead to timed samples. An untimed one-iteration SQL
audit returns one row per `dc`, verifying 131,072 rows and 256 instances per
group and min/max timestamps 1704067200 and 1704074865.
Controls are limited to grouped `sum_over_time` (wider non-rate path),
grouped `min by (dc) (rate(...))` (a different aggregation operator and a
negative fusion-gate control), and grouped `rate` with a 15-second offset
(offset gate). MIN keeps the same range, rate-window work, and compact 1,952-row
answer while not matching the SUM candidate. They reuse the same table and
range. The offset query's parser acceptance must be confirmed on the pinned
runtime. Each timed query retains the existing 10% candidate-latency-regression
threshold: a pass only means that configured guard did not trip; it is not proof
of candidate-gate activation or performance improvement. Do not loosen it to
hide noise.
After a native run, audit the normalized plans and complete raw responses,
including group labels, timestamps, numeric values with appropriate floating
point tolerance, and expected row counts. Also audit source SHAs, compiler,
features, fixture layout, the actual runtime gate, scans/indexes, and work counts.
Official performance acceptance still needs clean base/candidate medians,
control behavior, drift and tolerance review, and complete cross-arm answers.
This fixture alone cannot establish a gain. Finite-pool behavior, drops, and
spill behavior belong to code tests, not this CI case. No official workflow was
run as part of adding this fixture.
@@ -0,0 +1,144 @@
# Minimal native Query Regression fixture for the narrow direct-prom-rate sum fusion candidate.
# This deterministic wave is not the original 127-slope counter/input archive.
# Retain complete raw responses for parity auditing; passing thresholds only means
# the configured latency guard did not trip, not that fusion or a speedup was proven.
[case]
name = "promql_series_rate_fusion"
description = "PromQL rate-only grouped sum fusion regression fixture"
[scenario]
kind = "direct_readable_sst"
seed = 25652
[[scenario.tables]]
database = "public"
name = "promql_series_rate_fusion"
engine = "mito"
append_mode = true
sst_format = "flat"
primary_key = ["instance", "dc", "device"]
time_index = "ts"
[[scenario.tables.columns]]
name = "instance"
type = "STRING"
semantic = "tag"
distribution = { kind = "cardinality", values = 4096, prefix = "instance" }
[[scenario.tables.columns]]
name = "dc"
type = "STRING"
semantic = "tag"
distribution = { kind = "cardinality", values = 16, prefix = "dc" }
[[scenario.tables.columns]]
name = "device"
type = "STRING"
semantic = "tag"
distribution = { kind = "cardinality", values = 4, prefix = "device" }
[[scenario.tables.columns]]
name = "val"
type = "DOUBLE"
semantic = "field"
distribution = { kind = "deterministic_wave", min = 0.0, max = 100.0 }
[[scenario.tables.columns]]
name = "ts"
type = "TIMESTAMP(3)"
semantic = "timestamp"
[scenario.layout]
regions = 1
sst_count = 2
rows_per_sst = 1048576
row_group_size = 8192
series_count = 4096
start_unix_nanos = 1704067200000000000
step_nanos = 15000000000
time_range_layout = "non_overlapping_per_sst"
series_layout = "timestamp_major"
# 122 evaluations * 16 dc groups = 1,952 output rows. Each range evaluates
# 4,096 series at 122 timestamps (499,712 evaluated series points). This range
# crosses the first-SST boundary (1704071025); its initial 5m lookback starts
# at 1704069600, ensuring both SSTs are in the requested time span.
[[scenario.queries]]
name = "grouped_rate_sum_range"
kind = "tql"
query = "TQL EVAL (1704069900, 1704071715, '15s') sum by (dc) (rate(promql_series_rate_fusion[5m]))"
warmup = 3
iterations = 20
[scenario.queries.thresholds]
max_candidate_latency_regression_pct = 10
# Same complete response shape at the latest timestamp: 16 groups.
[[scenario.queries]]
name = "grouped_rate_sum_instant"
kind = "tql"
query = "TQL EVAL (1704071715, 1704071715, '15s') sum by (dc) (rate(promql_series_rate_fusion[5m]))"
warmup = 3
iterations = 9
[scenario.queries.thresholds]
max_candidate_latency_regression_pct = 10
# Separate diagnostics are intentionally not included in timed samples.
[[scenario.queries]]
name = "analyze_grouped_rate_sum_range"
kind = "tql"
query = "TQL ANALYZE VERBOSE (1704069900, 1704071715, '15s') sum by (dc) (rate(promql_series_rate_fusion[5m]))"
warmup = 0
iterations = 1
[[scenario.queries]]
name = "analyze_grouped_rate_sum_instant"
kind = "tql"
query = "TQL ANALYZE VERBOSE (1704071715, 1704071715, '15s') sum by (dc) (rate(promql_series_rate_fusion[5m]))"
warmup = 0
iterations = 1
# Wider/non-rate path: does not match the direct rate-only fusion candidate.
[[scenario.queries]]
name = "grouped_sum_over_time_control"
kind = "tql"
query = "TQL EVAL (1704069900, 1704071715, '15s') sum by (dc) (sum_over_time(promql_series_rate_fusion[5m]))"
warmup = 3
iterations = 9
[scenario.queries.thresholds]
max_candidate_latency_regression_pct = 10
# MIN is a distinct aggregation operator, so it must not match the SUM fusion
# candidate. It retains the same rate-window work and compact grouped response.
[[scenario.queries]]
name = "grouped_rate_min_control"
kind = "tql"
query = "TQL EVAL (1704069900, 1704071715, '15s') min by (dc) (rate(promql_series_rate_fusion[5m]))"
warmup = 3
iterations = 9
[scenario.queries.thresholds]
max_candidate_latency_regression_pct = 10
# Complete-table materialization audit: 16 rows, each dc has 131072 rows and
# 256 instances, with timestamps spanning the entire two-SST fixture.
[[scenario.queries]]
name = "validate_materialized_data"
kind = "sql"
query = "SELECT dc, COUNT(*) AS row_count, COUNT(DISTINCT instance) AS series_count, MIN(ts) AS min_ts, MAX(ts) AS max_ts FROM promql_series_rate_fusion GROUP BY dc ORDER BY dc"
warmup = 0
iterations = 1
# Offset gate control, if accepted by this pinned parser; an offset is not fused.
[[scenario.queries]]
name = "grouped_rate_sum_offset_control"
kind = "tql"
query = "TQL EVAL (1704069900, 1704071715, '15s') sum by (dc) (rate(promql_series_rate_fusion[5m] offset 15s))"
warmup = 3
iterations = 9
[scenario.queries.thresholds]
max_candidate_latency_regression_pct = 10