Repository navigation
refactor(optimizer): one shared-producer path for top-k reuse, shared sizes and shared panes - #959
Merged
Merged
Conversation
…shared panes Hashes each workload's expanded memo (groups, candidates, origins and children). The values were recorded on main before the shared-producer cases move onto one generation path, so that move cannot change them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and panes Top-k reuse and the shared-size / shared-pane configurations generate candidates through add_shared_producer_candidates: readers of one kind are grouped into sets that can share, each set gets its coverings (the ranking with the largest k; finite shared sizes; pane layouts), and each reader derives its candidate from each covering that serves it. The kind-specific code (TopKRankings, SummaryStates) is the old code moved into the SharedProducer methods; the generated candidates are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SharedProducer trait keeps three steps: sets (each kind groups its readers), coverings (no side effects) and derive (adds nothing when the covering does not serve the reader). can_share and serves are gone. SummaryStates numbers pane templates in sets, carried in StateNeed; top-k readers carry their ranking instead of a set index. The snapshot test now hashes the memo in order, including group edges, queries, roots and each candidate's implemented groups; its values are re-recorded on the base commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
force-pushed
the
refactor/shared-producer
branch
from
October 27, 2026 20:38
3fcf05f to
fcbc4eb
Compare
coverings takes &self; the serves check runs before the candidate is cloned; names say what they hold (configuration_index, normalized_layout, reader_groups). A snapshot of two top-k sets next to a pane set pins the order sets are expanded in (hash recorded on main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
milindsrivastava1997
added a commit
that referenced
this pull request
Oct 28, 2026
Same selected plans and costs. Only the search report changed: about twice the joint-price solves, and the direct-cost path now validates plans for q19, q22, q23, q25 and q26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG
zzylol
pushed a commit
that referenced
this pull request
Oct 29, 2026
Same selected plans and costs. Only the search report changed: about twice the joint-price solves, and the direct-cost path now validates plans for q19, q22, q23, q25 and q26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG
zzylol
pushed a commit
that referenced
this pull request
Oct 29, 2026
Same selected plans and costs. Only the search report changed: about twice the joint-price solves, and the direct-cost path now validates plans for q19, q22, q23, q25 and q26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG
zzylol
added a commit
that referenced
this pull request
Oct 29, 2026
* test(devtools): add planner corpus snapshot harness The planner has no reference answer, so pin its output instead: each corpus query's stage_pipeline document (default search) is compared with a committed snapshot. Timings are stripped and a run stopped by the wall-clock budget fails, so snapshots do not depend on machine speed. UPDATE_SNAPSHOTS=1 regenerates them. Part of #941. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG * test(devtools): snapshot 14 o11y-bench queries The o11y-bench queries that default search plans in under 10 s and 500 MB, each on its own, with declared source facts for the corpus metrics. Queries 05, 06 and 11 select no plan and are recorded as failure snapshots. Checked deterministic across two runs and a single-core run. Part of #941. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG * ci: check planner snapshots in a release-build job Runs the corpus snapshot test against a release build, since the corpus queries take minutes in debug, and uploads the regenerated snapshots when a plan changed. Part of #941. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG * docs: explain planner snapshots and require Snapshot changes in PRs A developer note on what the snapshots pin, how to regenerate them and how to add queries, plus a Snapshot changes section in the PR template and AGENTS.md so every changed plan is explained. Part of #941. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG * test(devtools): regenerate o11y-bench snapshots after #943, #961, #959 Same selected plans and costs. Only the search report changed: about twice the joint-price solves, and the direct-cost path now validates plans for q19, q22, q23, q25 and q26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKYtMxgJTLtPW9uAqPpiEG * test(devtools): snapshot only the selected plan, not the search The corpus snapshots compared the whole stage_pipeline document, including the search report's counters, status and candidate ids. Those vary from run to run because pane-width rounds have wall-clock budgets, so every snapshot failed on main without any plan change. - Snapshot only the selected Stage 2 candidate (display name, DAG), its cost and accepted accuracy, materialized views, pane retention, warnings and whether the search proved it optimal; for a query that does not plan, the error up to its search report and the rejection causes. Floats are rounded to 12 significant digits. The memo is not built (--no-memo). - Fail on a search report with status time_limit, not only on a run that used the whole budget. - 120 s per query instead of 600 s; the CI job has a 45 min timeout and caches only the cargo registry next to sccache. - Mark q18 (#1023) and q21 (a pane round ends on its wall-clock budget) known_slow and skip them. - Clear the regenerated directory at the start of a run, and write each failing query's full document next to its regenerated snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(devtools): 240 s per query, skip_reason, document the final-round status check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: zzylol <50204836+zzylol@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
#954: top-k reuse and the summary-capability rule both share one producer at a need that covers every reader (the largest
k; each size parameter's strictest value; a common pane grid with the longest window), and each reader derives its own result from it. They had two separate candidate-generation loops in the memo. This PR gives them one path, so that the next case (#951's shared scan, a group-by union) is a new implementation of that path, not a third loop.What
There is no behavior change. The memo's top-k reuse and shared-size / shared-pane configurations now generate their candidates through
add_shared_producer_candidates. The candidates they produce are identical to main's, which a new test pins with hashes recorded on main.covering/derivememo/rules/topk.rsadd_topk_candidates(its own loop overtopk_reuse_candidates)TopKRankings: covering = the rankingLimit(k_max) ▸ Sort; derive =Limit(k) ▸ Projectviaappend_producer/append_readermemo/rules/state_configurations.rsexpand_configurations, size branchSummaryStates: covering =StateCovering::Sizefromstate_size_configurations; derive =with_resized_buildSummaryStates: covering =StateCovering::Panesfrompane_configurations_before; derive =with_pane_chainir::cseinterning of equal windows over a scanir::cse: the producer is the identical window, so no candidate is generatedir::cse/ memo group identityir::cse, as #954 statesNot in this PR:
asap_aware_cse.rs(summary_capability_pass2_candidates,topk_reuse_pass2_candidates), which Reorganize by stage: one memo-based Pass 2, Stage 1 finishes the memo, deployment inputs split by stage, asap-planner as the only entry point #958 plans to delete once the memo path covers them;How
memo/rules/shared_producer.rsholds the driver and theSharedProducertrait (crate-private):setslists a kind's readers, already grouped into sets that can share. Each kind groups its own readers.coverings.derivefor each covering.deriveadds nothing when the covering does not serve the reader, so each kind filters its own readers.The two implementations are the old code moved into those methods, with the order of reads, writes and deduplication preserved:
SummaryStatesgroups by itscompatiblecheck. For a set that shares panes,setsalso numbers each reader's normalized pane layout (StateNeed::normalized_layout). The numbers continue across sets, so the request deduplication needs no per-set reset, andcoveringstakes&self.TopKRankingsreturns one set pertopk_reuse_candidatesresult, each reader carrying the set's ranking. Its covering is that ranking plus the set's groups. The ranking is interned in the first reader'sderive; later readers get the same producer group back, becauseappend_produceris idempotent.Key code interfaces added / modified
memo/rules/shared_producer.rs(new; crate-private,pub(in crate::memo))Coveringis a separate type fromNeed, unlike the sketch in #954. A pane covering is a whole configuration (grid, longest window, family), not one reader's need.memo/rules/topk.rs:add_topk_candidateskeeps its signature and now calls the driver withTopKRankings(new, private).memo/rules/state_configurations.rs:add_state_configuration_candidates_in_domainkeeps its signature and now calls the driver withSummaryStates(new, private). The privateReaderstruct is renamedStateNeedand gainsnormalized_layout;StateCoveringis new and private.TopKRankings's need is the set's ranking node and its coveringSharedRanking(ranking plusreader_groups); both private.Usage, end to end:
topk(3, sum_over_time(m_gauge[2m]))plustopk(10, sum_over_time(m_gauge[2m])), every 60 s, exact.try_populate_pass1builds the memo.expand_concrete_summary_state_groups_in_domainrunsadd_topk_candidates, which callsadd_shared_producer_candidates(memo, &mut TopKRankings { .. }, deadline).setsreturns one set: the two top-k groups, each with the reuse set's rankingLimit(10) ▸ Sort.coveringsreturns that ranking with the two groups.deriveinterns it once and addsLimit(3) ▸ ProjectandLimit(10) ▸ Projectreaders with originTopKReuse.top_k_reuse_candidates_are_unchangedchecks this.Major algorithm changes
None in results: candidate generation for these three cases is restructured onto one driver, and its outputs are unchanged. Complexity changes slightly: the top-k path now collects queries and calls
append_produceronce per reader instead of once per set, so a set of R readers does R linear scans of the memo groups instead of one; repeated calls find the existing producer group. Top-k sets are small, so this is negligible.SummaryStates::derivechecks that the covering serves the reader before cloning the candidate, so skipped pairs cost no clone.Before this PR
Two loops generated shared-producer candidates:
add_topk_candidatesandexpand_configurations. Each had its own grouping, covering and derivation code.After this PR
One driver generates them. A new case implements
SharedProducer(sets,coverings,derive) and callsadd_shared_producer_candidates.Verification
memo/shared_producer_snapshot.rs, new): it hashes each expanded memo in memo order: every group's node, children, parents, queries and roots, and every candidate's origin, budget share, implemented groups, child groups and node. Order matters because the search's tie-breaks depend on it.d4152bce): top-k (313 candidates,16940643818053118362), shared sizes (508,7457272222287953080), shared panes (729,15532247561651645380), two top-k sets next to a pane set (994,9213568444657927922; pins the order sets are expanded in).TopKReusecandidates and the pane workload yields pane chains, so each case is exercised.d4152bce):cargo test -p asap-logical-asap-optimization --lib: 229 passed, snapshot hashes unchanged.reuse_rules7sharing_issue_regressions12 ([Bug] Identical exact query-time aggregates are not shared across queries #922/[Bug] A nested shorter window of an exact sum does not reuse the newest panes of the longer window's chain #924/[Bug] The same query at a longer repeat interval recomputes instead of reusing the shorter-interval result #925 cost bounds included)sql_two_percentiles4tumbling_pane_merge13 (1 ignored, as on main)identical_exact_queries2operator_sharing(both tests ignored on main too)cargo fmt --allandcargo clippy -p asap-logical-asap-optimization --all-targets --all-features -- -D warningsare clean (stable toolchain).Part of #954
🤖 Generated with Claude Code