Skip to content

grt: Implement timing-driven net sorting for incremental CUGR#9828

Open
Divinesoumyadip wants to merge 3 commits intoThe-OpenROAD-Project:masterfrom
Divinesoumyadip:grt-cugr-timing-sort
Open

grt: Implement timing-driven net sorting for incremental CUGR#9828
Divinesoumyadip wants to merge 3 commits intoThe-OpenROAD-Project:masterfrom
Divinesoumyadip:grt-cugr-timing-sort

Conversation

@Divinesoumyadip
Copy link
Contributor

This PR prioritizes timing-critical nets during the incremental rerouting process. By querying fresh slack data from OpenSTA before rerouting, the tool ensures that nets with the worst negative slack (WNS) get the first choice of routing resources.

In the previous incremental flow, nets were rerouted in an arbitrary order. This often led to non-critical nets occupying the most direct tracks, forcing critical timing paths into long detours. This PR ensures that "VIP" nets (those with negative slack) are handled first to protect chip performance during ECO passes.

I modified CUGR::rerouteNets to refresh timing data before routing.Integrated a loop to querysta_(OpenSTA) for each net's current slack.Utilizes sortNetIndices to re-order the reroute queue so that nets with the most negative slack are at the front.

Reduces timing degradation during ECO passes and improves the overall Timing Quality of Results (QoR) by prioritizing paths that define the chip's maximum clock frequency.

This PR ensures that critical paths are prioritized during incremental routing by querying slacks from OpenSTA before sorting the reroute queue. This significantly improves timing QoR during ECO passes.

Signed-off-by: Divinesoumyadip <soumyacode7@gmail.com>
Copy link
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 timing-driven net sorting for incremental routing in CUGR. The changes in rerouteNets correctly query slack data from OpenSTA and prioritize critical nets. A new helper function, removeRouteUsage, is also added for ripping up individual nets. The implementation is sound and aligns with the goal of improving timing QoR during ECOs. I have one suggestion to merge two loops in rerouteNets for better performance, aligning with principles of optimizing loop structures.

Comment on lines 682 to +697
for (const int idx : net_indices) {
if (gr_nets_[idx]->getRoutingTree()) {
grid_graph_->removeTreeUsage(gr_nets_[idx]->getRoutingTree());
}
}

// 2. Query STA for fresh slacks if timing is available
if (sta_ != nullptr) {
for (const int idx : net_indices) {
odb::dbNet* db_net = gr_nets_[idx]->getDbNet();
float slack = getNetSlack(db_net);
gr_nets_[idx]->setSlack(slack);
}
// 3. Sort: Most negative slack (critical) nets go FIRST
sortNetIndices(net_indices);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For better performance, the loop for ripping up nets and the loop for querying slacks can be merged into a single loop. This avoids iterating over net_indices twice, which can be a significant saving if the number of nets to reroute is large. This aligns with the principle of optimizing loop structures to reduce redundant iterations, similar to how a single-pass approach can be more efficient than a two-pass approach.

  for (const int idx : net_indices) {
    GRNet* gr_net = gr_nets_[idx];
    if (gr_net->getRoutingTree()) {
      grid_graph_->removeTreeUsage(gr_net->getRoutingTree());
    }

    if (sta_ != nullptr) {
      odb::dbNet* db_net = gr_net->getDbNet();
      float slack = getNetSlack(db_net);
      gr_net->setSlack(slack);
    }
  }

  // 3. Sort if timing is available
  if (sta_ != nullptr) {
    // Sort: Most negative slack (critical) nets go FIRST
    sortNetIndices(net_indices);
  }
References
  1. When analyzing code within a loop, consider the entire loop structure. Operations at the beginning of the loop can affect the logic within the loop body, potentially making similar calls inside the loop redundant. Also, a single-pass method can be more efficient than a two-pass approach by avoiding processing all items multiple times.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

updated_nets_.insert(db_net);
}

void CUGR::removeRouteUsage(odb::dbNet* db_net)
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: out-of-line definition of 'removeRouteUsage' does not match any declaration in 'grt::CUGR' [clang-diagnostic-error]

void CUGR::removeRouteUsage(odb::dbNet* db_net)
           ^

@eder-matheus eder-matheus self-requested a review March 19, 2026 13:16
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

for (const int idx : net_indices) {
if (gr_nets_[idx]->getRoutingTree()) {
grid_graph_->removeTreeUsage(gr_nets_[idx]->getRoutingTree());
GRNet* gr_net = gr_nets_[idx];
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no viable conversion from 'value_type' (aka 'std::unique_ptrgrt::GRNet') to 'GRNet *' [clang-diagnostic-error]

    GRNet* gr_net = gr_nets_[idx];
           ^

Signed-off-by: Divinesoumyadip <soumyacode7@gmail.com>
Copy link
Member

@eder-matheus eder-matheus left a comment

Choose a reason for hiding this comment

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

The idea of the PR is good, but if you look at the patternRoute, patternRouteWithDetours and mazeRoute functions, you'll see that they already call the sortNetIndices internally. So the new process introduced in this PR is redundant.

updated_nets_.insert(db_net);
}

void CUGR::removeRouteUsage(odb::dbNet* db_net)
Copy link
Member

Choose a reason for hiding this comment

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

Where's this function used? I believe the first lines of the rerouteNets function already covers this process.

grid_graph_->removeTreeUsage(gr_net->getRoutingTree());
}

if (sta_ != nullptr) {
Copy link
Member

Choose a reason for hiding this comment

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

You don't need this sta_ check (here and below).

}
}

// 3. Sort: Most negative slack (critical) nets go FIRST
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems a bit out of place - where are steps 1. and 2.? Please remove it (and the comment below), the functions are self documented.

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