Skip to content

grt: cache per-layer wire resistance - #11622

Draft
rafaelmoresco wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:grt_small_runtime
Draft

rafaelmoresco wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:grt_small_runtime

Conversation

@rafaelmoresco

Copy link
Copy Markdown
Contributor

Summary

Chached dbuToMicron and layer resistance to avoid unecessary calls during res aware operations. In a VTune test these calls were costing a bit over 10% of Fast Route time

Type of Change

  • Refactoring

Impact

Reduce Res Aware runtime.

Verification

  • I have verified that the local build succeeds (./etc/Build.sh).
  • I have run the relevant tests and they pass.
  • My code follows the repository's formatting guidelines.
  • I have signed my commits (DCO).

Signed-off-by: rafaelmoresco <rafaelmorescovieira@gmail.com>
@rafaelmoresco rafaelmoresco self-assigned this Oct 3, 2026
@github-actions github-actions Bot added the size/S label Oct 3, 2026

@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 optimizes performance in FastRouteCore by caching dbu_per_micron_ and layer_res_per_micron_ during tech layer preprocessing, reducing database lookups in getWireResistance and dbuToMicrons. The review feedback highlights several critical safety concerns, including potential out-of-bounds vector access, null pointer dereferences, and division-by-zero vulnerabilities in the new caching logic.

Comment on lines +554 to +556
if (layer < net->getMinLayer() || layer > net->getMaxLayer()) {
return BIG_INT;
}

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

Accessing layer_res_per_micron_[layer] without verifying that layer is within the valid bounds of the vector can lead to undefined behavior or segmentation faults. Adding bounds checking ensures safety.

Suggested change
if (layer < net->getMinLayer() || layer > net->getMaxLayer()) {
return BIG_INT;
}
if (layer < 0 || layer >= layer_res_per_micron_.size() || layer < net->getMinLayer() || layer > net->getMaxLayer()) {
return BIG_INT;
}

Comment on lines 561 to 568
// If net has NDR, get the correct width value
odb::dbTechNonDefaultRule* ndr = net->getDbNet()->getNonDefaultRule();
if (ndr != nullptr) {
odb::dbTechLayer* db_layer = getTechLayer(layer, false);
odb::dbTechLayerRule* layerRule = ndr->getLayerRule(db_layer);
width = layerRule->getWidth();
const float layer_width = dbuToMicrons(layerRule->getWidth());
res_ohm_per_micron = db_layer->getResistance() / layer_width;
}

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

Several potential issues exist here:

  1. getTechLayer could return nullptr.
  2. ndr->getLayerRule(db_layer) can return nullptr if the NDR does not define a rule for the given layer.
  3. layer_width could be 0.0f, leading to a division-by-zero error.

Adding defensive checks for these cases prevents potential crashes and undefined behavior.

  // If net has NDR, get the correct width value
  odb::dbTechNonDefaultRule* ndr = net->getDbNet()->getNonDefaultRule();
  if (ndr != nullptr) {
    odb::dbTechLayer* db_layer = getTechLayer(layer, false);
    if (db_layer != nullptr) {
      odb::dbTechLayerRule* layerRule = ndr->getLayerRule(db_layer);
      if (layerRule != nullptr) {
        const float layer_width = dbuToMicrons(layerRule->getWidth());
        if (layer_width > 0.0f) {
          res_ohm_per_micron = db_layer->getResistance() / layer_width;
        }
      }
    }
  }

Comment on lines +531 to +533
// Keep layer_width as float: other rounding perturbs getWireCost() results
const float layer_width = dbuToMicrons(db_layer->getWidth());
layer_res_per_micron_[layer] = db_layer->getResistance() / layer_width;

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

If layer_width is 0.0f (e.g., due to an invalid or uninitialized layer width in the tech file), dividing by it will result in a division-by-zero error. It is safer to guard against this by checking if layer_width is greater than zero.

Suggested change
// Keep layer_width as float: other rounding perturbs getWireCost() results
const float layer_width = dbuToMicrons(db_layer->getWidth());
layer_res_per_micron_[layer] = db_layer->getResistance() / layer_width;
// Keep layer_width as float: other rounding perturbs getWireCost() results
const float layer_width = dbuToMicrons(db_layer->getWidth());
layer_res_per_micron_[layer] = layer_width > 0.0f ? db_layer->getResistance() / layer_width : 0.0f;

Comment on lines 2815 to 2818
double FastRouteCore::dbuToMicrons(const int dbu)
{
return db_->getChip()->getBlock()->dbuToMicrons(dbu);
return dbu / dbu_per_micron_;
}

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

If dbu_per_micron_ is 0.0 (e.g., if dbuToMicrons is called before preProcessTechLayers initializes it, or if the database tech units are uninitialized), this will result in a division-by-zero error. Falling back to the original database-level implementation when dbu_per_micron_ is 0.0 provides a safe and robust fallback.

double FastRouteCore::dbuToMicrons(const int dbu)
{
  if (dbu_per_micron_ == 0.0) {
    return db_->getChip()->getBlock()->dbuToMicrons(dbu);
  }
  return dbu / dbu_per_micron_;
}

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant