grt: cache per-layer wire resistance - #11622
rafaelmoresco wants to merge 1 commit into
Conversation
Signed-off-by: rafaelmoresco <rafaelmorescovieira@gmail.com>
There was a problem hiding this comment.
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.
| if (layer < net->getMinLayer() || layer > net->getMaxLayer()) { | ||
| return BIG_INT; | ||
| } |
There was a problem hiding this comment.
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.
| 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; | |
| } |
| // 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; | ||
| } |
There was a problem hiding this comment.
Several potential issues exist here:
getTechLayercould returnnullptr.ndr->getLayerRule(db_layer)can returnnullptrif the NDR does not define a rule for the given layer.layer_widthcould be0.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;
}
}
}
}| // 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; |
There was a problem hiding this comment.
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.
| // 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; |
| double FastRouteCore::dbuToMicrons(const int dbu) | ||
| { | ||
| return db_->getChip()->getBlock()->dbuToMicrons(dbu); | ||
| return dbu / dbu_per_micron_; | ||
| } |
There was a problem hiding this comment.
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_;
}
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
Impact
Reduce Res Aware runtime.
Verification
./etc/Build.sh).