Repository navigation
feat(planner): add asap-planner --planner legacy|milp - #808
Conversation
plan_milp loads the facts and costs, builds the objective and solves, so asap-planner can share it with asap-optimizer-cli. PlannerOutput gains write_to_dir. Refs #790 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--planner milp plans with the rqe-optimizer MILP and writes its configs; legacy stays the default. milp takes --workload-facts and --atomic-costs (required) and --w-cpu/--w-mem, and supports only PromQL with --input_config. It rejects --query-log, --prometheus-url, --enable-punting, --range-duration-ms, --step-ms, and per-group step_ms/range_duration_ms, whose retention MILP configs don't model yet (#800). Refs #790 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #790 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
milindsrivastava1997
left a comment
There was a problem hiding this comment.
Controller::generate_to_dir (asap-planner-rs/src/promql/controller.rs:163) and the SQL/Elastic equivalents still duplicate the write-both-YAMLs logic that PlannerOutput::write_to_dir now provides. Could they call write_to_dir so output file names live in one place?
| .input_config | ||
| .as_deref() | ||
| .ok_or_else(|| anyhow::anyhow!("--planner milp requires --input_config"))?; | ||
| let scrape_interval_ms = args.data_ingestion_interval_ms.ok_or_else(|| { |
There was a problem hiding this comment.
--data-ingestion-interval-ms 0 isn't rejected here (asap-optimizer-cli uses range(1..)). A 0 reaches load_workload_facts / extract_aqes, where per-series rates are derived from the scrape interval → inf/NaN or divide-by-zero inside the solver instead of a clear CLI error. Suggest ensure!(scrape_interval_ms > 0) here or range(1..) on the flag.
Also nit: the message says "required for PromQL mode" (copied from the legacy branch); every other check in run_milp names --planner milp.
There was a problem hiding this comment.
Fixed in 0c4bcf5: run_milp now rejects 0 with ensure!(scrape_interval_ms > 0). I didn't put range(1..) on the flag because legacy shares it. The missing-interval message now names --planner milp.
| let scrape_interval_ms = args.data_ingestion_interval_ms.ok_or_else(|| { | ||
| anyhow::anyhow!("--data-ingestion-interval-ms is required for PromQL mode") | ||
| })?; | ||
| let config: ControllerConfig = serde_yaml::from_str(&std::fs::read_to_string(config_path)?)?; |
There was a problem hiding this comment.
This parses the config with serde_yaml directly, skipping the windowing.validate() that every legacy Controller::from_* constructor runs. E.g. windowing: {type: sliding, window_size_ms: 1000} without slide_interval_ms, or window_size_ms: 0, is rejected by the legacy planner but planned and written under --planner milp.
There was a problem hiding this comment.
Addressed in 0c4bcf5 by rejecting windowing under MILP (see the build_milp_workload thread). The MILP picks its own windows, so a validated windowing would still be ignored.
| facts: &WorkloadFacts, | ||
| scrape_interval_ms: u64, | ||
| ) -> Result<MilpWorkload, MilpError> { | ||
| // They only size retention, which MILP configs don't set yet. |
There was a problem hiding this comment.
Two things:
-
step_ms/range_duration_msare rejected because MILP ignores them, butwindowing,sketch_parametersandaggregate_cleanupare equally ignored and pass silently (e.g.sketch_parameters: {DatasketchesKLL: {K: 400}}gets dropped without warning). Worth rejecting all unsupported fields in one place. -
Living in
build_milp_workloadmeansasap-optimizer-cliprint-only runs (no--output-dir, or--allow-undeployable-families) now fail on range-query workloads, though the stated reason (retention sizing in written configs) only applies when configs are written. Comparereject_avg_queries, which is gated onoutput_dir.is_some().
There was a problem hiding this comment.
Both fixed in 0c4bcf5:
build_milp_workloadnow rejectswindowing,sketch_parametersandaggregate_cleanupin one place, in both binaries and whether or not configs are written. I leftexisting_*_configalone because legacy ignores it too.- The
step_ms/range_duration_mscheck moved intoreject_unwritable_queries(formerlyreject_avg_queries), which only runs when configs are written. Print-onlyasap-optimizer-cliruns plan those workloads again. Test:range_query_overrides_block_only_the_written_configs.
| EngineArg::Precompute => StreamingEngine::Precompute, | ||
| }; | ||
|
|
||
| if args.planner == PlannerArg::Milp { |
There was a problem hiding this comment.
With --planner milp, --clickhouse-url, --clickhouse-database and --streaming_engine are silently ignored, while --prometheus-url, --enable-punting, --step-ms etc. are explicitly rejected in run_milp. Should these be rejected too for consistency?
There was a problem hiding this comment.
Fixed in 0c4bcf5: --clickhouse-url and --clickhouse-database are now rejected under --planner milp. I left --streaming_engine as is: its only value is precompute, which is what MILP emits, so it isn't ignored.
…_to_dir The PromQL, SQL and Elastic controllers each repeated the two-file write; the output file names now live in one place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- windowing, sketch_parameters and aggregate_cleanup are rejected by build_milp_workload, since the MILP picks windows and parameters itself. - Per-group step_ms/range_duration_ms move to reject_unwritable_queries (formerly reject_avg_queries), so print-only asap-optimizer-cli runs still plan them. - asap-planner --planner milp rejects a zero scrape interval and the ClickHouse flags. Refs #790 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Re the |
# Conflicts: # asap-planner-rs/src/bin/optimizer_cli.rs # asap-planner-rs/src/optimizer/milp.rs
A5′ of #790.
asap-planner --planner milpplans with sketch-bench's rqe-optimizer MILP and writesstreaming_config.yaml/inference_config.yaml. The default islegacy, which is unchanged.Changes
optimizer::plan_milp(config, &MilpInputs)loads the facts and cost table, builds the objective and solves. Bothasap-plannerandasap-optimizer-clicall it.parse_weightmoved there from the CLI.PlannerOutput::write_to_dir: serializes both YAMLs before writing either. Both MILP paths and the PromQL, SQL and Elastic controllers'generate_to_diruse it, so the output file names live in one place.asap-plannerflags:--planner legacy|milp--workload-facts,--atomic-costsand--saturation-dir(required withmilp; the saturation curves came with feat(planner): read MILP accuracy from sketch-bench's saturation curves; heap from the plan #804, andplan_milppasses them tosolve_milpas the accuracy source)--w-cpuand--w-mem(optional)--planner milpis an error.--planner milpaccepts only PromQL with--input_config. These are errors:--query-language sql|elastic_*--query-log(it has nometrics:hints)--prometheus-url(labels come from the hints)--enable-punting,--range-duration-ms,--step-mswindowing,sketch_parametersandaggregate_cleanupare rejected bybuild_milp_workload(both binaries, always): the MILP picks windows and sketch parameters itself.reject_unwritable_queries(formerlyreject_avg_queries) rejects avg queries (A3b) and per-groupstep_ms/range_duration_ms, which only size retention that MILP configs don't set yet (planner: MILP plan → InferenceConfig should use ReadBased cleanup instead of NoCleanup #800). It runs only when configs are written, so print-onlyasap-optimizer-cliruns still plan them.--planner milpalso rejects--data-ingestion-interval-ms 0,--clickhouse-urland--clickhouse-database.allow_undeployable_familiesis always false inasap-planner, which always writes configs.Test plan
unsupported_config_fields_are_rejected,range_query_overrides_block_only_the_written_configs.cargo test -p asap_planner(123 tests), clippy with-D warnings, fmt; pre-commit hooks passed.--planner milpon a sum / rate / quantile / topk workload. It wrote 4 aggregations: DatasketchesKLL, MultipleIncrease, MultipleSum and CountMinSketchWithHeap. I checked the rejection errors for missing facts/costs,--step-ms, and MILP flags without--planner milp. Legacy runs unchanged.sketch-bench/out*/rqe_atomic_costs.json) are older than the rqe-optimizer version pinned in feat(planner): deploy DDSketch from MILP plans #806. Theirddrows lackmean_relative_value_error, and rqe-optimizer panics on that, so the smoke run used a copy with theddrows removed. A fresh export is needed.🤖 Generated with Claude Code