11use asap_planner:: optimizer:: {
2- parse_weight, plan_milp, plan_to_planner_output, reject_unwritable_queries, MilpInputs ,
2+ parse_weight, plan_milp, plan_to_planner_output, reject_unwritable_queries, saved_plan_output,
3+ MilpInputs , PlanSelector ,
34} ;
45use asap_planner:: {
56 Controller , ControllerConfig , ElasticController , ElasticRuntimeOptions , RuntimeOptions ,
@@ -57,10 +58,33 @@ struct Args {
5758 clickhouse_database : Option < String > ,
5859
5960 /// `milp` plans with sketch-bench's rqe-optimizer: PromQL with
60- /// --input_config only, labels from its `metrics:` hints.
61+ /// --input_config only, labels from its `metrics:` hints. `saved` writes
62+ /// a plan sketch-bench's `autosketch_vs_asap` already solved.
6163 #[ arg( long, value_enum, default_value = "legacy" ) ]
6264 planner : PlannerArg ,
6365
66+ /// Saved only. sketch-bench `autosketch_vs_asap` plan file
67+ /// (`<table>.plans.json.gz`).
68+ #[ arg( long, required_if_eq( "planner" , "saved" ) ) ]
69+ plan : Option < PathBuf > ,
70+
71+ /// Saved only. The eval workload table the plan was solved for; its
72+ /// `e2e` block gives the PromQL queries and metric labels.
73+ #[ arg( long = "workload-table" , required_if_eq( "planner" , "saved" ) ) ]
74+ workload_table : Option < PathBuf > ,
75+
76+ /// Saved only. The plan's method, e.g. `asap`.
77+ #[ arg( long, required_if_eq( "planner" , "saved" ) ) ]
78+ method : Option < String > ,
79+
80+ /// Saved only. The plan's objective weights, e.g. `cpu` or `fargate`.
81+ #[ arg( long, required_if_eq( "planner" , "saved" ) ) ]
82+ weights : Option < String > ,
83+
84+ /// Saved only. The plan at this latency SLA; without it, the cheapest.
85+ #[ arg( long = "sla-ms" ) ]
86+ sla_ms : Option < f64 > ,
87+
6488 /// MILP only. YAML workload facts: per metric, positive `value_range` and
6589 /// `cardinality` per label set, including all labels (the series count),
6690 /// plus the `shape` of each grouping sketches may serve.
@@ -99,6 +123,7 @@ enum EngineArg {
99123enum PlannerArg {
100124 Legacy ,
101125 Milp ,
126+ Saved ,
102127}
103128
104129fn main ( ) -> anyhow:: Result < ( ) > {
@@ -116,8 +141,22 @@ fn main() -> anyhow::Result<()> {
116141 EngineArg :: Precompute => StreamingEngine :: Precompute ,
117142 } ;
118143
119- if args. planner == PlannerArg :: Milp {
120- run_milp ( & args) ?;
144+ if args. planner != PlannerArg :: Saved {
145+ anyhow:: ensure!(
146+ args. plan. is_none( )
147+ && args. workload_table. is_none( )
148+ && args. method. is_none( )
149+ && args. weights. is_none( )
150+ && args. sla_ms. is_none( ) ,
151+ "--plan, --workload-table, --method, --weights and --sla-ms require --planner saved"
152+ ) ;
153+ }
154+ if args. planner != PlannerArg :: Legacy {
155+ match args. planner {
156+ PlannerArg :: Milp => run_milp ( & args) ?,
157+ PlannerArg :: Saved => run_saved ( & args) ?,
158+ PlannerArg :: Legacy => unreachable ! ( ) ,
159+ }
121160 println ! ( "Generated configs in {}" , args. output_dir. display( ) ) ;
122161 return Ok ( ( ) ) ;
123162 }
@@ -274,3 +313,52 @@ fn run_milp(args: &Args) -> anyhow::Result<()> {
274313 . write_to_dir ( & args. output_dir ) ?;
275314 Ok ( ( ) )
276315}
316+
317+ fn run_saved ( args : & Args ) -> anyhow:: Result < ( ) > {
318+ anyhow:: ensure!(
319+ args. input_config. is_none( ) && args. query_log. is_none( ) ,
320+ "--planner saved reads its queries from --workload-table, not --input_config or --query-log"
321+ ) ;
322+ anyhow:: ensure!(
323+ matches!( args. query_language, QueryLanguage :: promql)
324+ && args. prometheus_url. is_none( )
325+ && !args. enable_punting
326+ && args. range_duration_ms == 0
327+ && args. step_ms == 0
328+ && args. clickhouse_url. is_none( )
329+ && args. clickhouse_database. is_none( ) ,
330+ "--planner saved takes only PromQL and none of --prometheus-url, --enable-punting, \
331+ --range-duration-ms, --step-ms, --clickhouse-url, --clickhouse-database"
332+ ) ;
333+ anyhow:: ensure!(
334+ args. workload_facts. is_none( )
335+ && args. atomic_costs. is_none( )
336+ && args. saturation_dir. is_none( )
337+ && args. w_cpu. is_none( )
338+ && args. w_mem. is_none( ) ,
339+ "--workload-facts, --atomic-costs, --saturation-dir, --w-cpu and --w-mem require \
340+ --planner milp"
341+ ) ;
342+ let scrape_interval_ms = args
343+ . data_ingestion_interval_ms
344+ . filter ( |& ms| ms > 0 )
345+ . ok_or_else ( || {
346+ anyhow:: anyhow!( "--planner saved requires a positive --data-ingestion-interval-ms" )
347+ } ) ?;
348+ saved_plan_output (
349+ args. workload_table
350+ . as_deref ( )
351+ . expect ( "clap requires --workload-table with --planner saved" ) ,
352+ args. plan
353+ . as_deref ( )
354+ . expect ( "clap requires --plan with --planner saved" ) ,
355+ & PlanSelector {
356+ method : args. method . as_deref ( ) . expect ( "clap requires --method" ) ,
357+ weights : args. weights . as_deref ( ) . expect ( "clap requires --weights" ) ,
358+ sla_ms : args. sla_ms ,
359+ } ,
360+ scrape_interval_ms,
361+ ) ?
362+ . write_to_dir ( & args. output_dir ) ?;
363+ Ok ( ( ) )
364+ }
0 commit comments