diff --git a/asap-planner-rs/src/optimizer/pipeline.rs b/asap-planner-rs/src/optimizer/pipeline.rs index e0132cf..ff4a106 100644 --- a/asap-planner-rs/src/optimizer/pipeline.rs +++ b/asap-planner-rs/src/optimizer/pipeline.rs @@ -7,36 +7,50 @@ use crate::config::input::ControllerConfig; use super::aqe_extractor::{extract_aqes, RQE}; use super::cost_model::{AtomicCosts, CostWeights}; use super::greedy::greedy_assign; -use super::solution::OptimizerSolution; +use super::solution::{OptimizerSolution, AQE}; use super::translator::{translate, TranslationSummary}; -/// Run the all-EXACT optimizer pipeline (Phase 1 scaffolding). -/// -/// Converts a `ControllerConfig` into `(StreamingConfig, InferenceConfig)` via -/// the optimizer path: RQEs → AQEs → all-EXACT solution → deployment artifacts. -/// -/// No streaming configs are deployed — every AQE falls back to raw data at -/// query time. This validates the end-to-end pipeline plumbing before real -/// sketch selection logic is added in Phase 2. -pub fn run_all_exact_pipeline( +/// Shared shell for optimizer pipelines: RQEs → AQEs → `solve` → deployment +/// artifacts, with a uniform log line. `solver_name` only affects the log. +fn run_pipeline( config: &ControllerConfig, schema: &PromQLSchema, + solver_name: &str, + solve: impl FnOnce(Vec) -> OptimizerSolution, ) -> (StreamingConfig, InferenceConfig) { let rqes = config_to_rqes(config); let aqes = extract_aqes(&rqes, schema); - let solution = OptimizerSolution::all_exact(aqes); + let solution = solve(aqes); let summary = TranslationSummary::from_solution(&solution); tracing::info!( + solver = solver_name, num_deployed_configs = summary.num_deployed_configs, num_sketch_assignments = summary.num_sketch_assignments, num_exact_fallbacks = summary.num_exact_fallbacks, - "optimizer pipeline: all-EXACT solution produced" + estimated_ingest_cost_per_sec = solution.estimated_ingest_cost_per_sec, + estimated_total_cost_per_sec = solution.estimated_total_cost_per_sec, + "optimizer pipeline: solution produced" ); translate(&solution) } +/// Run the all-EXACT optimizer pipeline (Phase 1 scaffolding). +/// +/// Converts a `ControllerConfig` into `(StreamingConfig, InferenceConfig)` via +/// the optimizer path: RQEs → AQEs → all-EXACT solution → deployment artifacts. +/// +/// No streaming configs are deployed — every AQE falls back to raw data at +/// query time. This validates the end-to-end pipeline plumbing before real +/// sketch selection logic is added in Phase 2. +pub fn run_all_exact_pipeline( + config: &ControllerConfig, + schema: &PromQLSchema, +) -> (StreamingConfig, InferenceConfig) { + run_pipeline(config, schema, "all-EXACT", OptimizerSolution::all_exact) +} + /// Run the greedy optimizer pipeline (Phase 2): each AQE is assigned, independently, /// to its cheapest feasible candidate config (or to the EXACT fallback). /// @@ -52,27 +66,15 @@ pub fn run_greedy_pipeline( scrape_interval_secs: u64, rho_g: f64, ) -> (StreamingConfig, InferenceConfig) { - let rqes = config_to_rqes(config); - let aqes = extract_aqes(&rqes, schema); - let solution = greedy_assign( - aqes, - scrape_interval_secs, - rho_g, - &AtomicCosts::default(), - &CostWeights::default(), - ); - - let summary = TranslationSummary::from_solution(&solution); - tracing::info!( - num_deployed_configs = summary.num_deployed_configs, - num_sketch_assignments = summary.num_sketch_assignments, - num_exact_fallbacks = summary.num_exact_fallbacks, - estimated_ingest_cost_per_sec = solution.estimated_ingest_cost_per_sec, - estimated_total_cost_per_sec = solution.estimated_total_cost_per_sec, - "optimizer pipeline: greedy solution produced" - ); - - translate(&solution) + run_pipeline(config, schema, "greedy", |aqes| { + greedy_assign( + aqes, + scrape_interval_secs, + rho_g, + &AtomicCosts::default(), + &CostWeights::default(), + ) + }) } /// Convert a `ControllerConfig`'s query groups into a flat list of RQEs.