Skip to content

pad: add custom comparator for GridGraphEdge set to prevent non-determinism#10632

Open
eder-matheus wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
eder-matheus:pad_non_determinism
Open

pad: add custom comparator for GridGraphEdge set to prevent non-determinism#10632
eder-matheus wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
eder-matheus:pad_non_determinism

Conversation

@eder-matheus

@eder-matheus eder-matheus commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

RDL routing was nondeterministic across builds, causing pad.rdl_route_failed.tcl
to fail intermittently in CI (only the merge pipeline) while passing locally and
being stable within any single binary.

The router ordered graph data by heap addresses in two places:

  • std::set<GridGraphEdge> — a boost adjacency_list edge descriptor's default
    operator< compares its internal edge-property pointer (a heap address).
  • std::set<RDLRoutePtr> (the ripup set) — std::shared_ptr compares by pointer
    value.

Both orders drive the sequence in which edges are removed and re-added to the
graph (commitRoute/uncommitRoute/access-point teardown). Boost A* walks a
vertex's incident edges in adjacency-list (insertion) order, so the heap layout
— which varies by build (compiler, allocator, LTO, CI node) — changed A*
equal-cost tie-breaks and therefore the final set of unroutable nets. Within one
binary ASLR shifts all addresses equally, preserving relative order, which is
why it was stable locally but flaky across CI builds.

The fix orders both by stable integer keys:

  • edges by their (source, target) vertex indices (GridGraphEdgeLess /
    GridGraphEdgeSet), and
  • ripup routes by their source terminal id (RDLRoutePtrLess).

It also drops a redundant in_edges traversal in getVertexEdges (for an
undirected graph out_edges already yields every incident edge).

Type of Change

  • Bug fix

Impact

This is a result-changing deterministic policy, not a no-op cleanup. It replaces
an arbitrary, build-dependent (heap-address) ordering with an arbitrary but
stable one, so routing converges on a single canonical result instead of a
layout-dependent one. As a consequence two congested-case goldens change
(rdl_route_failed: 17 -> 13 reported unroutable nets; rdl_route_max_iterations:
one fewer). The chosen ordering is deterministic but is not selected for routing
quality; the QoR shift is incidental. All geometry (defok) goldens are
unaffected.

Verification

  • I have verified that the local build succeeds (./etc/Build.sh).
  • I have run the relevant tests and they pass (full pad suite on gcc; both
    changed tests stable across repeated runs).
  • My code follows the repository's formatting guidelines.
  • I have included tests to prevent regressions.
  • I have signed my commits (DCO).

Related Issues

N/A

…minism

Signed-off-by: Eder Monteiro <emrmonteiro@precisioninno.com>

@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 deterministic edge ordering in RDLRouter by replacing std::set<GridGraphEdge> with a custom GridGraphEdgeSet that orders edges by their vertex indices rather than heap pointers. The review feedback suggests further improvements to ensure complete determinism and optimize performance: adding a custom comparator for std::set<RDLRoutePtr> to prevent non-deterministic pointer comparison, using std::minmax for a cleaner implementation of GridGraphEdgeLess, and eliminating the getVertexEdges helper to avoid the overhead of temporary container allocations by calling boost::out_edges directly.

Comment thread src/pad/src/RDLRouter.cpp

// Determine access points
std::unordered_map<odb::Point, std::set<GridGraphEdge>> remove_edges;
std::unordered_map<odb::Point, GridGraphEdgeSet> remove_edges;

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

While fixing the non-determinism of GridGraphEdge sets is a great step, there is another source of non-determinism in RDLRouter::route at line 652:

std::set<RDLRoutePtr> ripup;

Since RDLRoutePtr is a std::shared_ptr<RDLRoute>, std::set will default to comparing the memory addresses of the shared pointers. This makes the iteration order of ripup (and consequently the order in which uncommitRoute and addGraphEdge are called) dependent on the heap layout, which varies across builds and runs.

To ensure complete determinism, ripup should use a custom comparator that orders the routes deterministically, for example by their terminal ID:

struct RDLRoutePtrLess
{
  bool operator()(const RDLRoutePtr& lhs, const RDLRoutePtr& rhs) const
  {
    return lhs->getTerminal()->getId() < rhs->getTerminal()->getId();
  }
};
std::set<RDLRoutePtr, RDLRoutePtrLess> ripup;
References
  1. Iteration over containers with pointer keys is non-deterministic unless a custom comparator is defined for the pointer type to ensure a stable, deterministic order.

Comment thread src/pad/src/RDLRouter.h
Comment thread src/pad/src/RDLRouter.cpp
Signed-off-by: Eder Monteiro <emrmonteiro@precisioninno.com>
@eder-matheus

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@eder-matheus eder-matheus marked this pull request as ready for review June 11, 2026 03:09
@eder-matheus eder-matheus requested a review from a team as a code owner June 11, 2026 03:09
@eder-matheus eder-matheus requested a review from maliberty June 11, 2026 03:09

@gadfort gadfort 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.

LGTM

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.

2 participants