Skip to content

rsz: Add the experimental PARALLEL_EVAL setup repair policy - #11799

Merged
maliberty merged 3 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:secure-rsz-parallel-eval
Oct 18, 2026
Merged

maliberty merged 3 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:secure-rsz-parallel-eval

Conversation

@jhkim-pii

@jhkim-pii jhkim-pii commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Part 6 of 12 of the PARALLEL_EVAL setup repair stack. It builds on #11798 and also shows the commits of parts 1 to 5; its own change is the last commit.

Summary

  • Add PARALLEL_EVAL, an experimental setup repair policy that commits a batch of moves per timing update instead of one move per pass. It is the first policy that runs the Mt moves: VtSwapMt, SizeUpMt and RebufferMt here, the other Mt moves in the next PRs.

Changes

  • Worker threads scan the violating endpoints and generate and score candidates from data the main thread prepared; only the main thread reads live STA and edits the netlist.
  • BatchSelector picks a conflict-free batch by score and reserves room for the worst endpoints when WNS stalls; BottleneckAnalysis gives the drivers that many failing endpoints share a higher weight.
  • One ECO journal and one RC and STA update per batch. A batch that improves WNS, or TNS within a 1% WNS band, is saved; a missed batch reverts its culprit swaps in place or rolls back. Under -path_group the check reads the group's WNS and TNS.
  • ParallelEvalState holds the work meter, which counts work instead of wall time, the stall monitor, the WNS tail of small batches on the worst endpoints, and the miss tabu.
  • -effort low|medium|high sets the stop rules, -max_iterations counts batches, and a batch that would leave the design above -max_utilization is undone.
  • RebufferMt plans trees on the workers with planners owned by RebufferMtGenerator; their warnings are counted and reported once (RSZ-2034).
  • Optimizer::run() calls OptimizationPolicy::finish() at the end of each phase, so PARALLEL_EVAL releases its threads before the next phase, and prints the final report itself after the last phase (reportRunResult()), so each policy ends with its phase.
flowchart TD
  A["scan the violating endpoints<br/>(worker threads)"] --> B["collect targets in chunks,<br/>worst slack first"]
  B --> C["prepare the STA reads<br/>(main thread)"]
  C --> D["generate and score candidates<br/>(worker threads)"]
  D --> E["select a conflict-free batch<br/>by score"]
  E --> F["commit the batch in one journal,<br/>then one RC and STA update"]
  F --> G{"WNS or TNS better<br/>than the checkpoint?"}
  G -- yes --> H["save the checkpoint"]
  G -- no --> I["revert the culprits,<br/>else roll back"]
  H --> J{"stalled?"}
  I --> J
  J -- no --> A
  J -- yes --> K["WNS tail: small batches<br/>on the worst endpoints"]
Loading

Behavior

  • New experimental policy, selected with the PARALLEL_EVAL token of -phases; LEGACY results stay the same.
  • A run makes the same decisions on every machine and for any thread count.

Stack

  1. test: Add LEGACY repair setup path regressions #11794 test: Add LEGACY repair setup path regressions
  2. rsz: Remove MT1, MEASURED_VT_SWAP, LEGACY_MT and the RSZ_* knobs #11795 rsz: Remove MT1, MEASURED_VT_SWAP, LEGACY_MT and the RSZ_* knobs
  3. rsz: Add the setup repair profiler #11796 rsz: Add the setup repair profiler
  4. rsz: Model side paths in the Mt delay estimator #11797 rsz: Model side paths in the Mt delay estimator
  5. rsz: Add the RebufferMt buffer-tree move #11798 rsz: Add the RebufferMt buffer-tree move
  6. rsz: Add the experimental PARALLEL_EVAL setup repair policy #11799 rsz: Add the experimental PARALLEL_EVAL setup repair policy (this PR)
  7. rsz: Add SplitLoadMt to PARALLEL_EVAL #11800 rsz: Add SplitLoadMt to PARALLEL_EVAL
  8. rsz: Add SwapPinsMt to the PARALLEL_EVAL WNS tail #11801 rsz: Add SwapPinsMt to the PARALLEL_EVAL WNS tail
  9. rsz: Add UnbufferMt to the PARALLEL_EVAL WNS tail #11802 rsz: Add UnbufferMt to the PARALLEL_EVAL WNS tail
  10. rsz: Add SizeDownFanoutMt to the PARALLEL_EVAL WNS tail #11803 rsz: Add SizeDownFanoutMt to the PARALLEL_EVAL WNS tail
  11. rsz: Add the per-move analysis and the rebuffer accuracy report #11804 rsz: Add the per-move analysis and the rebuffer accuracy report
  12. doc: Update the rsz setup repair architecture #11805 doc: Update the rsz setup repair architecture

@jhkim-pii jhkim-pii self-assigned this Oct 17, 2026
@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 the experimental PARALLEL_EVAL setup repair policy, which optimizes setup timing in parallel batches. To support this, several new components are added, including SetupParallelEvalPolicy, BatchSelector, BottleneckAnalysis, SequentialTimingEstimator, and RepairSetupProfiler, while older experimental policies like MeasuredVtSwapPolicy and SetupMt1Policy are removed. Additionally, DelayEstimator and Rebuffer are refactored to support multi-threaded planning, caching, and side-load timing estimation. The code review feedback highlights several critical safety issues across these new files, primarily concerning potential null pointer dereferences (such as missing null checks on stage.arc.scene, target_arc.inputPort(), plan.targetPath(), plan.loadPath(), edge->role(), and inst pointers) and a potential crash in RebufferPlannerPool if the idle pool is empty during acquisition.

Comment thread src/rsz/src/DelayEstimator.cc
Comment thread src/rsz/src/DelayEstimator.cc
Comment thread src/rsz/src/DelayEstimatorBufferTree.cc
Comment thread src/rsz/src/DelayEstimatorBufferTree.cc
Comment thread src/rsz/src/SequentialTimingEstimator.cc
Comment thread src/rsz/src/policy/SetupParallelEvalPolicy.cc
Comment thread src/rsz/src/policy/SetupParallelEvalPolicy.cc
Comment thread src/rsz/src/policy/BottleneckAnalysis.cc
Comment thread src/rsz/src/move/RebufferPlannerPool.cc
@jhkim-pii

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-17T05:50:39.752224Z 131e67e Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Failed to sample tokens
ℹ️ 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".

What: the Mt delay estimator models the fanin side loads, the opposite
output transition, the latch D-side driver and the flip-flop setup and
hold change of a cell swap, and SizeUpMt and VtSwapMt charge them.

Why: scoring a swap on the selected path alone let a scored gain turn
into a loss after the timing update.

How: side models in DelayEstimator and SequentialTimingEstimator, input
cap budgets that workers can check without STA, and ArcDelayState
renamed to EstimatorContext. The side models are off by default.

Setup repair profiler review follow-ups: the profiler constructor takes
a RepairSetupProfiler::Mode instead of an int, CRIT_VT_SWAP samples WNS
and TNS before its sweep, and the Bazel TestResizerMt target drops the
--gtest_filter that skipped the profiler and fixture tests.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
What: RebufferMt, an Mt buffering move that plans a beam of Rebuffer
trees per driver and scores each with the buffer-tree estimator.

Why: buffering needs the same scored, comparable candidates as the cell
swaps before a batch policy can choose among them.

How: makeRebufferTreePlans() and applyRebufferTreePlan() in Rebuffer,
estimateBufferTreeWithSidePaths() in DelayEstimator, and current
required times after the endpoint scan. No policy runs RebufferMt yet;
PARALLEL_EVAL will. LEGACY is unchanged.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
What: PARALLEL_EVAL, an experimental setup repair policy that commits a
batch of VtSwapMt, SizeUpMt and RebufferMt moves per timing update.

Why: one timing update per batch instead of per move cuts the repair
time.

How: worker threads scan endpoints and generate and score candidates
from prepared data; BatchSelector, BottleneckAnalysis and
ParallelEvalState pick, rank and stop; each batch is kept, salvaged or
rolled back by its WNS and TNS (the group's under -path_group).
OptimizationPolicy::finish() ends each phase, and the Optimizer prints
the final report after the last phase. LEGACY results do not change.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
@openroad-ci
openroad-ci force-pushed the secure-rsz-parallel-eval branch from 131e67e to 32b4e4d Compare October 17, 2026 07:10
@maliberty

Copy link
Copy Markdown
Member

Claude

== Priority 1 (correctness) ==

  • test/repair_setup_parallel_eval_default_sequence.ok:39-46 bug: the batch keep rule
    cycles. Iterations 22-26 flip between two states (WNS -8.667/TNS -13.7 and
    WNS -8.712/TNS -12.5), and every row is saved ('*'). "Better WNS, OR better TNS
    within a 1% WNS band" is not a strict order, so two states can each beat the
    other. The run also ends on the worse-TNS state, which is worse than iteration 16
    (TNS -11.0) and worse than -effort low. Iterations 16-18 are identical no-ops.
    Please add hysteresis or a strict order, and/or keep the best checkpoint at exit.
  • policy/SetupParallelEvalPolicy.cc:344-355, 1662 bug?: finishAtMaxArea() calls
    markRunComplete(false) without closing an open speculative journal, and finish()
    never checks batch_journal_open_. Speculation is kept based on
    withinMaxUtilization() (computeDesignArea, recomputed), while the stop check uses
    overMaxArea() (design_area_, updated incrementally). At the limit these can
    disagree, leaving the journal open into the next phase. The logic_error throws in
    revertInPlace (~1411, 1421) also leave the journal open with part of the batch
    reverted. Suggest that finish() restore or commit any open journal.
  • policy/SetupParallelEvalPolicy.cc:1447-1455 + ParallelEvalState.cc:318-331 bug:
    recordUndo()/addTabu() store Instance* for batch_instances_ right after
    rollBackJournal(). In the WNS tail these can include buffers that the rolled-back
    speculative RebufferMt inserted, so they are already deleted. dbTable reuses
    slots, so a later buffer at the same address starts out tabu'd, or permanently
    excluded (excluded_ is cleared only in reset()). It is deterministic but loses
    QoR silently. Key by something stable, or drop instances the rollback destroys.
  • policy/BatchSelector.cc:104-111, 250-257 question: dependsOn() is only checked one
    way (candidate depends on a selected member's effect). All estimates come from the
    same pre-batch snapshot. If a higher-score member A read instance J and a later
    candidate B changes J, B is admitted and A's estimate is stale. Why is one
    direction enough?
  • policy/SetupParallelEvalPolicy.cc:1350-1353 nit: the comment says a restore is not
    a timing update, but MoveCommitter::restoreJournal runs
    updateParasiticsAndTiming() itself (MoveCommitter.cc:547). That update is not
    charged to the WorkMeter, which skews the stall and tail budgets.
  • RepairTargetCollector.cc:916-929 question: findRequireds() no longer runs under
    -path_group. Today it is still correct only because the main thread calls
    slack()/worstSlack before the workers read required() in annotateLoadSlacks.
    That is fragile. Restore the call or document the dependency.
  • move/RebufferPlannerPool.cc:56-57 suggestion: acquire() pops from idle_ without
    checking that it is non-empty. That is safe today, but nested pool work inside
    planning would make it UB. Add an assert or error.
  • policy/SetupParallelEvalPolicy.hh:299-301 nit: batch_candidates_/batch_swaps_ point
    into a BatchPool that is local to iterate(). Clear them when iterate() returns.

}
}

constexpr size_t kBitsPerWord = 64;

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.

This should be a sizeof for the relevant type (uint64_t I think).

return id < node_of_.size() ? node_of_[id] : -1;
}

std::vector<size_t> BottleneckAnalysis::collectCone(

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.

After discussing w/Codex:

There is a narrower caveat: the cone’s filter does not fully match OpenSTA’s traversal rules. OpenSTA also excludes some edges, such as disabled bidirectional instance paths and, by default, preset/clear arcs, when assigning vertex levels. collectCone can include those edges, so its assumption that every included fanin has a lower level is not guaranteed in those cases. That could distort the bottleneck weights; it does not negate the handling of edges explicitly marked as broken loop edges. Levelize.cc (src/sta/search/Levelize.cc:188)

Comment on lines +119 to +120
// Failing endpoints at the last collection and the last saved checkpoints.
size_t fep_{0};

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.

Avoid cryptic names (fep_).

Comment on lines +19 to +22
// Strength of the cone-need bonus.
float alpha{2.0f};
// Emphasis on the most shared bottlenecks.
float gamma{2.0f};

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.

More meaningful names than alpha/gamma

Comment on lines +167 to +171
float work_sta_per_vertex{5.0e-7f};
float work_per_pending_net{1.93e-3f};
float work_per_estimate{1.35e-5f};
float work_per_plan{1.14e-3f};
float work_per_endpoint{5.65e-4f};

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.

Where do these values come from?

@maliberty
maliberty merged commit 7fc8d2e into The-OpenROAD-Project:master Oct 18, 2026
20 checks passed
@maliberty
maliberty deleted the secure-rsz-parallel-eval branch October 18, 2026 01:11
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