Skip to content

[GPL] Add set_net_weight/unset_net_weight commands#10049

Open
jeffrey-song-melten wants to merge 1 commit intoThe-OpenROAD-Project:masterfrom
jeffrey-song-melten:feat/gpl-set-net-weight
Open

[GPL] Add set_net_weight/unset_net_weight commands#10049
jeffrey-song-melten wants to merge 1 commit intoThe-OpenROAD-Project:masterfrom
jeffrey-song-melten:feat/gpl-set-net-weight

Conversation

@jeffrey-song-melten
Copy link
Copy Markdown

Summary

  • Add set_net_weight / unset_net_weight TCL commands for per-net custom placement weight
  • Weights stored as dbDoubleProperty("gpl_weight") on dbNet — persistent across write_db/read_db
  • NesterovBase reads the property during GNet construction via existing setCustomWeight()

Motivation

External tools (e.g., timing-driven convergence loops) need to guide global placement by annotating specific nets with higher importance. This is useful for IP-level characterization → integration PnR workflows where sensitive nets identified during standalone analysis should receive higher placement priority.

Test plan

  • net_weight01.tcl: 7 positive tests (set, verify ODB property, unset, multiple nets, global_placement with weights, overwrite, write_db persistence)
  • net_weight_negative.tcl: 7 negative tests (non-existent net, zero weight, negative weight, unset non-existent, wrong arg count, non-numeric, unset without prior set)
  • Tests registered in CMakeLists.txt and BUILD
  • Golden .ok files generated

Related

🤖 Generated with Claude Code

Add TCL commands to set per-net custom placement weights via
persistent ODB properties. This enables external tools to guide
global placement by annotating nets with importance weights
(e.g., from IP-level timing characterization).

Implementation:
- set_net_weight stores weight as dbDoubleProperty("gpl_weight")
  on the target dbNet. Persists across write_db/read_db.
- unset_net_weight removes the property.
- NesterovBase reads gpl_weight during GNet construction and
  applies it via the existing setCustomWeight() method.
- TCL validation: positive finite float, design block required.

New commands:
  set_net_weight <net_name> <weight>
  unset_net_weight <net_name>

Signed-off-by: Jeffrey Song <jeffrey@melten.ai>
Signed-off-by: Jeffrey Song <jonguk@gmail.com>
Copy link
Copy Markdown
Contributor

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

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 the ability to set and unset custom net weights for global placement. It adds Tcl commands (set_net_weight, unset_net_weight), underlying C++ implementation using ODB properties to ensure persistence, and comprehensive functional and negative tests. The review feedback highlights several improvement opportunities: adding return statements after error logging to prevent potential null pointer dereferences if the program continues, using named constants instead of magic strings for property names, and optimizing property updates by modifying existing values instead of destroying and recreating them.

Comment on lines +206 to +215
if (!net) {
ord::OpenRoad::openRoad()->getLogger()->error(
utl::GPL, 500, "Net '{}' not found.", net_name);
}
// Store as persistent ODB property so it survives write_db/read_db
auto* existing = odb::dbDoubleProperty::find(net, "gpl_weight");
if (existing) {
odb::dbDoubleProperty::destroy(existing);
}
odb::dbDoubleProperty::create(net, "gpl_weight", 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

There are a couple of improvements that can be made here:

  1. Robustness: While logger->error is expected to terminate the program, the code proceeds to dereference net on the following lines, which will cause a crash if net is null and termination does not occur. It's safer to add a return statement after calling error.
  2. Maintainability: To avoid magic strings, it's a good practice to define property names like "gpl_weight" as a constant.
  3. Efficiency: It's more efficient to update the property value if it exists, instead of destroying and recreating it.

The suggested code applies these improvements.

  if (!net) {
    ord::OpenRoad::openRoad()->getLogger()->error(
        utl::GPL, 500, "Net '{}' not found.", net_name);
    return;
  }
  // Store as persistent ODB property so it survives write_db/read_db
  static const char* gpl_weight_prop_name = "gpl_weight";
  if (auto* prop = odb::dbDoubleProperty::find(net, gpl_weight_prop_name)) {
    prop->setValue(weight);
  } else {
    odb::dbDoubleProperty::create(net, gpl_weight_prop_name, weight);
  }
References
  1. Define tunable parameters as named constants instead of using hardcoded magic numbers.

Comment on lines +223 to +230
if (!net) {
ord::OpenRoad::openRoad()->getLogger()->error(
utl::GPL, 501, "Net '{}' not found.", net_name);
}
auto* existing = odb::dbDoubleProperty::find(net, "gpl_weight");
if (existing) {
odb::dbDoubleProperty::destroy(existing);
}
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

There are a couple of improvements that can be made here:

  1. Robustness: While logger->error is expected to terminate, the code proceeds to dereference net on the following lines, which will cause a crash if net is null and termination does not occur. It's safer to add a return statement after calling error.
  2. Maintainability: To avoid magic strings, it's a good practice to define property names like "gpl_weight" as a constant.

The suggested code applies these improvements and uses a more concise if statement with an initializer.

  if (!net) {
    ord::OpenRoad::openRoad()->getLogger()->error(
        utl::GPL, 501, "Net '{}' not found.", net_name);
    return;
  }
  static const char* gpl_weight_prop_name = "gpl_weight";
  if (auto* existing = odb::dbDoubleProperty::find(net, gpl_weight_prop_name)) {
    odb::dbDoubleProperty::destroy(existing);
  }
References
  1. Define tunable parameters as named constants instead of using hardcoded magic numbers.

Comment on lines +1103 to +1107
odb::dbDoubleProperty* wp
= odb::dbDoubleProperty::find(net->getDbNet(), "gpl_weight");
if (wp) {
myGNet.setCustomWeight(static_cast<float>(wp->getValue()));
}
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

To improve maintainability and avoid magic strings, it's a good practice to define property names as constants. This also allows for a more concise check using an if statement with an initializer.

A similar change should be applied in src/gpl/src/replace.i where this property is set.

    static const char* gpl_weight_prop_name = "gpl_weight";
    if (auto* wp = odb::dbDoubleProperty::find(net->getDbNet(), gpl_weight_prop_name)) {
      myGNet.setCustomWeight(static_cast<float>(wp->getValue()));
    }
References
  1. Define tunable parameters as named constants instead of using hardcoded magic numbers.

@maliberty maliberty requested a review from gudeh April 6, 2026 14:37
@maliberty maliberty added the gpl Global Placement label Apr 6, 2026
for (auto& net : pbc_->getNets()) {
GNet myGNet(net);
// Read custom placement weight from ODB property (set by set_net_weight)
odb::dbDoubleProperty* wp
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.

Would be nice to have better names for variables, for example renaming wp and myGNet. Perhaps net_property, and temp_gnet?

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.

Most importantly, the setting of timing-driven weights does not originally happen here. This is currently not protected by timing-driven mode being activated.

I believe this should happen at:

bool TimingBase::executeTimingDriven(bool run_journal_restore)

Notice how we originally set weights at the following, after RSZ is executed:

gNet->setTimingWeight(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.

This is an interesting new feature!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gpl Global Placement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants