Skip to content

Commit 352c666

Browse files
committed
Merge branch 'master' of https://github.com/The-OpenROAD-Project/OpenROAD into grt_cugr_vias
2 parents 58b735b + ad9e724 commit 352c666

32 files changed

Lines changed: 983 additions & 265 deletions

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ bazel_dep(name = "eigen", version = "3.4.0.bcr.3")
7878
bazel_dep(name = "fmt", version = "11.2.0.bcr.1")
7979
bazel_dep(name = "git", version = "2.54.0")
8080
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
81-
bazel_dep(name = "openmp", version = "21.1.5.bcr.1")
81+
bazel_dep(name = "openmp", version = "21.1.5.bcr.2")
8282
bazel_dep(name = "or-tools", version = "9.15")
8383
bazel_dep(name = "spdlog", version = "1.15.1")
8484
bazel_dep(name = "sv-lang", version = "10.0.1-20260316-f04e8156")

MODULE.bazel.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bazel/tcl_encode_or.bzl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ def _tcl_encode_or_impl(ctx):
2323
outputs = [output_file],
2424
inputs = ctx.files.srcs,
2525
arguments = [args],
26-
tools = [ctx.executable._encode_script],
26+
tools = depset(
27+
direct = [ctx.executable._encode_script],
28+
transitive = [ctx.toolchains["@rules_python//python:toolchain_type"].py3_runtime.files] if ctx.toolchains["@rules_python//python:toolchain_type"].py3_runtime and ctx.toolchains["@rules_python//python:toolchain_type"].py3_runtime.files else [],
29+
),
2730
executable = ctx.toolchains["@rules_python//python:toolchain_type"].py3_runtime.interpreter,
2831
)
2932
return [DefaultInfo(files = depset([output_file]))]

etc/DependencyInstaller.sh

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,9 +883,35 @@ _install_bazel() {
883883
_execute "Installing bazelisk..." mv bazelisk "${bazel_prefix}/bin/bazelisk"
884884
)
885885
if _command_exists "apt-get"; then
886+
# Ubuntu 26.04 ships the libxml2 runtime with soname
887+
# libxml2.so.16, but the prebuilt LLVM toolchain (lld) pulled in
888+
# by the Bazel build is linked against the old libxml2.so.2.
889+
# Pull in libxml2-dev there (and add a compatibility symlink
890+
# below); older Ubuntu still provides .so.2 via libxml2.
891+
local ubuntu_version=""
892+
if [[ -f /etc/os-release ]]; then
893+
ubuntu_version=$(awk -F= '/^VERSION_ID/{print $2}' /etc/os-release | sed 's/"//g')
894+
fi
895+
local libxml2_pkg="libxml2"
896+
if [[ -n "${ubuntu_version}" ]] && _version_compare "${ubuntu_version}" -ge "26.04"; then
897+
libxml2_pkg="libxml2-dev"
898+
fi
886899
_execute "Installing bazel required libraries..." \
887900
apt-get -y install --no-install-recommends \
888-
libc6-dev libxml2 libtinfo6 zlib1g libstdc++6
901+
libc6-dev "${libxml2_pkg}" libtinfo6 zlib1g libstdc++6
902+
# lld only uses libxml2 for Windows COFF manifests, never during a
903+
# Linux link, so the .so.16 -> .so.2 compatibility symlink is safe.
904+
# Gated to 26.04+ only.
905+
if [[ -n "${ubuntu_version}" ]] && _version_compare "${ubuntu_version}" -ge "26.04"; then
906+
local libdir="/usr/lib/$(uname -m)-linux-gnu"
907+
local libxml2_so
908+
libxml2_so=$(ls "${libdir}"/libxml2.so.* 2>/dev/null \
909+
| grep -v 'libxml2.so.2$' | head -n1)
910+
if [[ ! -e "${libdir}/libxml2.so.2" && -n "${libxml2_so}" ]]; then
911+
_execute "Adding libxml2.so.2 compatibility symlink for prebuilt LLVM lld..." \
912+
ln -sf "$(basename "${libxml2_so}")" "${libdir}/libxml2.so.2"
913+
fi
914+
fi
889915
elif _command_exists "yum"; then
890916
_execute "Installing bazel required libraries..." \
891917
yum install -y \

src/dpl/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ detailed_placement
7373
[-report_file_name filename]
7474
[-use_negotiation]
7575
[-abacus]
76+
[-site_search_window sites]
77+
[-row_search_window rows]
78+
[-drc_penalty penalty]
7679
```
7780

7881
#### Options
@@ -86,6 +89,9 @@ detailed_placement
8689
| `-report_file_name` | File name for saving the report to (e.g. `report.json`.) |
8790
| `-use_negotiation` | Use the NegotiationLegalizer instead of the default diamond search engine. |
8891
| `-abacus` | Enable the Abacus pre-pass within the NegotiationLegalizer. Only effective when `-use_negotiation` is set. |
92+
| `-site_search_window` | NegotiationLegalizer: maximum number of sites a cell may be moved left or right of its initial position. Default `20`, `0` allowed (no horizontal movement). |
93+
| `-row_search_window` | NegotiationLegalizer: maximum number of rows a cell may be moved up or down from its initial position. Default `5`, `0` allowed (no row changes). |
94+
| `-drc_penalty` | NegotiationLegalizer: priority to DRC violations, ramped up each iteration to push DRC cleanup later in the run. Lower values tolerate DRC violations early on while overlaps are resolved. Default `5`, `0` allowed (disables the escalating per-candidate penalty, DRC-violating cells still accrue history cost separately). |
8995

9096
### Set Placement Padding
9197

src/dpl/include/dpl/Opendp.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,18 @@ class Opendp
105105

106106
// legalize/report
107107
// max_displacment is in sites. use zero for defaults.
108+
// site_search_window/row_search_window/drc_penalty use a negative value to
109+
// mean "unset" (use the negotiation legalizer's own default); 0 is a valid
110+
// explicit value for all three.
108111
void detailedPlacement(int max_displacement_x,
109112
int max_displacement_y,
110113
const std::string& report_file_name = std::string(""),
111114
bool incremental = false,
112115
bool use_negotiation = false,
113-
bool run_abacus = false);
116+
bool run_abacus = false,
117+
int site_search_window = -1,
118+
int row_search_window = -1,
119+
double drc_penalty = -1.0);
114120
void reportLegalizationStats() const;
115121

116122
void setPaddingGlobal(int left, int right);
@@ -120,6 +126,8 @@ class Opendp
120126
void setJumpMoves(int jump_moves);
121127
void setIterativePlacement(bool iterative);
122128
void setDeepIterativePlacement(bool deep_iterative);
129+
void setNegotiationDebugInterval(int iterative_jump);
130+
void setNegotiationDebugStart(int iterative_start);
123131

124132
// Global padding.
125133
int padGlobalLeft() const;
@@ -398,6 +406,8 @@ class Opendp
398406
int move_count_ = 1;
399407
bool iterative_debug_ = false;
400408
bool deep_iterative_debug_ = false;
409+
int negotiation_debug_interval_ = 1;
410+
int negotiation_debug_start_ = 0;
401411
bool incremental_ = false;
402412
bool use_negotiation_ = false;
403413

src/dpl/src/NegotiationLegalizer.cpp

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ void NegotiationLegalizer::legalize()
9595
1,
9696
"NegotiationLegalizer: starting legalization.");
9797

98+
logger_->info(utl::DPL,
99+
1103,
100+
"NegotiationLegalizer search window: +/-{} sites horizontally, "
101+
"+/-{} rows vertically.",
102+
site_search_window_,
103+
row_search_window_);
104+
105+
logger_->info(
106+
utl::DPL, 1104, "NegotiationLegalizer DRC penalty: {}.", drc_penalty_);
107+
98108
double init_from_db_s{0}, build_grid_s{0}, fence_regions_s{0}, abacus_s{0};
99109
double negotiation_s{0}, post_neg_sync_s{0}, metrics_s{0}, flush_s{0},
100110
orient_s{0};
@@ -114,7 +124,6 @@ void NegotiationLegalizer::legalize()
114124

115125
if (debug_observer_) {
116126
debug_observer_->startPlacement(db_->getChip()->getBlock());
117-
debugPause("Pause after initFromDb.");
118127
}
119128

120129
{
@@ -137,6 +146,8 @@ void NegotiationLegalizer::legalize()
137146
initFenceRegions();
138147
}
139148

149+
debugPause("Pause after initialization.");
150+
140151
debugPrint(logger_,
141152
utl::DPL,
142153
"negotiation",
@@ -225,12 +236,17 @@ void NegotiationLegalizer::legalize()
225236
}
226237

227238
if (debug_observer_) {
228-
setDplPositions();
239+
commitNegotiationPosToDpl();
229240
// this flush may imply functional changes. It hides initial movements for
230241
// clean debugging negotiation phase.
231-
flushToDb();
242+
logger_->report(
243+
"Committing post-init positions to odb; debug move line drawings will "
244+
"exclude gpl-to-init displacement.");
245+
commitNegotiationPosToOdb();
232246
pushNegotiationPixels();
233-
logger_->report("Pause after Abacus pass.");
247+
logger_->report(run_abacus_
248+
? "Pause after initialization: Abacus executed."
249+
: "Pause after initialization: Abacus skipped.");
234250
debug_observer_->redrawAndPause();
235251
}
236252

@@ -302,12 +318,6 @@ void NegotiationLegalizer::legalize()
302318
maxDisp,
303319
nViol);
304320

305-
{
306-
utl::DebugScopedTimer t(
307-
flush_s, logger_, utl::DPL, "negotiation_runtime", 1, "flushToDb: {}");
308-
flushToDb();
309-
}
310-
311321
{
312322
utl::DebugScopedTimer t(orient_s,
313323
logger_,
@@ -348,7 +358,7 @@ void NegotiationLegalizer::legalize()
348358
"negotiation {:.1f}ms ({:.0f}%), "
349359
"postNegSync {:.1f}ms ({:.0f}%), "
350360
"metrics {:.1f}ms ({:.0f}%), "
351-
"flushToDb {:.1f}ms ({:.0f}%), "
361+
"commitNegotiationPosToOdb {:.1f}ms ({:.0f}%), "
352362
"orientUpdate {:.1f}ms ({:.0f}%)",
353363
to_ms(total_s),
354364
to_ms(init_from_db_s),
@@ -369,13 +379,16 @@ void NegotiationLegalizer::legalize()
369379
pct(flush_s),
370380
to_ms(orient_s),
371381
pct(orient_s));
382+
383+
debugPause("Pause after legalization complete.");
372384
}
373385

374386
// ===========================================================================
375-
// flushToDb – write current cell positions to ODB so the GUI reflects them
387+
// commitNegotiationPosToOdb – write current cell positions to ODB so the GUI
388+
// reflects them
376389
// ===========================================================================
377390

378-
void NegotiationLegalizer::flushToDb()
391+
void NegotiationLegalizer::commitNegotiationPosToOdb()
379392
{
380393
const Grid* dplGrid = opendp_->grid_.get();
381394
for (const auto& cell : cells_) {
@@ -454,17 +467,18 @@ void NegotiationLegalizer::debugPause(const std::string& msg)
454467
if (!debug_observer_) {
455468
return;
456469
}
457-
setDplPositions();
470+
commitNegotiationPosToDpl();
458471
pushNegotiationPixels();
459472
logger_->report("{}", msg);
460473
debug_observer_->redrawAndPause();
461474
}
462475

463476
// ===========================================================================
464-
// setDplPositions – pass the positions to the DPL original structure (Node)
477+
// commitNegotiationPosToDpl – pass the positions to the DPL original structure
478+
// (Node)
465479
// ===========================================================================
466480

467-
void NegotiationLegalizer::setDplPositions()
481+
void NegotiationLegalizer::commitNegotiationPosToDpl()
468482
{
469483
if (!network_) {
470484
return;

src/dpl/src/NegotiationLegalizer.h

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <cmath>
88
#include <limits>
99
#include <string>
10+
#include <unordered_map>
1011
#include <unordered_set>
1112
#include <utility>
1213
#include <vector>
@@ -30,18 +31,19 @@ class Edge;
3031
// Constants (defaults match the NBLG paper)
3132
// ---------------------------------------------------------------------------
3233
constexpr int kInfCost = std::numeric_limits<int>::max() / 2;
33-
constexpr int kHorizWindow = 20; // search width, current row (sites)
34-
constexpr int kAdjWindow = 5; // search width, adjacent rows
35-
constexpr int kMaxIterNeg = 400; // negotiation phase-1 limit
36-
constexpr int kMaxIterNeg2 = 1000; // negotiation phase-2 limit
37-
constexpr int kIsolationPt = 1; // isolation-point parameter I
38-
constexpr double kMfDefault = 1.5; // max-disp penalty multiplier
39-
constexpr int kThDefault = 30; // max-disp threshold (sites)
40-
constexpr double kHfDefault = 1.0; // history-cost increment factor
41-
constexpr double kAlpha = 0.7; // adaptive-pf α
42-
constexpr double kBeta = 10.0; // adaptive-pf β
43-
constexpr double kGamma = 0.005; // adaptive-pf γ
44-
constexpr int kIth = 300; // pf ramp-up threshold iteration
34+
constexpr int kSiteSearchWindow = 20; // search width, current row (sites)
35+
constexpr int kRowSearchWindow = 5; // search width, adjacent rows
36+
constexpr double kDrcPenalty = 5.0; // base DRC penalty (scaled per iter)
37+
constexpr int kMaxIterNeg = 400; // negotiation phase-1 limit
38+
constexpr int kMaxIterNeg2 = 1000; // negotiation phase-2 limit
39+
constexpr int kIsolationPt = 1; // isolation-point parameter I
40+
constexpr double kMfDefault = 1.5; // max-disp penalty multiplier
41+
constexpr int kThDefault = 30; // max-disp threshold (sites)
42+
constexpr double kHfDefault = 1.0; // history-cost increment factor
43+
constexpr double kAlpha = 0.7; // adaptive-pf α
44+
constexpr double kBeta = 10.0; // adaptive-pf β
45+
constexpr double kGamma = 0.005; // adaptive-pf γ
46+
constexpr int kIth = 300; // pf ramp-up threshold iteration
4547

4648
// ---------------------------------------------------------------------------
4749
// FenceRect / FenceRegion
@@ -129,15 +131,16 @@ class NegotiationLegalizer
129131
void legalize();
130132

131133
// Pass positions back to the DPL original structure.
132-
void setDplPositions();
134+
void commitNegotiationPosToDpl();
133135

134136
// Tuning knobs (all have paper-default values)
135137
void setRunAbacus(bool run) { run_abacus_ = run; }
136138
void setMf(double mf) { max_disp_multiplier_ = mf; }
137139
void setTh(int th) { max_disp_threshold_ = th; }
138140
void setMaxIterNeg(int n) { max_iter_neg_ = n; }
139-
void setHorizWindow(int w) { horiz_window_ = w; }
140-
void setAdjWindow(int w) { adj_window_ = w; }
141+
void setSiteSearchWindow(int w) { site_search_window_ = w; }
142+
void setRowSearchWindow(int w) { row_search_window_ = w; }
143+
void setDrcPenalty(double p) { drc_penalty_ = p; }
141144
void setNumThreads(int n) { num_threads_ = n; }
142145

143146
// Metrics (valid after legalize())
@@ -150,7 +153,8 @@ class NegotiationLegalizer
150153
bool initFromDb();
151154
void buildGrid();
152155
void initFenceRegions();
153-
void flushToDb(); // Write current cell positions to ODB (for GUI updates)
156+
void commitNegotiationPosToOdb(); // Write current cell positions to ODB (for
157+
// GUI updates)
154158
void pushNegotiationPixels();
155159
void debugPause(const std::string& msg);
156160

@@ -165,7 +169,8 @@ class NegotiationLegalizer
165169
void runNegotiation(const std::vector<int>& illegalCells);
166170
int negotiationIter(std::vector<int>& activeCells,
167171
int iter,
168-
bool updateHistory);
172+
bool updateHistory,
173+
bool print_row);
169174
void ripUp(int cell_idx);
170175
void place(int cell_idx, int x, int y);
171176
[[nodiscard]] std::pair<int, int> findBestLocation(int cell_idx,
@@ -177,6 +182,15 @@ class NegotiationLegalizer
177182
void updateDrcHistoryCosts(const std::vector<int>& activeCells);
178183
void sortByNegotiationOrder(std::vector<int>& indices) const;
179184

185+
// Print a stuck-cell summary (overall counts + per-height breakdown).
186+
// No-op when both counts are zero.
187+
void printStuckSummary(
188+
const char* label,
189+
int no_cand_count,
190+
int same_pos_count,
191+
const std::unordered_map<int, int>& no_cand_by_height,
192+
const std::unordered_map<int, int>& same_pos_by_height) const;
193+
180194
// Post-optimisation
181195
void greedyImprove(int passes);
182196
void cellSwap();
@@ -252,8 +266,23 @@ class NegotiationLegalizer
252266
double max_disp_multiplier_{kMfDefault}; // mf on the paper
253267
int max_disp_threshold_{kThDefault}; // th on the paper
254268
int max_iter_neg_{kMaxIterNeg};
255-
int horiz_window_{kHorizWindow};
256-
int adj_window_{kAdjWindow};
269+
int site_search_window_{kSiteSearchWindow};
270+
int current_iter_{0}; // updated at the start of each negotiationIter call
271+
272+
// Last-iteration stats, kept so runNegotiation can print the final row.
273+
int last_iter_{-1};
274+
int last_printed_iter_{-1};
275+
int last_violations_{0};
276+
int last_illegal_cells_{0};
277+
int last_illegal_sites_{0};
278+
279+
// Cells that actually changed position during the current negotiation
280+
// iteration. Passed to the debug observer so cells from prior iterations
281+
// are rendered in grey while current-iteration movers keep directional
282+
// colors.
283+
std::unordered_set<odb::dbInst*> current_iter_movers_;
284+
int row_search_window_{kRowSearchWindow};
285+
double drc_penalty_{kDrcPenalty};
257286
int num_threads_{1};
258287
bool run_abacus_{false};
259288

@@ -265,6 +294,21 @@ class NegotiationLegalizer
265294
mutable double prof_drc_s_{0};
266295
mutable int prof_candidates_evaluated_{0};
267296
mutable int prof_candidates_filtered_{0};
297+
298+
// Stuck-cell tallies for the current runNegotiation call. Reset at the
299+
// start of runNegotiation and printed at the end. The per-height maps are
300+
// keyed by cell.height (row units).
301+
mutable int stuck_no_candidate_count_{0};
302+
mutable int stuck_same_pos_count_{0};
303+
mutable std::unordered_map<int, int> stuck_no_candidate_by_height_;
304+
mutable std::unordered_map<int, int> stuck_same_pos_by_height_;
305+
306+
// Per-iteration variants. Reset at the start of each negotiationIter and
307+
// printed at the end of that iteration.
308+
mutable int stuck_no_candidate_count_iter_{0};
309+
mutable int stuck_same_pos_count_iter_{0};
310+
mutable std::unordered_map<int, int> stuck_no_candidate_by_height_iter_;
311+
mutable std::unordered_map<int, int> stuck_same_pos_by_height_iter_;
268312
};
269313

270314
} // namespace dpl

0 commit comments

Comments
 (0)