feat(devtools): add interactive SQL/PromQL Pre/Post-ASAP workload planner and DAG viewer - #283
Merged
Merged
Conversation
…ost-asap
Add a --post-asap flag to the dag_export devtools binary that runs
asap-aware-mapping's replacement search (default_strategies() plus the
unwired AvgToSumOverCountStrategy) over the lowered workload and surfaces
what it found, two ways:
- NamedGraph.replacements: Vec<TargetReplacement> - one small,
self-contained before/after pair per independently-discovered
replacement site (sketch mapping, CSE share/recompute, workload-aware
rollup, Hydra grouping, avg -> sum/count rewrite), each with a strategy
label, rationale, rank/cost, and an after tagged
{"kind": "Summary"|"Rewrite", "graph": {...}}.
- NamedGraph.post_graph: Option<DagGraph> - one merged, whole-query graph
per query with every winning candidate spliced directly into the query's
own pre-ASAP shape in place, built via a new
asap_types::dag_export::export_post_asap.
asap_types::dag_export gains the generic, crate-agnostic shapes for this
(SummaryDagNode/SummaryDagGraph/export_summary, TargetReplacement/
TargetReplacementAfter, PostAsapSubstitution/export_post_asap) following
the same layering discipline DagNode::notes already established: this
crate never runs the search or picks a winner, only defines shapes a
higher layer (the dag_export binary) populates after the fact. DagNode's
source_expr becomes Option<QueryExpr> (None for a post-ASAP-originated
node with no corresponding QueryExpr).
Without --post-asap, output is byte-identical to before (both new fields
are empty/None and skipped from JSON).
Sample outputs covering all four --post-asap replacement kinds saved to
/tmp/post_asap_samples/*.json for the frontend dag-viewer track.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a fourth view mode alongside Single/Compare/Union that lets a user pick one of a query's --post-asap `replacements[]` entries and see its `before`/`after` subtrees side by side, plus a whole-query option (query.graph vs the whole-query `post_graph`), so a claimed replacement can be visually confirmed instead of just trusted. - index.html: new "Before/After" mode button and a secondary #baPicker list (grouped by target node, sorted by rank, winner marked) shown below the tabs while the mode is active. - viewer.js: renderBeforeAfter/laneElements reuse Compare mode's compound-lane pattern for exactly two fixed lanes; renderBaPicker builds the per-target and whole-query picker rows; showBeforeAfterDetail renders a selected lane node's detail (degrades cleanly on SummaryDagNode's missing hash/notes fields); computeHashOwners now skips hash-less nodes instead of bucketing them under `undefined`. - node-style.js: new 'summary' category (neutral gray, distinct from the existing 9 hues) covering the 7 post-ASAP-only SummaryDagNode kinds; KeepPreAsap gets an extra muted/dashed override plus its own pass-through icon so 'unchanged' visually reads differently from 'the planner did something here'. - README.md: new "Before/After mode" section. - post_asap_fixture.json: fixture used to build/test against (3 queries covering Sketch/HydraGrouping rank comparison, AvgToSumRewrite, and a SharedSubtree CSE share; p95_pktlen hand-extended with a post_graph since the Rust track's --post-asap output doesn't exist yet). Verified via Playwright screenshots (light + dark) that Single/Compare/ Union are unregressed and all three fixture queries render correctly in Before/After mode, including the whole-query toggle and its disabled-when-absent state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tree matches Integration fix after merging the post-ASAP export (--post-asap) and dag-viewer Before/After tracks: export_post_asap's post-ASAP-originated nodes (SummaryAgg, SummaryEstimate, etc. — anything with no corresponding QueryExpr) were emitting hash: 0 as a placeholder. The viewer's shared-subtree highlighting only treats hash === undefined as 'no hash' (by design, per the frontend track's own report), so every post-ASAP-originated node across every query/graph would collide on hash 0 and get spuriously rung as 'shared' with each other. Fixed at the source: DagNode::hash is now Option<u64>, None (and omitted from JSON) for nodes with no QueryExpr to hash — mirroring how source_expr already handles the same situation. Verified real --post-asap output flows through the merged dag-viewer correctly with no false-shared highlighting and no regressions: full workspace test suite (asap-types, asap-aware-mapping, asap-devtools, and everything else) passes unchanged, fmt/clippy clean, and manually confirmed via Playwright against real generated JSON (sketch mapping and avg-to-sum-rewrite queries) in both Before/After per-target and whole-query views. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
default_strategies() already includes it as of #282 — this binary no longer needs its own custom strategy list, just plain search_workload(). Also reworded the 'unmatched winner' diagnostic: with AvgToSumOverCountStrategy now running by default, its rewrite output routinely exposes new sum/count descendants that the same search pass independently sketch-ranks — real winners, but ones with no node in any query's original pre-rewrite graph to attach a flat replacements[] entry to (expected, not a bug: still fully represented in that query's post_graph). The old wording read like an error for what is normally an expected case. Verified: cargo test --workspace, fmt, and clippy all clean; manually re-ran --post-asap on an AVG query and confirmed the JSON output is identical (only the diagnostic wording changed).
zzylol
force-pushed
the
feat/dag-post-asap-viz
branch
from
August 26, 2026 02:18
34967ce to
c1c6b84
Compare
…t_graph Found via manual testing against real corpus queries (not the toy examples used so far): a single, standalone STDDEV_POP aggregate crashed dag_export --post-asap with a stack overflow, no sharing or rewriting involved at all. Root cause: STDDEV_POP (like AVG) dispatches to Implementation::PassThrough with no alternative strategy of its own, so SketchAlgorithmStrategy's only candidate for it is keep_pre_asap()'s conservative fallback -- Replacement::Summary wrapping the entire target as SummaryExpr::KeepPreAsap. run_post_asap was treating this like any other winner and handing it to export_post_asap, whose find_winner re-checks every node inside a spliced KeepPreAsap payload by design (so a target nested underneath one still gets found) -- but this payload structurally is the enclosing target, so the fresh check finds the identical winner again, unconditionally, forever. This is the exact "no-op candidate" concept explanation.rs's own sketch_finding_reason already excludes from being reported as a finding. run_post_asap's own winner selection just wasn't applying that same filter. Fixed by skipping a candidate whose Replacement::Summary is a bare top-level KeepPreAsap when building winners, with a regression test exercising the exact repro. Also verified against several real corpus queries end to end (previously only exercised with hand-written toy SQL): PR-PKT/FT-PKT (#44/#49 in synthetic_packet_trace_queries.sql) now correctly show a genuine Rollup relationship, and P-LEN-AVG (#14) shows the real avg -> sum/count rewrite -- both screenshotted for the PR description. Verified: cargo test --workspace, fmt, and clippy all clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # crates/devtools/src/bin/dag_export.rs # tools/dag-viewer/README.md # tools/dag-viewer/test_render.py # tools/dag-viewer/viewer.js
…"" This reverts commit 411ecb2.
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.
Summary
Adds an interactive SQL/PromQL workload planner and DAG viewer for comparing the original pre-ASAP IR with the selected post-ASAP plan.
The browser can edit queries and table schemas, run the real planner pipeline, visualize one query or a multi-query workload union, and inspect the exported IR, schemas, sharing decisions, and replacement strategies without reconstructing planner intent in JavaScript.
Purpose of the demo
This demo is intended to serve three related purposes:
Planner and export model
dag_export --post-asapand runs parsing/lowering, pre-ASAP DAG generation, ASAP-aware replacement search and cost selection, and post-ASAP DAG generation.graphandpost_graphfor every named query, plus ranked per-targetreplacementsfor diagnostics.decisionto every post-ASAP node produced or carried by a selected replacement. It contains the real strategy name, rationale, rank, estimated cost, role, and workload-level decision ID.decision.id/replacement.decision_idmetadata. The viewer does not infer a replacement from labels, hashes, or client-side node signatures.workload_node_idin the exporter. Pre/post workload unions and shared-node highlighting consume this ID directly, so shared work is represented by one workload node.Replacement strategies
SketchAlgorithmStrategy,SharedSubtreeStrategy,HydraGroupingStrategy,AvgToSumOverCountStrategy,RollupStrategy, andTopKLimitReuseStrategy.TopKLimitReuseStrategyfor compatible top-k queries over the same ordered input. A smaller result can be derived from a larger selected limit, such asLimit(5) -> Limit(10), while retaining the shared ordered/summary input.KeepPreAsapwinners when splicing the post-ASAP graph, preventing recursive no-op substitution.Interactive viewer
/api/planbackend; it invokesdag_exportwith an argv array rather than a shell command.metricsandhostsschemas, per-query schema selection, custom tables/columns/nullability/time indexes, SQL binding, and inferred PromQL metric schemas.Pre/Post-ASAPvisualization:tools/dag-viewer/render.py.Bundled workload
The generated demo covers five queries:
q1: groupedCOUNT(*)overmetrics.q2: groupedAVG(latency), exercisingAvgToSumOverCountStrategyand sketch mapping while sharing themetricsinput with q1.q3:topk(5, rate(http_requests_total[5m])).q4:topk(10, rate(http_requests_total[5m])); q3 derives its smaller limit from q4's larger limit, and both share the ordered summary sub-DAG.q6: a realmetrics JOIN hostsgrouped-count query whose exported workload mapping sharesScan(metrics)with the other compatible SQL queries.dag.example.jsonis generated from these real queries throughdag_export; it is not manually edited viewer output.Run
Open the URL printed by the server, normally
http://127.0.0.1:8000. When the server runs on a remote host, forward that port over SSH or through the editor's Ports panel.To produce a directly-openable standalone page:
Verification
/api/plansubmission.