mpl: improved notches#9282
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces an improved notch detection algorithm for penalty calculation, along with debug visualization for the detected notches. The core logic changes are in SACoreSoftMacro::calNotchPenalty. My review focuses on enhancing the performance and maintainability of this new algorithm. I've identified a significant performance bottleneck due to redundant computations and suggest a fix. Additionally, I've provided recommendations for refactoring to reduce code duplication, replacing magic numbers with constants, and removing a non-standard header for better portability.
src/mpl/src/SACoreSoftMacro.cpp
Outdated
|
|
||
| #include "SACoreSoftMacro.h" | ||
|
|
||
| #include <bits/ranges_algo.h> |
There was a problem hiding this comment.
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| std::vector<int> x_coords; | ||
| int epsilon = outline_.dx() / 100; | ||
| for (size_t i = 0; i < x_point.size(); i++) { | ||
| if (i + 1 < x_point.size() | ||
| && std::abs(x_point[i + 1] - x_point[i]) <= epsilon) { | ||
| continue; | ||
| } | ||
| x_point.insert(macro.getX()); | ||
| x_point.insert(macro.getX() + macro.getWidth()); | ||
| y_point.insert(macro.getY()); | ||
| y_point.insert(macro.getY() + macro.getHeight()); | ||
| x_coords.push_back(x_point[i]); | ||
| } | ||
|
|
||
| std::vector<int> y_coords; | ||
| epsilon = outline_.dy() / 100; | ||
| for (size_t i = 0; i < y_point.size(); i++) { | ||
| if (i + 1 < y_point.size() | ||
| && std::abs(y_point[i + 1] - y_point[i]) <= epsilon) { | ||
| continue; | ||
| } | ||
| y_coords.push_back(y_point[i]); | ||
| } |
There was a problem hiding this comment.
The value 100 is used as a magic number in two places to calculate epsilon. It would be better to define it as a single named constant (e.g., constexpr int kCoordEpsilonDivisor = 100;) at a suitable scope to improve readability, maintainability, and ensure consistency.
References
- Define tunable parameters as named constants instead of using hardcoded magic numbers.
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| if (n.total() == 4) { | ||
| notch_penalty_ += calSingleNotchPenalty(block_->dbuToMicrons(width), | ||
| block_->dbuToMicrons(height)); | ||
| if (graphics_) { | ||
| graphics_->addNotch(odb::Rect(x_coords[start_col], | ||
| y_coords[start_row], | ||
| x_coords[end_col + 1], | ||
| y_coords[end_row + 1])); | ||
| } | ||
| } else if (n.top && n.bottom) { | ||
| if (height < notch_h_th_) { | ||
| notch_penalty_ += calSingleNotchPenalty(block_->dbuToMicrons(width), | ||
| block_->dbuToMicrons(height)); | ||
| if (graphics_) { | ||
| graphics_->addNotch(odb::Rect(x_coords[start_col], | ||
| y_coords[start_row], | ||
| x_coords[end_col + 1], | ||
| y_coords[end_row + 1])); | ||
| } | ||
| } | ||
| } else if (n.left && n.right) { | ||
| if (width < notch_v_th_) { | ||
| notch_penalty_ += calSingleNotchPenalty(block_->dbuToMicrons(width), | ||
| block_->dbuToMicrons(height)); | ||
| if (graphics_) { | ||
| graphics_->addNotch(odb::Rect(x_coords[start_col], | ||
| y_coords[start_row], | ||
| x_coords[end_col + 1], | ||
| y_coords[end_row + 1])); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The code block for calculating the notch penalty and adding the notch for visualization is duplicated in three places within the if-else if structure. This can be refactored to improve maintainability and reduce redundancy.
You could determine if a notch should be penalized using a boolean flag, and then have a single block of code that performs the penalty calculation and graphics update.
bool is_notch = false;
if (n.total() == 4) {
is_notch = true;
} else if (n.top && n.bottom) {
if (height < notch_h_th_) {
is_notch = true;
}
} else if (n.left && n.right) {
if (width < notch_v_th_) {
is_notch = true;
}
}
if (is_notch) {
notch_penalty_ += calSingleNotchPenalty(block_->dbuToMicrons(width),
block_->dbuToMicrons(height));
if (graphics_) {
graphics_->addNotch(odb::Rect(x_coords[start_col],
y_coords[start_row],
x_coords[end_col + 1],
y_coords[end_row + 1]));
}
}
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| #include <cmath> | ||
| #include <iterator> | ||
| #include <limits> | ||
| #include <ranges> |
There was a problem hiding this comment.
warning: included header limits is not used directly [misc-include-cleaner]
| #include <ranges> | |
| #include <ranges> |
| #include <iterator> | ||
| #include <limits> | ||
| #include <ranges> | ||
| #include <set> |
There was a problem hiding this comment.
warning: included header ranges is not used directly [misc-include-cleaner]
| #include <set> | |
| #include <set> |
src/mpl/src/SACoreSoftMacro.cpp
Outdated
|
|
||
| if (graphics_) { | ||
| graphics_->setNotchPenalty( | ||
| {"Notch", notch_weight_, notch_penalty_, norm_notch_penalty_}); |
There was a problem hiding this comment.
warning: use designated initializer list to initialize 'PenaltyData' [modernize-use-designated-initializers]
| {"Notch", notch_weight_, notch_penalty_, norm_notch_penalty_}); | |
| {.name="Notch", .weight=notch_weight_, .value=notch_penalty_, .normalization_factor=norm_notch_penalty_}); |
Additional context
src/mpl/src/mpl-util.h:89: aggregate type is defined here
struct PenaltyData
^
src/mpl/src/SACoreSoftMacro.cpp
Outdated
|
|
||
| std::vector<int> x_coords; | ||
| int epsilon = outline_.dx() / 100; | ||
| for (size_t i = 0; i < x_point.size(); i++) { |
There was a problem hiding this comment.
warning: no header providing "size_t" is directly included [misc-include-cleaner]
src/mpl/src/SACoreSoftMacro.cpp:9:
- #include <iterator>
+ #include <cstddef>
+ #include <iterator>|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
94f3969 to
407f91a
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
I think that the notch function is too big and should be broken into smaller pieces, that's why most of the comments. We've been making a large effort to a more granular code and it has been proven to be a very helpful thing.
I tend to prefer functions over lambdas if it starts to get too big. I think it does depend on the context (it looks that the idea here was to keep the notch detection code well encapsulated), but for concision and readability, let's keep things smaller. We can have a "section" of methods only for notch penalty.
A question: are the notches being erased when rendering after MPL is done? (see eraseDrawing).
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| bool left = true; | ||
| bool right = true; | ||
|
|
||
| int total() { return top + bottom + left + right; } |
There was a problem hiding this comment.
I'm not a fan of implicit casting. However the logic here is sound. @maliberty would you have an opinion on it?
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| for (int col = 0; col < num_x; col++) { | ||
| if (grid[row][col]) { | ||
| continue; | ||
| auto neighbors = [&](int row1, int col1, int row2, int col2) { |
There was a problem hiding this comment.
I think this should be a function `findNeighbors".
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| int end_row = start_row; | ||
| int end_col = start_col; | ||
|
|
||
| Neighbors n = neighbors(start_row, start_col, end_row, end_col); |
There was a problem hiding this comment.
Please, avoid this type of abbreviation.
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| return neighbors; | ||
| }; | ||
|
|
||
| auto valid = [&](int row1, int col1, int row2, int col2) { |
There was a problem hiding this comment.
This should also be a function. Validity doesn't feel like the best quality here. Perhaps expansionOverlapped or something in this sense? I'm not attached to my suggestion.
src/mpl/src/SACoreSoftMacro.cpp
Outdated
| return; | ||
| } | ||
|
|
||
| struct Neighbors |
There was a problem hiding this comment.
This can be a member of the annealer itself. I also think we should have a comment explaining what are Neighbors (seeing a boolean in the code doesn't tell us much).
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
|
clang-tidy review says "All clean, LGTM! 👍" |
src/mpl/src/graphics.cpp
Outdated
| painter.drawRect(rect); | ||
| } | ||
|
|
||
| // notches_.clear(); |
Signed-off-by: João Mai <[email protected]>
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: João Mai <[email protected]>
Signed-off-by: João Mai <[email protected]>
src/mpl/src/SACoreSoftMacro.h
Outdated
|
|
||
| bool enhancements_on_ = false; | ||
| bool centralization_was_reverted_ = false; | ||
| bool is_single_array_single_std_cell_cluster = false; |
There was a problem hiding this comment.
I think it would make more readable for the perspective of HierRTLMP class if this bool has something like force_centralization_.
Then, when setting it we'd have:
if (single_array_single_std_cell_cluster) {
sa->forceCentralization();
}
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: João Mai <[email protected]>
|
Currently blocked by #3846 on ORFS. |
Signed-off-by: João Mai <[email protected]>
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: João Mai <[email protected]>
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: João Mai <[email protected]>
|
clang-tidy review says "All clean, LGTM! 👍" |
|
Paired with #3863 on ORFS. |
| if (i + 1 < x_point.size() | ||
| && std::abs(x_point[i + 1] - x_point[i]) <= epsilon) { |
There was a problem hiding this comment.
This has the potential to skip too many points. Imagine a series of points all 0.9 epsilon apart. You would collapse them all. It would be better to set a threshold from an accepted point and skip all points within that threshold.
Changing this will require another secure CI so I suggest you do it in a follow up PR.
| bool SACoreSoftMacro::isSegmentEmpty(std::vector<std::vector<bool>>& grid, | ||
| int start_row, | ||
| int start_col, | ||
| int end_row, | ||
| int end_col) |
There was a problem hiding this comment.
All arguments should be const and the method itself can be static.
| SACoreSoftMacro::Neighbors SACoreSoftMacro::findNeighbors( | ||
| std::vector<std::vector<bool>>& grid, | ||
| int start_row, | ||
| int start_col, | ||
| int end_row, | ||
| int end_col) |
| if (current_neighbors.total() == 4) { | ||
| is_notch = true; |
There was a problem hiding this comment.
Pathological but you could have neighbors on all sides of a region larger than notch_h/v_th_ in both directions (e.g. a ring of macros). Probably that shouldn't be a notch.
| // Used to calculate notches | ||
| struct Neighbors |
There was a problem hiding this comment.
I had to read the code to understand the semantics of these bools. A better descriptive comment would be helpful.
This PR improves the notch detection for the notch penalty calculation. It achieves it by considering closely aligned macros as aligned (in order to generate a more meaningful grid) and merging cells in order to find the notches actual size and amount.
It also enhances the debug visualization, showing the notches when using the mpl::mpl_debug command.