Skip to content

gpl: inflate retained timing-repair cells after routability - #11899

Merged
maliberty merged 11 commits into
The-OpenROAD-Project:masterfrom
naveenvenk17:nv-gpl-congestion-inflation-8402
Oct 24, 2026
Merged

maliberty merged 11 commits into
The-OpenROAD-Project:masterfrom
naveenvenk17:nv-gpl-congestion-inflation-8402

Conversation

@naveenvenk17

@naveenvenk17 naveenvenk17 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Retained timing repairs can add cells after ordinary routability refinement has finished. This refreshes RUDY and inflates those surviving new cells without restarting the routability search. Virtual timing iterations and passes where routability refinement is still active do not take this path.

Following @gudeh's review, this now runs by default when timing-driven and routability-driven placement are enabled. I removed the Tcl switch and its C++ option plumbing. Late inflation uses the existing allowance and whole-filler budget; it does not raise target density.

I also merged master, updated the fixtures for the current GPL APIs and fixed the integration test to save the placer-owned routability snapshot before testing restoration. The TileGrid reset fix is separate and has merged as #11917.

After that merge, I moved this PR's test declaration to avoid a BUILD insertion-point conflict. Every target attribute and C++ source/test file is unchanged. All 49 focused cases, the default-behavior Tcl test and BUILD format/lint checks passed again after the move.

Testing on the merged head, on a Linux GCP VM with test-result caching disabled:

  • All 139 selected CPU GPL, affected resizer and repository checks passed, including the 11 large GPL targets. Four GPU-only targets were excluded.
  • All 49 focused C++ cases passed in six fresh runs, plus 200 shuffled TileGrid executions.
  • AddressSanitizer passed 347 case executions. Leak detection was disabled, per the repository configuration.
  • Four fresh Nangate45 GCD/AES flows compared the old switch enabled against the new default, using the same inputs and seed through legalization, CTS and global routing. All saved result files, instance tables and checked non-runtime measurements matched. Repeated metric keys are compared as complete ordered value sequences, not overwritten.
  • Both AES runs exercised late inflation after routability completion: a logged 0.854 um^2, funded by a logged 1.382 um^2 of filler removal, with zero remaining compensation and no density change. GCD had no positive inflation and is a compatibility case.
  • The threaded invariance check still has the same single hardware INFO-line mismatch on both versions. Both produce the same DEF, matching the unchanged upstream golden. This is not counted as a passing test.

The earlier baseline/OFF/ON experiment had mixed tradeoffs: AES TNS and wirelength improved, while WNS, area, buffer count and estimated power worsened. The new matched runs establish equivalence between the old enabled behavior and the new default, not a general QoR improvement. No golden or metric limit was changed. No GPU, detailed-route, signoff-power or speedup claim is made.

Related to #8402.

Carry forward the reviewed changes from The-OpenROAD-Project#11853 under the correct contributor account.
The source tree matches 5e30ad2.

Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
@naveenvenk17
naveenvenk17 requested a review from a team as a code owner October 21, 2026 14:15
@naveenvenk17
naveenvenk17 requested a review from gudeh October 21, 2026 14:15
@github-actions

Copy link
Copy Markdown
Contributor

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@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 an experimental, opt-in -timing_driven_congestion_inflation option to global_placement. When enabled alongside timing-driven and routability-driven modes, it refreshes RUDY after timing repairs and inflates newly inserted standard cells without restarting the routability search. Feedback on the implementation identifies a potential segmentation fault in GCell::inflationArea() where insts_.front() is accessed without checking if insts_ is empty, and suggests adding a defensive check.

Comment thread src/gpl/src/nesterovBase.cpp Outdated
Comment on lines +189 to +204
int64_t GCell::inflationArea() const
{
if (isFiller()) {
return 0;
}
// Instance geometry carries current master dimensions, placement padding
// and pin-density extension. A move callback can make the GCell unpadded;
// it must not change this reference or turn padding into congestion area.
int64_t physical_area = insts_.front()->getArea();
if (insts_.size() > 1) {
const GCell physical(insts_);
physical_area = static_cast<int64_t>(physical.dx()) * physical.dy();
}
return std::max<int64_t>(0,
static_cast<int64_t>(dx()) * dy() - physical_area);
}

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

In GCell::inflationArea(), calling insts_.front() without verifying if insts_ is empty can lead to undefined behavior or a segmentation fault if the GCell has no associated instances. Adding a defensive check for insts_.empty() ensures robustness.

int64_t GCell::inflationArea() const
{
  if (isFiller()) {
    return 0;
  }
  if (insts_.empty()) {
    return 0;
  }
  // Instance geometry carries current master dimensions, placement padding
  // and pin-density extension. A move callback can make the GCell unpadded;
  // it must not change this reference or turn padding into congestion area.
  int64_t physical_area = insts_.front()->getArea();
  if (insts_.size() > 1) {
    const GCell physical(insts_);
    physical_area = static_cast<int64_t>(physical.dx()) * physical.dy();
  }
  return std::max<int64_t>(0,
                           static_cast<int64_t>(dx()) * dy() - physical_area);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

isFiller() is defined as insts_.empty(), so the existing early return already guards front().

Regenerated against the current upstream merge and checked for idempotence on the GCP VM. Only the missing Bison registry checksum is added; no dependency versions change.

Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
@naveenvenk17
naveenvenk17 requested review from a team as code owners October 21, 2026 14:49
Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
@naveenvenk17

Copy link
Copy Markdown
Contributor Author

GCell::isFiller() is exactly insts_.empty(), so the existing return already covers the empty-vector case before front() is reached. I left that check as-is.

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

To approve this PR we need QoR experiments, I should try to run a secure-CI to asses the impact of this.

Comment thread src/gpl/src/nesterovBase.cpp Resolved
Comment thread src/gpl/README.md Outdated
value is calculated based on the weight coefficients. The algorithm will stop
if the RC is not decreasing for three consecutive iterations.

The optional `-timing_driven_congestion_inflation` experiment is disabled by

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 description is way more complex than necessary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Shortened this to the option's behavior, its prerequisites and the filler-budget limit.

Comment thread src/gpl/src/routeBase.h Resolved
Comment thread src/gpl/src/nesterovPlace.cpp Outdated
= tb_->executeTimingDriven(virtual_td_iter, enable_repair_timing);
// fixPointers() may have moved the GPins the IO pins point at.
getTopLevelNB()->refreshIoPins();
const bool retained_inflation

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.

We shouldn't do this on TD iterations that happen before routability mode. I am not entirely sure only !is_routability_need_ guarantees that, could be reviewed to make sure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I checked the state transitions and added regressions for early timing passes, active routability passes, completion and re-entry. The new path requires a retained repair, the opt-in flag, routability mode and !is_routability_need_. That state starts true; only runRoutability() changes it, and any final restore completes before the next timing-repair iteration. The early and active cases leave new cells uninflated.

Comment thread src/gpl/src/nesterovBase.h Outdated

const std::vector<GCellHandle>& getGCells() const { return nb_gcells_; }

// Pending callback creations, consumed by updateGCellState(). Resolve these

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.

Pending callback creations? Does this ever happen? If so, we may have a bug.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The callbacks are synchronous and have already created the GCells. new_instances_ tracks those creations until the optimizer-state update; it does not represent callbacks waiting to run. I removed the misleading wording and added tests for deduplication, reindexing, deletion and consuming each creation once.

Comment thread src/gpl/src/routeBase.cpp
debugInflatedTiles();
}

int64_t RouteBase::inflateNewCells()

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.

Why are inflations being handled here different from the default ones? Can't we have a single function to be used both here (for new instances), and at the original routability inflations?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Both paths now call inflateCell(). Ordinary routability keeps its existing float arithmetic and rounding; late insertions pass an area limit so the result fits the live allowance and available whole fillers. I reran the GCD/AES default-off comparison against upstream plus the separate TileGrid fix in #11917. All 15 saved result files and all checked non-runtime metrics match on both designs.

@naveenvenk17

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I'll rename the getter, shorten the README text, and remove the extra comment. I'm also tracing the TD/routability transition and the callback updates, then refactoring the shared inflation logic so the two paths use the same geometry calculation.

I'll post refreshed VM QoR runs after that update. The existing GCD/AES results are mixed, which is why the option is still off by default. A broader secure-CI run would be useful before approval.

Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
Preserve ordinary float rounding and bounded late filler funding. Document the completed-routability latch and synchronous callback staging, and cover real retained repairs across phase gates and shared geometry rounding boundaries.

Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
@naveenvenk17

Copy link
Copy Markdown
Contributor Author

Updated this in 6de507e4 with the inline review changes and fresh QoR runs.

I ran baseline, OFF and ON for Nangate45 GCD and AES through legalization, CTS and global routing. The baseline is b4f10aa87d82 plus only the separate TileGrid fix in #11917; using unmodified upstream would hide a real change in the reported congestion metric. OFF matches every checked non-runtime metric and all 15 saved result files for each design.

AES exercised the new path. TNS and wirelength improved, but WNS, area and estimated power got slightly worse. GCD added no inflation. I've put the actual numbers and test scope in the description, and kept this opt-in.

All 47 focused cases passed under ASan, with leak detection disabled. The focused regressions and flow evidence also received independent agent review. Larger secure-CI runs would still be useful before judging whether this is worth keeping.

@vvbandeira vvbandeira left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

approved from devops team side

Comment thread src/gpl/doc/TclCommands.md Outdated
global_placement
[-skip_initial_place]
[-incremental]
[-timing_driven_congestion_inflation]

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.

Lets make this default behavior and remove the TCL parameter.

@naveenvenk17 naveenvenk17 Oct 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. The switch and C++ option are gone, and the late-inflation path is now the default for timing-driven, routability-driven placement.

I merged master and updated the snapshot/API fixtures too. The merged head passed 139 selected checks, 494 normal native case executions and 347 ASan executions. Fresh GCD/AES runs matched the old switch-enabled behavior through global routing, including the AES late-inflation event. The hardware INFO-line mismatch in mt_invariance01 is unchanged on both versions; the DEFs match the upstream golden.

I also resolved the BUILD conflict with the merged #11917 by moving the test declaration. No target attributes or C++ sources changed. The focused suite and default-behavior Tcl check passed again.

@gudeh

gudeh commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Only reductions in congestion at GPL on private designs.
image

small improvement on finish wns
image

Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>
@naveenvenk17 naveenvenk17 changed the title gpl: add opt-in inflation for post-routability timing insertions gpl: inflate retained timing-repair cells after routability Oct 23, 2026
Signed-off-by: Naveen Venkat <81929600+naveenvenk17@users.noreply.github.com>

@maliberty maliberty left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

approve for openroad-maintainers

@maliberty
maliberty requested review from gudeh and removed request for sombraSoft October 24, 2026 14:50
@gudeh

gudeh commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

I think we should merge this @maliberty. We seem to have improvements in congestion and and really small (chance level) slack improvement. Other metrics look stable.

I triggered a secure-CI yesterday for large designs, I will check today if all is ok to merge.

@maliberty

Copy link
Copy Markdown
Member

@gudeh approve and merge when ready
image

@maliberty
maliberty enabled auto-merge October 24, 2026 14:57
@maliberty
maliberty merged commit 5c30883 into The-OpenROAD-Project:master Oct 24, 2026
20 checks passed
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.

4 participants