Skip to content

feat(rqe-optimizer): plan output with active deployments and instance counts - #168

Merged
milindsrivastava1997 merged 3 commits into
mainfrom
feat/s8-plan-output
Oct 7, 2026
Merged

milindsrivastava1997 merged 3 commits into
mainfrom
feat/s8-plan-output

Conversation

@milindsrivastava1997

@milindsrivastava1997 milindsrivastava1997 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Implements S8 (plan output) of #143. ASAPQuery's A3 builds StreamingConfig / InferenceConfig directly from this.

Interface change (A3 depends on this)

minimize still returns MilpSolution, which now has these fields:

pub struct MilpSolution {
    pub deployments: Vec<PlannedDeployment>, // active deployments only, renumbered from 0
    pub raqes: Vec<PlannedRaqe>,             // one per input RAQE, input order
    pub plan_cost: PlanCost,                 // unchanged; objective value is objective.value(&plan_cost)
}
pub struct PlannedDeployment {
    pub deployment: Deployment,              // variant (config.sketch), sketch_config, metric,
                                             // grouping_labels, window_ms (x), slide_ms (y), key_tracker
    pub retained_instance_count: u64,
}
pub struct PlannedRaqe {
    pub deployment: usize,                   // index into MilpSolution::deployments
    pub merged_instance_count: u64,          // n = L/x
}

MilpSolution::mapping (indexes into the full candidate list) is removed.

Design decisions (settled in a grilling session; please approve each)

  1. Keep the name MilpSolution and make it richer, rather than adding a new Plan type. minimize's signature does not change.
  2. Drop mapping. One indexing scheme per struct: PlannedRaqe::deployment indexes MilpSolution::deployments, which holds only the active deployments, in order of the first RAQE each serves.
  3. retained_instance_count = x/y + (L_max − x)/y + 1, in windows per group (per sketch). It is not multiplied by card(G) (or by 1 for shared sketches such as HydraKLL). L_max is the longest lookback among the RAQEs the deployment serves. The key tracker keeps the same window count, so it has no field of its own.
  4. merged_instance_count = L/x per RAQE. There is no query-method enum. With Subtract deferred (S9), n == 1 means Direct and n > 1 means Merge. Add the enum together with Subtract.
  5. Per-RAQE latency stays in plan_cost.query_latency_ms and is not copied onto PlannedRaqe.
  6. No $/h. rqe-optimizer: per-phase cost model, workload facts, weighted AUCCost objective #145 replaced minimize_cost on an EC2 family with AUCCost { w_cpu, w_mem } and removed the pricing snapshot. The plan reports PlanCost (CPU and memory per phase). There is no stored objective value, so it can't go stale; callers compute objective.value(&plan_cost) from the objective they passed in. If ASAPQuery wants a dollar figure, it can multiply on its side.
  7. No serde derives. ASAPQuery uses the library directly, so nothing serializes a plan yet.
  8. Scope is S8 only. AutoSketch, brute force and Pareto keep their Mapping outputs, since ASAPQuery calls only minimize. A3 and pinning the sketch-bench rev in ASAPQuery come after this merges.

Changes

  • rqe-optimizer/src/milp.rs: the new fields, a plan helper that renumbers active deployments and computes both counts, MILP tests switched from mapping to the planned fields, and a new test plan_lists_active_deployments_with_their_instance_counts.
  • rqe-optimizer/examples/small_problem.rs: --milp prints each planned deployment with its retained count and key-tracker flag, plus each RAQE's deployment and merged count.

Testing

  • cargo test -p rqe-optimizer: 54 passed. cargo clippy --all-targets -D warnings: clean.
  • small_problem --milp on a real cost table: for example, kll-percall with x=720 s, y=60 s, serving lookbacks up to 1 d, retains 12 + 1429 = 1441 windows, and latency_p99_1d merges 120.

🤖 Generated with Claude Code

… counts

MilpSolution now lists only the active deployments, renumbered, each with
its retained instance count, and per RAQE the serving deployment index and
merged instance count. Drops the candidate-index mapping; adds the solved
objective value. sketch-bench#143 S8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@milindsrivastava1997

Copy link
Copy Markdown
Contributor Author

Code review

All findings are in rqe-optimizer/src/milp.rs.

Correctness

  1. L252, duplicate deployments: plan dedups by candidate index, not by deployment value. If two candidates are equal and the MILP spreads RAQEs across them (a tie, or ingest cost ≈ 0), deployments lists the same deployment twice, and A3 would ingest the same data twice.
  2. L289, test helper picks the wrong candidate: chosen recovers indices with position(candidate == deployment), so with equal candidates it always maps to the first one, and assertions can pass or fail for the wrong reason. Before this PR, milp.mapping gave the exact index.

Cleanups

  1. L255, duplicated window counting: plan repeats the per-deployment "max over served RAQEs" fold from analytical_cost_model::score. If one copy changes (e.g. Subtract, S9), retained_instance_count and the costed storage drift apart with no error. Compute it in one place.
  2. L58, objective_value field: it can always be derived as objective.value(&plan_cost). Storing it in a struct with pub fields lets it go stale; compute it on demand instead.
  3. L472, test assertion checks nothing: it asserts objective_value == Objective::default().value(&plan_cost), the same expression that sets the field, so it can't catch a wrong objective.
  4. L240, BTreeMap for dense indices: the renumbering could be a vec![None; candidates.len()] of Option<usize>, which also drops the import.
  5. L251, repeated open-window count: active_instance_count() is recomputed and zipped in for every RAQE, but it's constant per deployment. Track the max closed_instance_count per deployment and add the open count once.

🤖 Generated with Claude Code

milindsrivastava1997 and others added 2 commits October 7, 2026 09:26
… once

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…use objective.value

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@milindsrivastava1997
milindsrivastava1997 merged commit 3b31dfb into main Oct 7, 2026
2 checks passed
@milindsrivastava1997
milindsrivastava1997 deleted the feat/s8-plan-output branch October 7, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant