Skip to content

test(planner_fuzz): relations from the ASAPWorkloads query catalog (ratios, longer windows, rate/increase, UnivMon statistics) - #986

Merged
zzylol merged 1 commit into
mainfrom
devtools/fuzz-workload-relations
Oct 28, 2026
Merged

zzylol merged 1 commit into
mainfrom
devtools/fuzz-workload-relations

Conversation

@zzylol

@zzylol zzylol commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Part of #879

Why

planner_fuzz checks the reuse patterns the design docs describe. Production workloads share state in more ways than that. The ASAPWorkloads query catalog (ProjectASAP/ASAPWorkloads, docs/query-catalog.md) collects real queries: recording rules, dashboards and agent traces. Its plans pair, for example:

The tester had no relation for most of these. Its h-other-statistic relation had never reached a verdict: the KLL and KMV sketches the planner selects answer only one statistic.

What

Four new relations, and changes to g and h:

Relation q' from q Witness
l-binary-over-result q{label="v"} / q on a label q does not group by; or q / q_count for a sum_over_time q (avg as sum/count) the division grafted onto q's node, with the other operand planned alongside W
m-longer-window q over the shortest longer window, up to 1 h, that is a multiple of q's q's pane chain lengthened; every merge of the chain in W's plan reads its old newest panes
n-longer-window-rollup m, grouped by one key fewer m's derivation, then c's rollup
o-equivalent-range-function rate and increase swapped q's result times, or divided by, the window in seconds
g-outer-over-result (changed) the outer operator follows q's own: topk, bottomk, max, quantile(0.5, …) or > 0 unchanged (graft)
h-other-statistic (changed) SQL, ungrouped: another frequency statistic of a high-cardinality column (distinct count → row count, L2 → distinct count, entropy → L2) another estimate from q's state; or W ∪ {q'} planned with UnivMon as the only sketch family, then priced with every family

The generator now emits more of these shapes:

  • SQL gets a column src_ip with one value per series. Its frequency statistics use COUNT(DISTINCT src_ip) and the L2 and entropy SQL idioms of planner-layering Example 2.
  • A related query may now also swap rate for increase, pick another frequency statistic of src_ip, or take a 30-minute or 1-hour window.

The README's coverage table cites each new pattern by its catalog number. No planner behavior changes.

How

  • relations.rs:
    • The four new arms in derive.
    • coarser: c's derivation, factored out so n can reuse it.
    • witness_roots: three witnesses need it because they change W's own roots, not only add a root for q'.
      • m and n: longer_chain_roots lengthens the chain and rewrites every reader of it.
      • l: GraftWithOperand plans W with the sibling operand added.
      • h: UnivMonOnly plans W ∪ {q'} with UnivMon as the only family.
    • h's in-place estimate swap handles SQL's NULL-on-empty join guard.
  • mod.rs: FuzzWorkload::sketch_families filters the deployment's supported summary families.
  • generate.rs: the SQL frequency aggregates, the src_ip column, and the new related-query edits.

Key code interfaces added / modified

crates/devtools/src/planner_fuzz/relations.rs

/// A metamorphic relation the tester checks. Stays.
pub enum Relation {
    /// (a)–(k) and the monotonicity/invariance relations: unchanged.
    LooserAccuracy, FilterOnGroupKey, CoarserGrouping, NestedShorterWindow, OtherQuantileRank,
    ExactDuplicate, OuterOverResult, OtherStatistic, OtherRepeatInterval, SmallerTopK,
    UnionOfSelections, TighterAccuracy, AddedQuery, NoRawRetention, ResultsRetained,
    RelaxedLatency, Renamed, Reordered, DisjointCopy, // unchanged (g and h derive differently)
    /// (l) a ratio of q and a sibling query. Produced for PromQL q with a range function.
    BinaryOverResult,        // new
    /// (m) q over a longer window that is a multiple of q's (not rate/increase).
    LongerWindow,            // new
    /// (n) m and one grouping key fewer.
    LongerWindowRollup,      // new
    /// (o) rate and increase swapped (not under count).
    EquivalentRangeFunction, // new
}

/// How a derived query q' is answered in the witness. Stays.
pub enum Witness {
    /// Same, Filter, Graft, ExactRollup, SmallerTopK, SketchRollup, NewestPanes,
    /// QuantileRank, OtherStatistic, UnionWithLast: unchanged.
    /// Like Graft, for a text that also reads the sibling query `operand`;
    /// W is planned with `operand` added.
    GraftWithOperand { text: String, operand: String }, // new
    /// q's pane chain lengthened to window_ms, then `rollup` when set (n).
    LongerWindow { window_ms: u64, rollup: Option<Box<Witness>> }, // new
    /// W ∪ {q'} planned with UnivMon as the only sketch family, priced with every family.
    UnivMonOnly, // new
}

/// The witness's roots: W's selected roots plus q''s, with W's roots rewritten when the
/// derivation changes a node they share. New; evaluate_marginal calls it for every witness.
pub fn witness_roots(
    planner: &mut Planner, witness: &Witness, base: &FuzzWorkload, related: &FuzzWorkload,
    planned: &Planned, base_roots: &[QueryRoot], target: usize,
) -> Result<Vec<QueryRoot>, String>;

crates/devtools/src/planner_fuzz/mod.rs

/// A workload the tester plans. Stays.
pub struct FuzzWorkload {
    pub language: Language,                   // unchanged
    pub queries: Vec<FuzzQuery>,              // unchanged
    pub data: DataWorkload,                   // unchanged
    pub tables: Vec<Value>,                   // unchanged
    pub raw_data_retained: bool,              // unchanged
    pub query_time_results_retained: bool,    // unchanged
    /// The only sketch families the deployment builds; None (default) for every family
    /// the executor builds. Set only by the UnivMonOnly witness.
    pub sketch_families: Option<Vec<SketchAlgorithm>>, // new
}

crates/devtools/src/planner_fuzz/generate.rs

/// An SQL aggregate the generator draws. Stays.
pub enum SqlAggregate {
    Sum, Count, Avg, Max, Min, Quantile(f64), CountDistinct(String), // unchanged
    /// SQRT(SUM(c*c)) over a column's value counts (planner-layering Example 2).
    FrequencyL2(String),      // new
    /// -SUM(p*LN(p)) over a column's value shares.
    FrequencyEntropy(String), // new
}
/// The high-cardinality SQL column only the frequency aggregates read.
pub const SQL_FREQUENCY_COLUMN: &str = "src_ip"; // new

Usage (a real run; the draft is s61-001):

# Run the four new relations plus the changed g and h for 10 minutes on seed 61.
cargo run --release -p asap-devtools --bin planner_fuzz -- \
  --seed 61 --cases 400 --time-budget-s 600 --out out/s61 \
  --relations g,h,l,m,n,o --case-timeout-s 120
# summary.md: "Seed 61, 5 cases, 39 checks, 702 s."
# o derives q' = min by (job, instance, region) (increase(m_counter[5m])) from the exact
# W = { min by (job, instance, region) (rate(m_counter[5m])) every 10 s }.
# The witness reads q's result and multiplies it by 300.
#   cost(W) 0.222092, cost(W ∪ {q'}) 0.244628 → Δ = 0.022536
#   witness 0.222168 → derive_cost = 0.000076, tolerance 0.002446  → VIOLATED
# The draft is written to out/s61/findings/s61-001-o-equivalent-range-function.md,
# with both workloads and the stage_pipeline commands that reproduce it.

Major algorithm changes

None in the planner. The fuzz tester's witness construction now has two forms:

  • Adds a root. The original form: W's selected plan plus one root for q'.

  • Rewrites W's plan as well. Still a plan for W ∪ {q'}, so derive_cost = cost(witness) − cost(W's plan) keeps its meaning. Three witnesses use it:

    • m/n: W's readers of the lengthened chain merge only their old newest panes.
    • l: W is replanned with the sibling operand added.
    • h: UnivMonOnly replans W ∪ {q'} with one family.

    A violation found through the h witness means one of two things: a rule never generates the shared UnivMon, or the full search misses a plan that the restricted search finds.

Before this PR

  • A seeded run never generated a workload that pairs rate with increase, a ratio over a shared operand, or windows longer than 10 minutes over one metric.
  • h never reached a verdict: 2,926 inconclusive checks in the one-hour run.

After this PR

Two smoke runs on main a9737a7: 20 seeds × 10 minutes each, default search, accuracy guarantees enforced.

Relation Holds Violated Inconclusive
g (follows q's operator) 43 6 151
h (SQL frequency statistics) 5 0 95
l 15 0 135
m 5 2 99
n 0 0 83
o 0 6 66

The drafts point to three missed-reuse patterns. They are not filed yet; they will be reviewed after the one-hour rerun.

  • o: rate and increase of one counter never share state, exact or approximate. Seed 43: rate(m_counter[1m]) plus increase(m_counter[1m]). The marginal cost is 0.000233/s against a witness's 0.000033/s.
  • m: a SQL count at 10 min → 30 min (0.316 vs 0.282 per second) and a percentile at 5 → 10 min (0.129 vs 0.078) build new state instead of lengthening q's chain.
  • g: topk(3, sum by (instance)(m_gauge)) recomputes an exact instant sum. quantile(…) > 0 over an approximate quantile does not read it either.

Limits:

  • n needs a grouped q that is planned with a pane chain. Approximate sketches are rebuilt over the whole window on each evaluation, so n had no conclusive checks in these runs.
  • m and n return inconclusive when q merges more than one pane chain whole, such as an SQL idiom's exact row-count guard.
  • Throughput on main is about 5 cases per seed per 10 minutes, a quarter of the earlier run's rate. Most of the time goes to planning; there were 33 case timeouts.
  • Seeds no longer reproduce earlier drafts, because the generator's draws changed.
  • h no longer derives a count from a quantile query. KLL answers only quantiles, and e already checks that case.

Verification

  • cargo test -p asap-devtools --lib planner_fuzz: 10 passed. New: workload_catalog_relations_derive. Updated: h in statistic_and_selection_relations_derive.
  • cargo test --release -p asap-devtools --test planner_fuzz: 16 passed. Seven new tests require a verdict from each new witness:
    • l: rate share; it must use GraftWithOperand, because the plain graft cannot price.
    • l: sum/count.
    • o.
    • g: threshold.
    • m.
    • n.
    • h: SQL L2 → distinct count at 10,000 series.
  • cargo clippy -p asap-devtools --all-targets -- -D warnings and cargo fmt --check: clean.
  • An independent review covered witness semantics:
    • It confirmed that increase equals rate × window on both executor paths.
    • It confirmed l's one-to-one vector matching.
    • It confirmed that UnivMonOnly is a valid plan for W ∪ {q'}.
    • It led to three changes: m/n became inconclusive when q merges several chains, l's avg form is limited to no outer operator or sum, and the h swap comment and stale docs were fixed.

🤖 Generated with Claude Code

Adds l-binary-over-result, m-longer-window, n-longer-window-rollup and
o-equivalent-range-function; g's outer operator follows q's own; h checks
SQL frequency statistics of a high-cardinality column, with a witness that
plans W ∪ {q'} with UnivMon as the only sketch family.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zzylol zzylol added dev-tools Developer tools, diagnostics, and demos enhancement New feature or request testing Corpus, regression, differential, or benchmark tests workload Batch, repeating, or multi-query workload modeling labels Oct 28, 2026
@zzylol zzylol changed the title devtools(planner_fuzz): relations from the ASAPWorkloads query catalog (ratios, longer windows, rate/increase, UnivMon statistics) test(planner_fuzz): relations from the ASAPWorkloads query catalog (ratios, longer windows, rate/increase, UnivMon statistics) Oct 28, 2026
@zzylol
zzylol merged commit ce1136d into main Oct 28, 2026
3 of 5 checks passed
@zzylol
zzylol deleted the devtools/fuzz-workload-relations branch November 3, 2026 02:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-tools Developer tools, diagnostics, and demos enhancement New feature or request testing Corpus, regression, differential, or benchmark tests workload Batch, repeating, or multi-query workload modeling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant