1616STANDARD_DESIGNS = ("aes" , "ibex" , "jpeg" )
1717
1818STRESS_SUITE = "stress"
19+ HORROR_SUITE = "horror"
1920
2021# Chosen to increase routing difficulty without making the suite too brittle.
2122STRESS_CORE_UTILIZATION = {
3132 ("nangate45" , "aes" ): ["FLOORPLAN_DEF=" ],
3233}
3334
35+ HORROR_DESIGN_CONFIG = "./designs/sky130hd/jpeg/config_horror.mk"
36+ HORROR_PLACE_DENSITY_LB_ADDON = "0.25"
37+ HORROR_GLOBAL_ROUTE_ARGS = (
38+ "-congestion_iterations 30 -congestion_report_iter_step 5 -verbose -allow_congestion"
39+ )
40+
3441
3542@dataclass (frozen = True )
3643class IterTime :
@@ -52,7 +59,9 @@ class RunResult:
5259 variant : str
5360 drt_seconds : int | None
5461 final_drvs : int | None
62+ final_wirelength : int | None
5563 iter_drvs : dict [int , int ]
64+ iter_wirelength : dict [int , int ]
5665 iter_times : dict [int , IterTime ]
5766
5867 @property
@@ -169,18 +178,29 @@ def parse_iter_times(log_text: str) -> dict[int, IterTime]:
169178 return result
170179
171180
172- def parse_route_metrics (metrics_path : Path ) -> tuple [int | None , dict [int , int ]]:
181+ def parse_route_metrics (metrics_path : Path ) -> tuple [int | None , dict [int , int ], int | None , dict [ int , int ] ]:
173182 if not metrics_path .exists ():
174- return None , {}
183+ return None , {}, None , {}
175184 data = json .loads (metrics_path .read_text ())
176185 final_drvs = data .get ("detailedroute__route__drc_errors" )
186+ final_wirelength = data .get ("detailedroute__route__wirelength" )
177187 iter_drvs : dict [int , int ] = {}
188+ iter_wirelength : dict [int , int ] = {}
178189 for key , value in data .items ():
179190 m = re .match (r"detailedroute__route__drc_errors__iter:(\d+)$" , key )
180- if not m :
191+ if m :
192+ iter_drvs [int (m .group (1 ))] = int (value )
181193 continue
182- iter_drvs [int (m .group (1 ))] = int (value )
183- return (int (final_drvs ) if final_drvs is not None else None ), iter_drvs
194+ m = re .match (r"detailedroute__route__wirelength__iter:(\d+)$" , key )
195+ if m :
196+ iter_wirelength [int (m .group (1 ))] = int (value )
197+ continue
198+ return (
199+ int (final_drvs ) if final_drvs is not None else None ,
200+ iter_drvs ,
201+ int (final_wirelength ) if final_wirelength is not None else None ,
202+ iter_wirelength ,
203+ )
184204
185205
186206def parse_run (work_home : Path , platform : str , design : str , variant : str ) -> RunResult :
@@ -189,14 +209,16 @@ def parse_run(work_home: Path, platform: str, design: str, variant: str) -> RunR
189209 log_text = log_path .read_text () if log_path .exists () else ""
190210 drt_seconds = parse_drt_seconds (log_text )
191211 iter_times = parse_iter_times (log_text )
192- final_drvs , iter_drvs = parse_route_metrics (metrics_path )
212+ final_drvs , iter_drvs , final_wirelength , iter_wirelength = parse_route_metrics (metrics_path )
193213 return RunResult (
194214 platform = platform ,
195215 design = design ,
196216 variant = variant ,
197217 drt_seconds = drt_seconds ,
198218 final_drvs = final_drvs ,
219+ final_wirelength = final_wirelength ,
199220 iter_drvs = iter_drvs ,
221+ iter_wirelength = iter_wirelength ,
200222 iter_times = iter_times ,
201223 )
202224
@@ -275,6 +297,8 @@ def run_drt(
275297 env : dict [str , str ],
276298 extra_args : str | None ,
277299 make_overrides : list [str ],
300+ extra_make_overrides : list [str ] | None = None ,
301+ extra_env : dict [str , str ] | None = None ,
278302) -> None :
279303 platform = Path (design_config ).parts [- 3 ]
280304 design = Path (design_config ).parts [- 2 ]
@@ -286,11 +310,18 @@ def run_drt(
286310 dst_variant = variant ,
287311 )
288312 env = dict (env )
313+ if extra_env :
314+ env .update (extra_env )
289315 if extra_args :
290316 env ["DETAILED_ROUTE_EXTRA_ARGS" ] = extra_args
291317 else :
292318 env .pop ("DETAILED_ROUTE_EXTRA_ARGS" , None )
293319
320+ combined_overrides = list (make_overrides )
321+ if extra_make_overrides :
322+ combined_overrides .extend (extra_make_overrides )
323+ combined_overrides = _normalize_make_overrides (combined_overrides )
324+
294325 _make (
295326 flow_dir ,
296327 [
@@ -299,7 +330,7 @@ def run_drt(
299330 f"WORK_HOME={ work_home } " ,
300331 f"NUM_CORES={ threads } " ,
301332 f"OPENROAD_EXE={ openroad_exe } " ,
302- * make_overrides ,
333+ * combined_overrides ,
303334 "do-5_2_route" ,
304335 ],
305336 env = env ,
@@ -379,10 +410,16 @@ def main() -> int:
379410 )
380411 ap .add_argument (
381412 "--suite" ,
382- choices = ("standard" , STRESS_SUITE ),
413+ choices = ("standard" , STRESS_SUITE , HORROR_SUITE ),
383414 default = "standard" ,
384415 help = "Benchmark suite selection." ,
385416 )
417+ ap .add_argument (
418+ "--mode" ,
419+ choices = ("both" , "control" , "doomed" ),
420+ default = "both" ,
421+ help = "Which variants to run (default: both)." ,
422+ )
386423 ap .add_argument (
387424 "--platform" ,
388425 action = "append" ,
@@ -452,6 +489,24 @@ def main() -> int:
452489 default = None ,
453490 help = "Directory for summary artifacts (default: <work_home>/doomed_clips_benchmark)." ,
454491 )
492+ ap .add_argument (
493+ "--horror-control-end-iter" ,
494+ type = int ,
495+ default = 40 ,
496+ help = f"For --suite { HORROR_SUITE } : DETAILED_ROUTE_END_ITERATION for the control run." ,
497+ )
498+ ap .add_argument (
499+ "--horror-slay-max-iter" ,
500+ type = int ,
501+ default = 3 ,
502+ help = f"For --suite { HORROR_SUITE } : DETAILED_ROUTE_MULTI_START_MAX_ITER for the doomed run." ,
503+ )
504+ ap .add_argument (
505+ "--horror-slay-max-runs" ,
506+ type = int ,
507+ default = 1 ,
508+ help = f"For --suite { HORROR_SUITE } : DETAILED_ROUTE_MULTI_START_MAX_RUNS for the doomed run." ,
509+ )
455510 args = ap .parse_args ()
456511
457512 flow_dir : Path = args .flow_dir
@@ -479,11 +534,14 @@ def main() -> int:
479534 design = parts [- 2 ]
480535 suite .append ((platform , design , design_config ))
481536 else :
482- platforms = args .platform or list (STANDARD_PLATFORMS )
483- designs = args .design or list (STANDARD_DESIGNS )
484- for platform in platforms :
485- for design in designs :
486- suite .append ((platform , design , f"./designs/{ platform } /{ design } /config.mk" ))
537+ if args .suite == HORROR_SUITE :
538+ suite .append (("sky130hd" , "jpeg" , HORROR_DESIGN_CONFIG ))
539+ else :
540+ platforms = args .platform or list (STANDARD_PLATFORMS )
541+ designs = args .design or list (STANDARD_DESIGNS )
542+ for platform in platforms :
543+ for design in designs :
544+ suite .append ((platform , design , f"./designs/{ platform } /{ design } /config.mk" ))
487545 env = dict (os .environ )
488546 env ["OR_SEED" ] = str (args .or_seed )
489547 env ["OR_K" ] = str (args .or_k )
@@ -520,6 +578,15 @@ def main() -> int:
520578 )
521579 make_overrides .extend (STRESS_PER_CASE_OVERRIDES .get ((platform , design ), []))
522580
581+ if args .suite == HORROR_SUITE :
582+ make_overrides .extend (
583+ [
584+ f"PLACE_DENSITY_LB_ADDON={ HORROR_PLACE_DENSITY_LB_ADDON } " ,
585+ f"GLOBAL_ROUTE_ARGS={ HORROR_GLOBAL_ROUTE_ARGS } " ,
586+ "SKIP_ANTENNA_REPAIR_POST_DRT=1" ,
587+ ]
588+ )
589+
523590 make_overrides .extend (user_overrides )
524591 try :
525592 make_overrides = _normalize_make_overrides (make_overrides )
@@ -543,28 +610,46 @@ def main() -> int:
543610 env = env ,
544611 make_overrides = make_overrides ,
545612 )
546- run_drt (
547- flow_dir = flow_dir ,
548- work_home = work_home ,
549- design_config = design_config ,
550- variant = control_variant ,
551- openroad_exe = openroad_control ,
552- threads = args .threads ,
553- env = env ,
554- extra_args = None ,
555- make_overrides = make_overrides ,
556- )
557- run_drt (
558- flow_dir = flow_dir ,
559- work_home = work_home ,
560- design_config = design_config ,
561- variant = doomed_variant ,
562- openroad_exe = openroad_doomed ,
563- threads = args .threads ,
564- env = env ,
565- extra_args = args .doomed_args ,
566- make_overrides = make_overrides ,
567- )
613+ if args .mode in ("both" , "control" ):
614+ run_drt (
615+ flow_dir = flow_dir ,
616+ work_home = work_home ,
617+ design_config = design_config ,
618+ variant = control_variant ,
619+ openroad_exe = openroad_control ,
620+ threads = args .threads ,
621+ env = env ,
622+ extra_args = None ,
623+ make_overrides = make_overrides ,
624+ extra_make_overrides = [
625+ f"DETAILED_ROUTE_END_ITERATION={ args .horror_control_end_iter } "
626+ ]
627+ if args .suite == HORROR_SUITE
628+ else None ,
629+ )
630+ if args .mode in ("both" , "doomed" ):
631+ doomed_env : dict [str , str ] | None = None
632+ if args .suite == HORROR_SUITE :
633+ doomed_env = {
634+ "DETAILED_ROUTE_MULTI_START" : "1" ,
635+ "DETAILED_ROUTE_MULTI_START_MAX_ITER" : str (args .horror_slay_max_iter ),
636+ "DETAILED_ROUTE_MULTI_START_MAX_RUNS" : str (args .horror_slay_max_runs ),
637+ "DETAILED_ROUTE_MULTI_START_ACCEPT_BEST" : "1" ,
638+ "DETAILED_ROUTE_MULTI_START_FALLBACK_TO_SINGLE" : "0" ,
639+ "DETAILED_ROUTE_MULTI_START_OR_K" : "0.0" ,
640+ }
641+ run_drt (
642+ flow_dir = flow_dir ,
643+ work_home = work_home ,
644+ design_config = design_config ,
645+ variant = doomed_variant ,
646+ openroad_exe = openroad_doomed ,
647+ threads = args .threads ,
648+ env = env ,
649+ extra_args = args .doomed_args ,
650+ make_overrides = make_overrides ,
651+ extra_env = doomed_env ,
652+ )
568653
569654 control = parse_run (work_home , platform , design , control_variant )
570655 doomed = parse_run (work_home , platform , design , doomed_variant )
@@ -588,12 +673,20 @@ def main() -> int:
588673 "speedup" : speedup ,
589674 "control_final_drvs" : "" if control .final_drvs is None else str (control .final_drvs ),
590675 "doomed_final_drvs" : "" if doomed .final_drvs is None else str (doomed .final_drvs ),
676+ "control_final_wirelength" : ""
677+ if control .final_wirelength is None
678+ else str (control .final_wirelength ),
679+ "doomed_final_wirelength" : ""
680+ if doomed .final_wirelength is None
681+ else str (doomed .final_wirelength ),
591682 "control_avg_eff_cores" : f"{ control .avg_effective_cores :.2f} "
592683 if control .avg_effective_cores is not None
593684 else "" ,
594685 "doomed_avg_eff_cores" : f"{ doomed .avg_effective_cores :.2f} "
595686 if doomed .avg_effective_cores is not None
596687 else "" ,
688+ "control_iter_count" : str (len (control .iter_times )),
689+ "doomed_iter_count" : str (len (doomed .iter_times )),
597690 }
598691 )
599692 keys = list (rows [0 ].keys ()) if rows else []
0 commit comments