Skip to content

Commit b421595

Browse files
authored
Merge pull request #9247 from The-OpenROAD-Project-staging/mpl-tight-packing
mpl: enumerate tilings for macro clusters instead of using simulated annealing
2 parents e0d028b + 75221b8 commit b421595

File tree

4 files changed

+39
-221
lines changed

4 files changed

+39
-221
lines changed

src/mpl/src/clusterEngine.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,8 +1227,7 @@ void ClusteringEngine::multilevelAutocluster(Cluster* parent)
12271227
if (level_ == 0) {
12281228
const int leaf_max_std_cell
12291229
= tree_->base_max_std_cell
1230-
/ std::pow(tree_->cluster_size_ratio, tree_->max_level - 1)
1231-
* (1 + size_tolerance_);
1230+
/ std::pow(tree_->cluster_size_ratio, tree_->max_level - 1);
12321231
if (parent->getNumStdCell() < leaf_max_std_cell) {
12331232
force_split_root = true;
12341233
debugPrint(logger_,
@@ -1293,13 +1292,6 @@ void ClusteringEngine::updateSizeThresholds()
12931292
max_std_cell_ = tree_->base_max_std_cell / coarse_factor;
12941293
min_std_cell_ = tree_->base_min_std_cell / coarse_factor;
12951294

1296-
// We define the tolerance to improve the robustness of our hierarchical
1297-
// clustering
1298-
max_macro_ *= (1 + size_tolerance_);
1299-
min_macro_ *= (1 - size_tolerance_);
1300-
max_std_cell_ *= (1 + size_tolerance_);
1301-
min_std_cell_ *= (1 - size_tolerance_);
1302-
13031295
if (min_macro_ <= 0) {
13041296
min_macro_ = 1;
13051297
max_macro_ = min_macro_ * tree_->cluster_size_ratio / 2.0;

src/mpl/src/clusterEngine.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ class ClusteringEngine
309309
int min_macro_{0};
310310
int max_std_cell_{0};
311311
int min_std_cell_{0};
312-
const float size_tolerance_ = 0.1;
313312

314313
// Variables for data flow
315314
DataFlow data_connections_;

src/mpl/src/hier_rtlmp.cpp

Lines changed: 35 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -635,240 +635,65 @@ void HierRTLMP::calculateMacroTilings(Cluster* cluster)
635635
}
636636

637637
std::vector<HardMacro*> hard_macros = cluster->getHardMacros();
638-
TilingSet tilings_set;
639-
640-
if (hard_macros.size() == 1) {
641-
int width = hard_macros[0]->getWidth();
642-
int height = hard_macros[0]->getHeight();
643-
644-
TilingList tilings;
645-
tilings.emplace_back(width, height);
646-
cluster->setTilings(tilings);
647-
648-
debugPrint(logger_,
649-
MPL,
650-
"coarse_shaping",
651-
1,
652-
"{} has only one macro, set tiling according to macro with halo",
653-
cluster->getName());
654-
return;
655-
}
638+
int number_of_macros = hard_macros.size();
639+
int macro_width = hard_macros.front()->getWidth();
640+
int macro_height = hard_macros.front()->getHeight();
656641

657-
if (cluster->isArrayOfInterconnectedMacros()) {
658-
setTightPackingTilings(cluster);
659-
return;
660-
}
642+
TilingList tilings = generateTilingsForMacroCluster(
643+
macro_width, macro_height, number_of_macros);
661644

662-
if (graphics_) {
663-
graphics_->setCurrentCluster(cluster);
664-
}
665-
666-
// otherwise call simulated annealing to determine tilings
667-
// set the action probabilities
668-
const float action_sum = pos_swap_prob_ + neg_swap_prob_ + double_swap_prob_
669-
+ exchange_swap_prob_;
670-
671-
const odb::Rect outline(
672-
0, 0, tree_->root->getWidth(), tree_->root->getHeight());
673-
674-
// update macros
675-
std::vector<HardMacro> macros;
676-
macros.reserve(hard_macros.size());
677-
for (auto& macro : hard_macros) {
678-
macros.push_back(*macro);
679-
}
680-
int num_perturb_per_step = (macros.size() > num_perturb_per_step_ / 10)
681-
? macros.size()
682-
: num_perturb_per_step_ / 10;
683-
if (cluster->getParent() == nullptr) {
684-
num_perturb_per_step = (macros.size() > num_perturb_per_step_ / 5)
685-
? macros.size()
686-
: num_perturb_per_step_ / 5;
687-
}
688-
689-
// To generate different macro tilings, we vary the outline constraints
690-
// we first vary the outline width while keeping outline_height fixed
691-
// Then we vary the outline height while keeping outline_width fixed
692-
// We vary the outline of cluster to generate different tilings
693-
std::vector<float> vary_factor_list{1.0};
694-
float vary_step = 1.0 / num_runs_; // change the outline by at most halfly
695-
for (int i = 1; i < num_runs_; i++) {
696-
vary_factor_list.push_back(1.0 - i * vary_step);
697-
}
698-
int remaining_runs = num_runs_;
699-
int run_id = 0;
700-
while (remaining_runs > 0) {
701-
HardSAVector sa_batch;
702-
const int run_thread
703-
= graphics_ ? 1 : std::min(remaining_runs, num_threads_);
704-
for (int i = 0; i < run_thread; i++) {
705-
const odb::Rect new_outline(
706-
0, 0, outline.dx() * vary_factor_list[run_id++], outline.dy());
707-
if (graphics_) {
708-
graphics_->setOutline(new_outline);
709-
}
710-
std::unique_ptr<SACoreHardMacro> sa
711-
= std::make_unique<SACoreHardMacro>(tree_.get(),
712-
new_outline,
713-
macros,
714-
shaping_core_weights_,
715-
pos_swap_prob_ / action_sum,
716-
neg_swap_prob_ / action_sum,
717-
double_swap_prob_ / action_sum,
718-
exchange_swap_prob_ / action_sum,
719-
init_prob_,
720-
max_num_step_,
721-
num_perturb_per_step,
722-
random_seed_ + run_id,
723-
graphics_.get(),
724-
logger_,
725-
block_);
726-
sa_batch.push_back(std::move(sa));
727-
}
728-
if (sa_batch.size() == 1) {
729-
runSA<SACoreHardMacro>(sa_batch[0].get());
730-
} else {
731-
// multi threads
732-
std::vector<std::thread> threads;
733-
threads.reserve(sa_batch.size());
734-
for (auto& sa : sa_batch) {
735-
threads.emplace_back(runSA<SACoreHardMacro>, sa.get());
736-
}
737-
for (auto& th : threads) {
738-
th.join();
739-
}
740-
}
741-
// add macro tilings
742-
for (auto& sa : sa_batch) {
743-
if (sa->fitsIn(outline)) {
744-
tilings_set.insert({sa->getWidth(), sa->getHeight()});
745-
}
746-
}
747-
remaining_runs -= run_thread;
748-
}
749-
// change the outline height while keeping outline width fixed
750-
remaining_runs = num_runs_;
751-
run_id = 0;
752-
while (remaining_runs > 0) {
753-
HardSAVector sa_batch;
754-
const int run_thread
755-
= graphics_ ? 1 : std::min(remaining_runs, num_threads_);
756-
for (int i = 0; i < run_thread; i++) {
757-
const odb::Rect new_outline(
758-
0, 0, outline.dx(), outline.dy() * vary_factor_list[run_id++]);
759-
if (graphics_) {
760-
graphics_->setOutline(new_outline);
761-
}
762-
std::unique_ptr<SACoreHardMacro> sa
763-
= std::make_unique<SACoreHardMacro>(tree_.get(),
764-
new_outline,
765-
macros,
766-
shaping_core_weights_,
767-
pos_swap_prob_ / action_sum,
768-
neg_swap_prob_ / action_sum,
769-
double_swap_prob_ / action_sum,
770-
exchange_swap_prob_ / action_sum,
771-
init_prob_,
772-
max_num_step_,
773-
num_perturb_per_step,
774-
random_seed_ + run_id,
775-
graphics_.get(),
776-
logger_,
777-
block_);
778-
sa_batch.push_back(std::move(sa));
779-
}
780-
if (sa_batch.size() == 1) {
781-
runSA<SACoreHardMacro>(sa_batch[0].get());
782-
} else {
783-
// multi threads
784-
std::vector<std::thread> threads;
785-
threads.reserve(sa_batch.size());
786-
for (auto& sa : sa_batch) {
787-
threads.emplace_back(runSA<SACoreHardMacro>, sa.get());
788-
}
789-
for (auto& th : threads) {
790-
th.join();
791-
}
792-
}
793-
// add macro tilings
794-
for (auto& sa : sa_batch) {
795-
if (sa->fitsIn(outline)) {
796-
tilings_set.insert({sa->getWidth(), sa->getHeight()});
797-
}
798-
}
799-
remaining_runs -= run_thread;
645+
if (tilings.empty()) {
646+
tilings = generateTilingsForMacroCluster(
647+
macro_width, macro_height, number_of_macros + 1);
800648
}
801649

802-
if (tilings_set.empty()) {
650+
if (tilings.empty()) {
803651
logger_->error(MPL,
804652
4,
805-
"No valid tilings for hard macro cluster: {}",
806-
cluster->getName());
653+
"Unable to fit cluster {} within outline. Macro height: {}, "
654+
"width: {}, number of macros: {}.",
655+
cluster->getName(),
656+
macro_width,
657+
macro_height,
658+
number_of_macros);
807659
}
808660

809-
TilingList tilings_list(tilings_set.begin(), tilings_set.end());
810-
std::ranges::sort(tilings_list, isAreaSmaller);
661+
cluster->setTilings(tilings);
811662

812-
for (auto& tiling : tilings_list) {
813-
debugPrint(logger_,
814-
MPL,
815-
"coarse_shaping",
816-
2,
817-
"width: {}, height: {}",
818-
tiling.width(),
819-
tiling.height());
820-
}
821-
822-
// we only keep the minimum area tiling since all the macros has the same size
823-
// later this can be relaxed. But this may cause problems because the
824-
// minimizing the wirelength may leave holes near the boundary
825-
TilingList new_tilings_list;
826-
float first_tiling_area = tilings_list.front().area();
827-
for (auto& tiling : tilings_list) {
828-
if (tiling.area() <= first_tiling_area) {
829-
new_tilings_list.push_back(tiling);
663+
if (logger_->debugCheck(MPL, "coarse_shaping", 2)) {
664+
std::string line = "Tiling for hard cluster " + cluster->getName()
665+
+ " with " + std::to_string(number_of_macros)
666+
+ " macros.\n";
667+
for (auto& tiling : tilings) {
668+
line += " < " + std::to_string(tiling.width()) + " , ";
669+
line += std::to_string(tiling.height()) + " > ";
830670
}
671+
line += "\n";
672+
debugPrint(logger_, MPL, "coarse_shaping", 2, "{}", line);
831673
}
832-
tilings_list = std::move(new_tilings_list);
833-
cluster->setTilings(tilings_list);
834-
835-
std::string line = "Tiling for hard cluster " + cluster->getName() + " ";
836-
for (auto& tiling : tilings_list) {
837-
line += " < " + std::to_string(tiling.width()) + " , ";
838-
line += std::to_string(tiling.height()) + " > ";
839-
}
840-
line += "\n";
841-
debugPrint(logger_, MPL, "coarse_shaping", 2, "{}", line);
842674
}
843675

844-
// Used only for arrays of interconnected macros.
845-
void HierRTLMP::setTightPackingTilings(Cluster* macro_array)
676+
TilingList HierRTLMP::generateTilingsForMacroCluster(int macro_width,
677+
int macro_height,
678+
int number_of_macros)
846679
{
847680
TilingList tight_packing_tilings;
848-
849-
int num_macro = macro_array->getNumMacro();
850-
float macro_width = macro_array->getHardMacros().front()->getWidth();
851-
float macro_height = macro_array->getHardMacros().front()->getHeight();
852-
853681
const odb::Rect outline = tree_->root->getBBox();
854682

855-
int columns = 0;
856-
for (int rows = 1; rows < std::sqrt(num_macro) + 1; rows++) {
857-
if (num_macro % rows == 0) {
858-
columns = num_macro / rows;
683+
int rows = 0;
684+
for (int cols = 1; cols <= number_of_macros; cols++) {
685+
if (number_of_macros % cols == 0) {
686+
rows = number_of_macros / cols;
859687

860-
// We don't consider tilings for right angle rotation orientations,
861-
// because they're not allowed in our macro placer.
862-
// Tiling needs to fit inside outline
863-
if (columns * macro_width <= outline.dx()
688+
if (cols * macro_width <= outline.dx()
864689
&& rows * macro_height <= outline.dy()) {
865-
tight_packing_tilings.emplace_back(columns * macro_width,
690+
tight_packing_tilings.emplace_back(cols * macro_width,
866691
rows * macro_height);
867692
}
868693
}
869694
}
870695

871-
macro_array->setTilings(tight_packing_tilings);
696+
return tight_packing_tilings;
872697
}
873698

874699
void HierRTLMP::searchAvailableRegionsForUnconstrainedPins()

src/mpl/src/hier_rtlmp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ class HierRTLMP
145145
void calculateChildrenTilings(Cluster* parent);
146146
void calculateMacroTilings(Cluster* cluster);
147147
IntervalList computeWidthIntervals(const TilingList& tilings);
148-
void setTightPackingTilings(Cluster* macro_array);
148+
TilingList generateTilingsForMacroCluster(int macro_width,
149+
int macro_height,
150+
int number_of_macros);
149151
void searchAvailableRegionsForUnconstrainedPins();
150152
BoundaryToRegionsMap getBoundaryToBlockedRegionsMap(
151153
const std::vector<odb::Rect>& blocked_regions_for_pins) const;

0 commit comments

Comments
 (0)