Skip to content

gpl: hoist loop-invariant accessors in getDensityGradient (bit-identical) - #10863

Merged
maliberty merged 1 commit into
The-OpenROAD-Project:masterfrom
Fermions-ASI:feat/gpl-perf
Jul 11, 2026
Merged

gpl: hoist loop-invariant accessors in getDensityGradient (bit-identical)#10863
maliberty merged 1 commit into
The-OpenROAD-Project:masterfrom
Fermions-ASI:feat/gpl-perf

Conversation

@saurav-fermions

Copy link
Copy Markdown
Contributor

Summary

Hoist loop-invariant accessors out of the getDensityGradient inner loop in global placement. Placed DEF is bit-identical (MD5 unchanged).

Split out of #10849 as its own PR per review feedback (@gudeh) — that PR now contains only the detailed-placement (src/dpl) changes.

Testing

Built openroad; gpl regression suite passes, placed DEF bit-identical to baseline.

Notes

  • Pure constant-factor optimization; no placement behavior change. No src/sta change.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@saurav-fermions

Copy link
Copy Markdown
Contributor Author

/gemini review

@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 the NesterovBase::getDensityGradient function by hoisting loop-invariant values out of the inner loops to improve performance. The reviewer suggests using a const reference to the vector instead of calling .data() to avoid potential dangling pointer issues if the return type of getBinsConst() changes in the future.

Comment thread src/gpl/src/nesterovBase.cpp Outdated
Comment on lines +2867 to +2873
const Bin* bins = bg_.getBinsConst().data();
const float scale = gCell->getDensityScale();

for (int i = pairX.first; i < pairX.second; i++) {
for (int j = pairY.first; j < pairY.second; j++) {
const Bin& bin = bg_.getBinsConst()[j * getBinCntX() + i];
float overlapArea
= getOverlapDensityArea(bin, gCell) * gCell->getDensityScale();
const Bin& bin = bins[j * binCntX + i];
float overlapArea = getOverlapDensityArea(bin, gCell) * scale;

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

Using .data() on the result of bg_.getBinsConst() can be brittle. If getBinsConst() were to be changed to return by value in the future, this would create a dangling pointer.

A more robust approach is to hold a const reference to the vector. This makes the code safer against future refactoring of getBinsConst() and is just as performant.

  const auto& bins = bg_.getBinsConst();
  const float scale = gCell->getDensityScale();

  for (int i = pairX.first; i < pairX.second; i++) {
    for (int j = pairY.first; j < pairY.second; j++) {
      const Bin& bin = bins[j * binCntX + i];
      float overlapArea = getOverlapDensityArea(bin, gCell) * scale;

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

I triggered a secure-CI with our designs to make sure this is no-op. I wonder if this would lead to any runtime improvements at all, I would guess not.

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

FloatPoint electroForce;

// Hoist loop-invariant values out of the inner loop. These do not change

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.

Unnecessary comment

Comment thread src/gpl/src/nesterovBase.cpp Outdated
// inside the loop, so re-fetching them every iteration is pure overhead.
// Arithmetic-neutral: identical loop nesting, identical operands, identical
// accumulation order -> bit-identical result.
const int binCntX = getBinCntX();

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.

Snake case for variables. I know gpl code has a lot to be changed, but we should use Google C++ style.

NesterovBase::getDensityGradient re-fetched three loop-invariant values on
every inner bin iteration: getBinCntX() (two non-inlined .cpp calls),
bg_.getBinsConst(), and gCell->getDensityScale(). Hoist them to locals before
the loop and index a raw const Bin* base pointer.

Arithmetic-neutral: identical loop nesting, operands, and accumulation order,
so placement output is bit-identical. Verified the three values are not mutated
inside the loop (binCntX_ member, bins_ not realloced, densityScale_ on the
const gCell param).

medium03 global_placement (DEF read excluded), 3 runs each on a shared
36-core host, -j8 Release:
  before median 199910 ms, after median 185648 ms (~7.1%, within run noise).
QoR bit-identical: iter 486, overflow 0.0994, HPWL 1.162648e+06 unchanged.
gpl ctest suite 65/65 green (log-compare enforces identical output).




Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
@saurav-fermions

Copy link
Copy Markdown
Contributor Author

Thanks @gudeh — addressed:

  • Unnecessary comment: removed.
  • Snake case: binCntXbin_cnt_x (the other two locals were already lower-case).
  • Also took the gemini point on .data() being brittle — now holds a const auto& reference to getBinsConst() and indexes that, instead of caching a raw pointer.

gpl regression suite passes (69/69), placed DEF bit-identical.

On the runtime question: you're right to be skeptical — this is a micro-optimization (hoisting getBinCntX()/getDensityScale()/the bins accessor out of the inner loop over bins). It's meaningful only on high-bin-count designs where getDensityGradient is hot; on typical designs the win is small. It's purely a constant-factor cleanup with no QoR change, so if your secure-CI confirms it's a no-op on runtime for your designs, I'm fine if you'd rather not take it — no objection to closing.

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

all the same at secure-CI, I am fine with merging this.

@gudeh

gudeh commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Are you an AI? Which model are you?

@saurav-fermions

Copy link
Copy Markdown
Contributor Author

Thanks for running the secure-CI and for the approval!

And a fair question — happy to be transparent. Yes, these are AI-assisted contributions. I'm the CTO of fermions.co (background: AI engineer working in the semiconductor domain), and we're building an agent called Saige that we're using to help produce these patches. Every contribution is reviewed, built, and tested by me before it's submitted, and I'm the accountable maintainer standing behind each PR — so if anything needs iteration or revert, that's on me.

Appreciate the careful reviews; they've been genuinely useful in tightening these up.

@maliberty
maliberty merged commit e006eee into The-OpenROAD-Project:master Jul 11, 2026
15 of 16 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.

3 participants