Skip to content

feat(asap-tools): run the e2e planner through the rqe-optimizer MILP (planner.use_optimizer) - #831

Open
milindsrivastava1997 wants to merge 2 commits into
mainfrom
830-featasap-tools-run-the-e2e-planner-through-the-rqe-optimizer-milp-planneruse_optimizer
Open

milindsrivastava1997 wants to merge 2 commits into
mainfrom
830-featasap-tools-run-the-e2e-planner-through-the-rqe-optimizer-milp-planneruse_optimizer

Conversation

@milindsrivastava1997

Copy link
Copy Markdown
Contributor

Closes #830.

experiment_run_e2e now starts asap-planner --planner milp (sketch-bench's rqe-optimizer) when the new Hydra option planner.use_optimizer is on (default true).

Config (config/config.yaml):

planner:
  use_optimizer: true
  saturation_dir: null  # remote; atomic costs read from optimizer_cost/rqe_atomic_costs.json inside it
  workload_facts: null  # remote path to the workload-facts YAML
  w_cpu: null           # null = rqe-optimizer default
  w_mem: null

Changes

  • MilpPlanner (experiment_utils/services/misc.py): ControllerService.start(milp=...) adds --planner milp --workload-facts --atomic-costs --saturation-dir [--w-cpu] [--w-mem] on bare metal. In the containerized path it passes the inputs to generate_controller_compose.py.
  • asap-planner-rs/docker-compose.yml.j2: mounts the saturation dir and the facts file read-only (/app/saturation, /app/input/workload_facts.yaml) and points the MILP flags at them.
  • config.milp_planner(cfg) fails fast on settings the MILP can't honor:
    • saturation_dir or workload_facts unset
    • controller.punting=true
    • controller.auto_discover_labels=true
    • windowing set
  • experiment_run_e2e leaves aggregate_cleanup and sketch_parameters out of the planner input when the optimizer is on: the MILP rejects both and chooses them itself.
  • experiment_run_clickhouse fails fast when use_optimizer=true, because MILP doesn't support SQL. The grafana demo and ingest-path scripts are unchanged.

Notes

Testing

  • pytest asap-tools/experiments/tests: 61 passed. New tests are in tests/test_planner_config.py and tests/test_controller_service.py.
  • Not yet run end to end on a cluster.

🤖 Generated with Claude Code

milindsrivastava1997 and others added 2 commits October 12, 2026 11:12
…(planner.use_optimizer)

planner.use_optimizer (default true) makes experiment_run_e2e start
asap-planner with --planner milp, reading planner.saturation_dir (atomic
costs at optimizer_cost/rqe_atomic_costs.json inside it) and
planner.workload_facts on the remote, plus optional w_cpu/w_mem. The
containerized planner mounts both read-only.

Settings the MILP can't honor fail fast: punting, auto_discover_labels,
windowing, and the scripts that only run the legacy planner (ClickHouse,
grafana demo, ingest path). aggregate_cleanup and sketch_parameters are
left out of the planner input since the MILP picks both.

Closes #830

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

@milindsrivastava1997 milindsrivastava1997 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core wiring looks right: the CLI flags match asap-planner-rs/src/main.rs, the compose mounts are correct, and generate_controller_client_configs already handles None for cleanup and sketch params. Inline comments cover the rest. Two points that touch lines outside the diff:

  • The Grafana demo and ingest-path scripts silently run the legacy planner when use_optimizer=true. experiment_run_grafana_demo.py and experiment_only_ingest_path.py read the same config and call controller_service.start(...) without milp. ClickHouse got a guard, so this is inconsistent, and it breaks fail-loud: a user who sets use_optimizer=true for a Grafana demo gets a legacy plan with no warning. Either add require_legacy_planner there too (this only works if the default becomes false), or wire milp through.
  • Tests: the negative paths are covered well. Nothing covers the default-config interaction, though: a test that loads the real config.yaml defaults and runs the ClickHouse guard would have caught the regression flagged on experiment_run_clickhouse.py.
  • Nit (predates this PR): Args.cleanup_policy (config.py:612) is set but never read anywhere, and it's now misleading under MILP. Drop it if you're nearby.

+ config.required_cloudlab_params(cfg),
script_name="experiment_run_clickhouse",
)
config.require_legacy_planner(cfg, "experiment_run_clickhouse")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

experiment_run_clickhouse now fails by default. config.yaml defaults planner.use_optimizer: true, and this guard runs first, so every ClickHouse run now needs planner.use_optimizer=false. The PR notes cover the e2e break but not this one. Options: default use_optimizer: false (this also avoids breaking e2e runs until the saturation and facts inputs are routinely available), have ClickHouse ignore the key, or keep the guard and document the required override.

"--enable-punting"{% endif %}{% if saturation_dir %},
"--planner", "milp",
"--workload-facts", "/app/input/workload_facts.yaml",
"--atomic-costs", "/app/saturation/optimizer_cost/rqe_atomic_costs.json",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cost-table path is written in two places: here and as COST_TABLE in experiment_utils/services/misc.py. Pass it into the template (e.g. /app/saturation/{{ cost_table }}) so there is one source of truth.

"--workload-facts", "/app/input/workload_facts.yaml",
"--atomic-costs", "/app/saturation/optimizer_cost/rqe_atomic_costs.json",
"--saturation-dir", "/app/saturation"{% endif %}{% if w_cpu is not none %},
"--w-cpu", "{{ w_cpu }}"{% endif %}{% if w_mem is not none %},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: --w-cpu/--w-mem sit outside {% if saturation_dir %}, and generate_controller_compose.py only checks that saturation-dir and facts are set together. Weights without a saturation dir would render flags the planner rejects (main.rs:125). That fails loudly, so it's harmless, but nesting the weights inside the block or adding them to the generator's parser.error check would be tidier.

Fails on settings --planner milp can't honor rather than dropping them.
"""
planner = cfg.get("planner")
if planner is None or not planner.get("use_optimizer", False):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use_optimizer default is set in two places: config.yaml says true, but this .get(..., False) falls back to False (same at L778 in require_legacy_planner). Since config.yaml always defines planner, read cfg.planner.use_optimizer directly.

cfg.aggregate_cleanup,
cfg.get("sketch_parameters", None),
# The MILP rejects both; it chooses sketch parameters and cleanup itself.
None if milp else cfg.aggregate_cleanup,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: with the optimizer on, aggregate_cleanup and sketch_parameters are dropped without a message. That's unavoidable since config.yaml sets defaults for both, but an explicit CLI override (e.g. sketch_parameters.CountMinSketch.width=4096) vanishes quietly. Consider a one-line log when the optimizer is on.

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.

feat(asap-tools): run the e2e planner through the rqe-optimizer MILP (planner.use_optimizer)

1 participant