Skip to content

gpl: Expose PDK-aware GPL parameters through variables.yaml - #4418

Draft
oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:gpl-heuristics-orfs
Draft

gpl: Expose PDK-aware GPL parameters through variables.yaml#4418
oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:gpl-heuristics-orfs

Conversation

@oharboe

@oharboe oharboe commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Update variables.yaml and global_place.tcl to expose OpenROAD global placement tuning parameters (-init_wirelength_coef and -virtual_cts_max_skew_fraction). Includes the tune_gpl_magic.py Bazel-idiomatic autotuning script to find optimal placement parameters for different designs using --define.

Campaign Plan (Large Targets Sweep)

The tune_gpl_magic.py script is set up to automatically sweep parameters for the following large target set to find the optimal global placement heuristics. We will be offloading this to a more powerful machine:

sky130hd:

  • //flow/designs/sky130hd/ibex:ibex_core_route
  • //flow/designs/sky130hd/jpeg:jpeg_encoder_route
  • //flow/designs/sky130hd/microwatt:microwatt_route
  • //flow/designs/sky130hd/riscv32i:riscv_route

asap7:

  • //flow/designs/asap7/mock-array:mock_array_route
  • //flow/designs/asap7/swerv_wrapper:swerv_wrapper_route
  • //flow/designs/asap7/tinyRocket:RocketTile_route

The hyper-parameters we will sweep are:

  • GPL_WIRELENGTH_PENALTY: [0.1, 0.25, 0.5]
  • GPL_TIMING_SPAN_CLOCK_PERCENT: [0.05, 0.10, 0.15]

To execute the campaign, run:

python3 flow/scripts/tune_gpl_magic.py --campaign=large

@oharboe
oharboe force-pushed the gpl-heuristics-orfs branch from 07ab255 to 921baa7 Compare August 12, 2026 16:00

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces PDK-aware GPL parameters (GPL_WIRELENGTH_PENALTY and GPL_TIMING_SPAN_CLOCK_PERCENT) to the global placement flow, along with a hyperparameter autotuning script. Key feedback includes addressing a critical division-by-zero risk in the OpenROAD patch when effective_slack_max <= slack_min, resolving the hardcoded clock_period value, and correcting mismatched default values between global_place.tcl and variables.yaml. Additionally, the autotuner script needs to parse actual metrics instead of returning hardcoded zeros and should avoid buffering build outputs to prevent the script from appearing frozen.

Comment on lines +120 to +122
+ + (net_weight_max_ - 1) * (effective_slack_max - net_slack)
+ / (effective_slack_max - slack_min);
+ gNet->setTimingWeight(std::max(1.0f, std::min(net_weight_max_, weight)));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

If timing_weight_span_clock_percent_ is 0.0f (which is the default passed in global_place.tcl), effective_slack_max becomes exactly equal to slack_min. This causes a division by zero when calculating weight, leading to NaN propagation or crashes. Please add a guard to prevent division by zero when effective_slack_max <= slack_min.

+          if (effective_slack_max <= slack_min) {
+            gNet->setTimingWeight(net_weight_max_);
+          } else {
+            const float weight = 1
+                                 + (net_weight_max_ - 1) * (effective_slack_max - net_slack)
+                                       / (effective_slack_max - slack_min);
+            gNet->setTimingWeight(std::max(1.0f, std::min(net_weight_max_, weight)));
+          }

Comment thread flow/scripts/tune_gpl_magic.py Outdated
if result.returncode != 0:
print(f"Build failed for {pdk} {design} (penalty={penalty}, span={span})")
return None
return {"WNS": 0.0, "TNS": 0.0, "Congestion": 0.0}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Returning hardcoded 0.0 values for WNS, TNS, and Congestion makes the autotuner completely non-functional, as it cannot compare different runs to find the optimal parameters. Please implement parsing of the actual metrics from the build reports or the generated metrics JSON file.

- // weight(max_slack) = 1
+ float effective_slack_max = slack_max;
+ if (timing_weight_span_clock_percent_ >= 0.0f) {
+ float clock_period = 1.0f; // placeholder/normalized

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Hardcoding clock_period = 1.0f as a placeholder makes the percent-based timing weight span calculation incorrect for any design with a non-1.0 clock period. Please query the actual clock period from the STA database or pass it as a parameter.

Comment thread flow/scripts/global_place.tcl Outdated
Comment on lines +28 to +29
append_env_var global_placement_args GPL_WIRELENGTH_PENALTY -wirelength_penalty 0
append_env_var global_placement_args GPL_TIMING_SPAN_CLOCK_PERCENT -timing_weight_span_clock_percent 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The default values passed to append_env_var (0) do not match the default values defined in variables.yaml (1.0 for GPL_WIRELENGTH_PENALTY and -1.0 for GPL_TIMING_SPAN_CLOCK_PERCENT). This discrepancy can lead to inconsistent behavior if the environment variables are not explicitly set. Please update the defaults to match variables.yaml.

append_env_var global_placement_args GPL_WIRELENGTH_PENALTY -wirelength_penalty 1.0
append_env_var global_placement_args GPL_TIMING_SPAN_CLOCK_PERCENT -timing_weight_span_clock_percent -1.0

Comment on lines +16 to +19
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"Build failed for {pdk} {design} (penalty={penalty}, span={span})")
return None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using capture_output=True buffers all stdout and stderr in memory, which makes the script appear completely frozen during long-running Bazel builds. Since the output is not parsed, it is better to run the command without capturing output so that the user can see the build progress in real-time.

Suggested change
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"Build failed for {pdk} {design} (penalty={penalty}, span={span})")
return None
result = subprocess.run(cmd, text=True)
if result.returncode != 0:
print(f"Build failed for {pdk} {design} (penalty={penalty}, span={span})")
return None

@oharboe
oharboe force-pushed the gpl-heuristics-orfs branch from 921baa7 to b20c122 Compare August 12, 2026 16:02
@oharboe
oharboe marked this pull request as draft August 12, 2026 16:25
@openroad-ci

openroad-ci commented Aug 12, 2026

Copy link
Copy Markdown
Member

🔍 QoR check

Metrics reflect the PR merge build — i.e. what will land on the target branch. Advisory — results are log-only and do not affect build status. The authoritative QoR gate remains the local rules-file check.

Commit c04c40b · Jenkins build #4 · Baseline: build

61 design(s) checked — 8 with regression(s), 0 without a comparable baseline.
Design Variant Verdict local vs inline passed / failed / missing
asap7/aes base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/aes-block base ✅ pass ✅ MATCH 25 / 0 / 0
asap7/aes-mbff base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/aes_lvt base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/cva6 base ✅ pass ✅ MATCH 12 / 0 / 2
asap7/ethmac base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/ethmac_lvt base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/gcd base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/gcd-ccs base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/ibex base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/jpeg base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/jpeg_lvt base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/mock-alu base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/mock-cpu base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/riscv32i base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/riscv32i-mock-sram base ❌ fail ⚠️ MISMATCH 24 / 1 / 2
asap7/swerv_wrapper base ✅ pass ✅ MATCH 25 / 0 / 2
asap7/uart base ✅ pass ✅ MATCH 25 / 0 / 2
gf180/aes base ✅ pass ✅ MATCH 25 / 0 / 2
gf180/aes-hybrid base ✅ pass ✅ MATCH 25 / 0 / 2
gf180/ibex base ✅ pass ✅ MATCH 25 / 0 / 2
gf180/jpeg base ✅ pass ✅ MATCH 25 / 0 / 22
gf180/riscv32i base ✅ pass ✅ MATCH 25 / 0 / 2
gf180/uart-blocks base ✅ pass ✅ MATCH 25 / 0 / 2
gt2n/aes base ✅ pass ✅ MATCH 25 / 0 / 0
gt2n/gcd base ✅ pass ✅ MATCH 25 / 0 / 0
gt2n/jpeg base ✅ pass ✅ MATCH 25 / 0 / 0
ihp-sg13g2/aes base ✅ pass ✅ MATCH 25 / 0 / 2
ihp-sg13g2/gcd base ✅ pass ✅ MATCH 25 / 0 / 2
ihp-sg13g2/i2c-gpio-expander base ✅ pass ✅ MATCH 25 / 0 / 2
ihp-sg13g2/ibex base ❌ fail ✅ MATCH 24 / 1 / 2
ihp-sg13g2/jpeg base ✅ pass ✅ MATCH 25 / 0 / 2
ihp-sg13g2/riscv32i base ✅ pass ✅ MATCH 25 / 0 / 2
ihp-sg13g2/spi base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/aes base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/ariane133 base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/ariane136 base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/black_parrot base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/bp_be_top base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/bp_fe_top base ✅ pass ✅ MATCH 25 / 0 / 3
nangate45/bp_multi_top base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/dynamic_node base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/gcd base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/ibex base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/jpeg base ✅ pass ✅ MATCH 25 / 0 / 2
nangate45/mempool_group base ❌ fail ⚠️ MISMATCH 11 / 1 / 2
nangate45/swerv base ❌ fail ⚠️ MISMATCH 23 / 2 / 2
nangate45/swerv_wrapper base ❌ fail ✅ MATCH 22 / 3 / 2
nangate45/tinyRocket base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hd/aes base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hd/chameleon base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hd/gcd base ❌ fail ✅ MATCH 24 / 1 / 2
sky130hd/ibex base ✅ pass ✅ MATCH 25 / 0 / 4
sky130hd/jpeg base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hd/microwatt base ❌ fail ✅ MATCH 23 / 2 / 2
sky130hd/riscv32i base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hs/aes base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hs/gcd base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hs/ibex base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hs/jpeg base ✅ pass ✅ MATCH 25 / 0 / 2
sky130hs/riscv32i base ❌ fail ⚠️ MISMATCH 23 / 2 / 3
❌ asap7/riscv32i-mock-sram base — 1 failing metric(s)
Metric target base delta threshold
finish__timing__setup__tns -2635.61 -1888.2 39.58320093210465% 20%
❌ ihp-sg13g2/ibex base — 1 failing metric(s)
Metric target base delta threshold
globalroute__timing__setup__tns -3.38807 -1.35349 150.32102195066088% 20%
❌ nangate45/mempool_group base — 1 failing metric(s)
Metric target base delta threshold
finish__timing__hold__tns -0.94043 -0.313244 200.22282948755603% 20%
❌ nangate45/swerv base — 2 failing metric(s)
Metric target base delta threshold
cts__timing__setup__tns -448.945 -432.355 3.8371245851210234% 20%
globalroute__timing__setup__tns -477.642 -471.381 1.3282249390620327% 20%
❌ nangate45/swerv_wrapper base — 3 failing metric(s)
Metric target base delta threshold
cts__timing__setup__tns -458.177 -414.603 10.509813001835491% 20%
finish__timing__setup__tns -425.288 -383.316 10.949712508739525% 20%
globalroute__timing__setup__tns -508.841 -437.6 16.27993601462523% 20%
❌ sky130hd/gcd base — 1 failing metric(s)
Metric target base delta threshold
finish__timing__setup__ws -1.57388 -1.47925 6.39716072333953% 5.0%
❌ sky130hd/microwatt base — 2 failing metric(s)
Metric target base delta threshold
cts__timing__setup__tns -217.945 -211.376 3.1077321928695785% 20%
detailedroute__antenna_diodes_count 2744 2722 0.8082292432035268% 0.1%
❌ sky130hs/riscv32i base — 2 failing metric(s)
Metric target base delta threshold
finish__timing__setup__tns -323.59 -299.014 8.219013156574608% 20%
globalroute__timing__setup__tns -463.247 -437.319 5.928852851122407% 20%

@oharboe
oharboe force-pushed the gpl-heuristics-orfs branch 2 times, most recently from 79daa60 to 12e0974 Compare August 12, 2026 19:27
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe
oharboe force-pushed the gpl-heuristics-orfs branch from 12e0974 to 62f5166 Compare August 12, 2026 19:30

if { [info exists ::env(GPL_WIRELENGTH_PENALTY)] } {
lappend global_placement_args -init_wirelength_coef $::env(GPL_WIRELENGTH_PENALTY)
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

remove iffy code default values are guaranteed so env vars here are always set.

"//flow/designs/asap7/rocket:RocketTile_route"
]

# Grid of hyper-parameters

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this is a feeble autotuner at home, we need something like Optuna to drive the two dimensional search across all the designs per PDK, wire it up in bazel

description: |
Global placement wirelength penalty (passed as -init_wirelength_coef or similar logic).
stages:
- place

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

add default values here from the global placement source code

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.

2 participants