-
Notifications
You must be signed in to change notification settings - Fork 772
mpl: enumerate tilings for macro clusters instead of using simulated annealing #9247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
5d71d78
0c2bb5c
bafe6dd
e57ea8a
65f03e6
7d5e86b
01e0f06
0e67816
ed39a9d
75221b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -635,240 +635,66 @@ void HierRTLMP::calculateMacroTilings(Cluster* cluster) | |||||
| } | ||||||
|
|
||||||
| std::vector<HardMacro*> hard_macros = cluster->getHardMacros(); | ||||||
| TilingSet tilings_set; | ||||||
|
|
||||||
| if (hard_macros.size() == 1) { | ||||||
| int width = hard_macros[0]->getWidth(); | ||||||
| int height = hard_macros[0]->getHeight(); | ||||||
|
|
||||||
| TilingList tilings; | ||||||
| tilings.emplace_back(width, height); | ||||||
| cluster->setTilings(tilings); | ||||||
|
|
||||||
| debugPrint(logger_, | ||||||
| MPL, | ||||||
| "coarse_shaping", | ||||||
| 1, | ||||||
| "{} has only one macro, set tiling according to macro with halo", | ||||||
| cluster->getName()); | ||||||
| return; | ||||||
| } | ||||||
| int number_of_macros = hard_macros.size(); | ||||||
| int macro_width = hard_macros.front()->getWidth(); | ||||||
| int macro_height = hard_macros.front()->getHeight(); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does this check that all macros are of a single master? What if they are not?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The clusters are always made of macros of the same size. The function that creates/merges macro clusters checks for their sizes (ClusteringEngine::groupSingleMacroCluster using the size_class variable). |
||||||
|
|
||||||
| if (cluster->isArrayOfInterconnectedMacros()) { | ||||||
| setTightPackingTilings(cluster); | ||||||
| return; | ||||||
| } | ||||||
| TilingList tilings = generateTilingsForMacroCluster( | ||||||
| macro_width, macro_height, number_of_macros); | ||||||
|
|
||||||
| if (graphics_) { | ||||||
| graphics_->setCurrentCluster(cluster); | ||||||
| } | ||||||
|
|
||||||
| // otherwise call simulated annealing to determine tilings | ||||||
| // set the action probabilities | ||||||
| const float action_sum = pos_swap_prob_ + neg_swap_prob_ + double_swap_prob_ | ||||||
| + exchange_swap_prob_; | ||||||
|
|
||||||
| const odb::Rect outline( | ||||||
| 0, 0, tree_->root->getWidth(), tree_->root->getHeight()); | ||||||
|
|
||||||
| // update macros | ||||||
| std::vector<HardMacro> macros; | ||||||
| macros.reserve(hard_macros.size()); | ||||||
| for (auto& macro : hard_macros) { | ||||||
| macros.push_back(*macro); | ||||||
| } | ||||||
| int num_perturb_per_step = (macros.size() > num_perturb_per_step_ / 10) | ||||||
| ? macros.size() | ||||||
| : num_perturb_per_step_ / 10; | ||||||
| if (cluster->getParent() == nullptr) { | ||||||
| num_perturb_per_step = (macros.size() > num_perturb_per_step_ / 5) | ||||||
| ? macros.size() | ||||||
| : num_perturb_per_step_ / 5; | ||||||
| } | ||||||
|
|
||||||
| // To generate different macro tilings, we vary the outline constraints | ||||||
| // we first vary the outline width while keeping outline_height fixed | ||||||
| // Then we vary the outline height while keeping outline_width fixed | ||||||
| // We vary the outline of cluster to generate different tilings | ||||||
| std::vector<float> vary_factor_list{1.0}; | ||||||
| float vary_step = 1.0 / num_runs_; // change the outline by at most halfly | ||||||
| for (int i = 1; i < num_runs_; i++) { | ||||||
| vary_factor_list.push_back(1.0 - i * vary_step); | ||||||
| } | ||||||
| int remaining_runs = num_runs_; | ||||||
| int run_id = 0; | ||||||
| while (remaining_runs > 0) { | ||||||
| HardSAVector sa_batch; | ||||||
| const int run_thread | ||||||
| = graphics_ ? 1 : std::min(remaining_runs, num_threads_); | ||||||
| for (int i = 0; i < run_thread; i++) { | ||||||
| const odb::Rect new_outline( | ||||||
| 0, 0, outline.dx() * vary_factor_list[run_id++], outline.dy()); | ||||||
| if (graphics_) { | ||||||
| graphics_->setOutline(new_outline); | ||||||
| } | ||||||
| std::unique_ptr<SACoreHardMacro> sa | ||||||
| = std::make_unique<SACoreHardMacro>(tree_.get(), | ||||||
| new_outline, | ||||||
| macros, | ||||||
| shaping_core_weights_, | ||||||
| pos_swap_prob_ / action_sum, | ||||||
| neg_swap_prob_ / action_sum, | ||||||
| double_swap_prob_ / action_sum, | ||||||
| exchange_swap_prob_ / action_sum, | ||||||
| init_prob_, | ||||||
| max_num_step_, | ||||||
| num_perturb_per_step, | ||||||
| random_seed_ + run_id, | ||||||
| graphics_.get(), | ||||||
| logger_, | ||||||
| block_); | ||||||
| sa_batch.push_back(std::move(sa)); | ||||||
| } | ||||||
| if (sa_batch.size() == 1) { | ||||||
| runSA<SACoreHardMacro>(sa_batch[0].get()); | ||||||
| } else { | ||||||
| // multi threads | ||||||
| std::vector<std::thread> threads; | ||||||
| threads.reserve(sa_batch.size()); | ||||||
| for (auto& sa : sa_batch) { | ||||||
| threads.emplace_back(runSA<SACoreHardMacro>, sa.get()); | ||||||
| } | ||||||
| for (auto& th : threads) { | ||||||
| th.join(); | ||||||
| } | ||||||
| } | ||||||
| // add macro tilings | ||||||
| for (auto& sa : sa_batch) { | ||||||
| if (sa->fitsIn(outline)) { | ||||||
| tilings_set.insert({sa->getWidth(), sa->getHeight()}); | ||||||
| } | ||||||
| } | ||||||
| remaining_runs -= run_thread; | ||||||
| } | ||||||
| // change the outline height while keeping outline width fixed | ||||||
| remaining_runs = num_runs_; | ||||||
| run_id = 0; | ||||||
| while (remaining_runs > 0) { | ||||||
| HardSAVector sa_batch; | ||||||
| const int run_thread | ||||||
| = graphics_ ? 1 : std::min(remaining_runs, num_threads_); | ||||||
| for (int i = 0; i < run_thread; i++) { | ||||||
| const odb::Rect new_outline( | ||||||
| 0, 0, outline.dx(), outline.dy() * vary_factor_list[run_id++]); | ||||||
| if (graphics_) { | ||||||
| graphics_->setOutline(new_outline); | ||||||
| } | ||||||
| std::unique_ptr<SACoreHardMacro> sa | ||||||
| = std::make_unique<SACoreHardMacro>(tree_.get(), | ||||||
| new_outline, | ||||||
| macros, | ||||||
| shaping_core_weights_, | ||||||
| pos_swap_prob_ / action_sum, | ||||||
| neg_swap_prob_ / action_sum, | ||||||
| double_swap_prob_ / action_sum, | ||||||
| exchange_swap_prob_ / action_sum, | ||||||
| init_prob_, | ||||||
| max_num_step_, | ||||||
| num_perturb_per_step, | ||||||
| random_seed_ + run_id, | ||||||
| graphics_.get(), | ||||||
| logger_, | ||||||
| block_); | ||||||
| sa_batch.push_back(std::move(sa)); | ||||||
| } | ||||||
| if (sa_batch.size() == 1) { | ||||||
| runSA<SACoreHardMacro>(sa_batch[0].get()); | ||||||
| } else { | ||||||
| // multi threads | ||||||
| std::vector<std::thread> threads; | ||||||
| threads.reserve(sa_batch.size()); | ||||||
| for (auto& sa : sa_batch) { | ||||||
| threads.emplace_back(runSA<SACoreHardMacro>, sa.get()); | ||||||
| } | ||||||
| for (auto& th : threads) { | ||||||
| th.join(); | ||||||
| } | ||||||
| } | ||||||
| // add macro tilings | ||||||
| for (auto& sa : sa_batch) { | ||||||
| if (sa->fitsIn(outline)) { | ||||||
| tilings_set.insert({sa->getWidth(), sa->getHeight()}); | ||||||
| } | ||||||
| } | ||||||
| remaining_runs -= run_thread; | ||||||
| if (tilings.size() == 0) { | ||||||
|
||||||
| if (tilings.size() == 0) { | |
| if (tilings.empty()) { |
Additional context
/usr/include/c++/13/bits/stl_vector.h:1087: method 'vector'::empty() defined here
empty() const _GLIBCXX_NOEXCEPT
^
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for std::vector::insert here. Just assign tilings directly.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
| if (tilings.size() == 0) { | |
| if (tilings.empty()) { |
Additional context
/usr/include/c++/13/bits/stl_vector.h:1087: method 'vector'::empty() defined here
empty() const _GLIBCXX_NOEXCEPT
^There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we only allow perfect tiling we will have more limited choices (e.g. for an 9 macros you won't try 2x5, only 1x9 and 3x3). Is this intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The previous code kept only the smallest area tilings too. Doing it this way also avoids notches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a potential for a crash here if
cluster->getHardMacros()returns an empty vector, ashard_macros.front()would be undefined behavior. Although the call chain seems to prevent this, adding a defensive check for an empty vector would make the code more robust. For example: