Skip to content

Commit 6aa854f

Browse files
authored
Merge pull request #8375 from AcKoucher/mpl-connection-by-ratio
mpl: evaluate connection between clusters based on connections' ratio
2 parents 3f36eb5 + f5093ca commit 6aa854f

File tree

14 files changed

+614
-593
lines changed

14 files changed

+614
-593
lines changed

src/mpl/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ rtl_macro_placer
2626
[-max_num_level max_num_level]
2727
[-coarsening_ratio coarsening_ratio]
2828
[-large_net_threshold large_net_threshold]
29-
[-signature_net_threshold signature_net_threshold]
3029
[-halo_width halo_width]
3130
[-halo_height halo_height]
3231
[-fence_lx fence_lx]
@@ -59,7 +58,6 @@ rtl_macro_placer
5958
| `-max_num_level` | Maximum depth of physical hierarchical tree. The default value is `2`, and the allowed values are integers `[0, MAX_INT]`. |
6059
| `-coarsening_ratio` | The larger the coarsening_ratio, the faster the convergence process. The allowed values are floats, and the default value is `10.0`. |
6160
| `-large_net_threshold` | Ignore nets with many connections during clustering, such as global nets. The default value is `50`, and the allowed values are integers `[0, MAX_INT]`. |
62-
| `-signature_net_threshold` | Minimum number of connections between two clusters to be identified as connected. The default value is `50`, and the allowed values are integers `[0, MAX_INT]`. |
6361
| `-halo_width` | Horizontal/vertical halo around macros (microns). The allowed values are floats, and the default value is `0.0`. |
6462
| `-fence_lx`, `-fence_ly`, `-fence_ux`, `-fence_uy` | Defines the global fence bounding box coordinates. The default values are the core area coordinates). |
6563
| `-target_util` | Specifies the target utilization of `MixedCluster` and has higher priority than target_dead_space. The allowed values are floats, and the default value is `0.25`. |

src/mpl/include/mpl/rtl_mp.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ class MacroPlacer
5151
int max_num_level,
5252
float coarsening_ratio,
5353
int large_net_threshold,
54-
int signature_net_threshold,
5554
float halo_width,
5655
float halo_height,
5756
float fence_lx,

src/mpl/src/clusterEngine.cpp

Lines changed: 136 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,23 +1743,10 @@ void ClusteringEngine::mergeChildrenBelowThresholds(
17431743
}
17441744
// Firstly we perform Type 1 merge
17451745
for (int i = 0; i < num_small_children; i++) {
1746-
const int cluster_id = small_children[i]->getCloseCluster(
1747-
small_children_ids, tree_->min_net_count_for_connection);
1748-
debugPrint(
1749-
logger_,
1750-
MPL,
1751-
"multilevel_autoclustering",
1752-
1,
1753-
"Candidate cluster: {} - {}",
1754-
small_children[i]->getName(),
1755-
(cluster_id != -1 ? tree_->maps.id_to_cluster[cluster_id]->getName()
1756-
: " "));
1757-
if (cluster_id != -1
1758-
&& !tree_->maps.id_to_cluster[cluster_id]->isIOCluster()) {
1759-
Cluster* close_cluster = tree_->maps.id_to_cluster[cluster_id];
1760-
if (attemptMerge(close_cluster, small_children[i])) {
1761-
cluster_class[i] = close_cluster->getId();
1762-
}
1746+
Cluster* close_cluster = findSingleWellFormedConnectedCluster(
1747+
small_children[i], small_children_ids);
1748+
if (close_cluster && attemptMerge(close_cluster, small_children[i])) {
1749+
cluster_class[i] = close_cluster->getId();
17631750
}
17641751
}
17651752

@@ -1772,8 +1759,7 @@ void ClusteringEngine::mergeChildrenBelowThresholds(
17721759
continue;
17731760
}
17741761

1775-
if (small_children[i]->isSameConnSignature(
1776-
*small_children[j], tree_->min_net_count_for_connection)) {
1762+
if (sameConnectionSignature(small_children[i], small_children[j])) {
17771763
if (attemptMerge(small_children[i], small_children[j])) {
17781764
cluster_class[j] = i;
17791765
} else {
@@ -1860,6 +1846,128 @@ void ClusteringEngine::mergeChildrenBelowThresholds(
18601846
"Finished merging clusters");
18611847
}
18621848

1849+
bool ClusteringEngine::sameConnectionSignature(Cluster* a, Cluster* b) const
1850+
{
1851+
std::vector<int> a_neighbors = findNeighbors(a, /* ignore */ b);
1852+
if (a_neighbors.empty()) {
1853+
return false;
1854+
}
1855+
1856+
std::vector<int> b_neighbors = findNeighbors(b, /* ignore */ a);
1857+
if (b_neighbors.size() != a_neighbors.size()) {
1858+
return false;
1859+
}
1860+
1861+
std::ranges::sort(a_neighbors);
1862+
std::ranges::sort(b_neighbors);
1863+
1864+
for (int i = 0; i < a_neighbors.size(); i++) {
1865+
if (a_neighbors[i] != b_neighbors[i]) {
1866+
return false;
1867+
}
1868+
}
1869+
1870+
return true;
1871+
}
1872+
1873+
std::vector<int> ClusteringEngine::findNeighbors(Cluster* target_cluster,
1874+
Cluster* ignored_cluster) const
1875+
{
1876+
std::vector<int> neighbors;
1877+
const ConnectionsMap& target_connections
1878+
= target_cluster->getConnectionsMap();
1879+
1880+
for (const auto& [cluster_id, connection_weight] : target_connections) {
1881+
if (cluster_id == target_cluster->getId()) {
1882+
logger_->error(MPL,
1883+
53,
1884+
"Cluster {} is connected to itself.",
1885+
target_cluster->getName());
1886+
}
1887+
1888+
if (cluster_id == ignored_cluster->getId()) {
1889+
continue;
1890+
}
1891+
1892+
const float connection_ratio
1893+
= connection_weight / target_cluster->allConnectionsWeight();
1894+
1895+
if (connection_ratio >= minimum_connection_ratio_) {
1896+
neighbors.push_back(cluster_id);
1897+
}
1898+
}
1899+
1900+
return neighbors;
1901+
}
1902+
1903+
bool ClusteringEngine::strongConnection(Cluster* a,
1904+
Cluster* b,
1905+
const float* connection_weight) const
1906+
{
1907+
if (a == b) {
1908+
logger_->error(
1909+
MPL,
1910+
61,
1911+
"Attempt to evaluate if cluster {} has strong connection with itself.",
1912+
a->getName());
1913+
}
1914+
1915+
// Attention that we need to subtract the weight of the connection that
1916+
// we're evaluating otherwise we'll be taking it into account twice.
1917+
float total_weight = a->allConnectionsWeight() + b->allConnectionsWeight();
1918+
float connection_ratio = 0.0;
1919+
if (connection_weight) {
1920+
total_weight -= *connection_weight;
1921+
connection_ratio = *connection_weight / total_weight;
1922+
} else {
1923+
const ConnectionsMap& a_connections = a->getConnectionsMap();
1924+
auto itr = a_connections.find(b->getId());
1925+
1926+
if (itr != a_connections.end()) {
1927+
const float conn_weight = itr->second;
1928+
total_weight -= conn_weight;
1929+
connection_ratio = conn_weight / total_weight;
1930+
}
1931+
}
1932+
1933+
return connection_ratio >= minimum_connection_ratio_;
1934+
}
1935+
1936+
Cluster* ClusteringEngine::findSingleWellFormedConnectedCluster(
1937+
Cluster* target_cluster,
1938+
const std::vector<int>& small_clusters_id_list) const
1939+
{
1940+
int number_of_close_clusters = 0;
1941+
Cluster* close_cluster = nullptr;
1942+
const ConnectionsMap& target_connections
1943+
= target_cluster->getConnectionsMap();
1944+
1945+
for (auto& [cluster_id, connection_weight] : target_connections) {
1946+
Cluster* candidate = tree_->maps.id_to_cluster.at(cluster_id);
1947+
1948+
if (candidate->isIOCluster()) {
1949+
continue;
1950+
}
1951+
1952+
if (strongConnection(target_cluster, candidate, &connection_weight)) {
1953+
auto small_child_found
1954+
= std::ranges::find(small_clusters_id_list, cluster_id);
1955+
1956+
// A small child is not well-formed, so we avoid them.
1957+
if (small_child_found == small_clusters_id_list.end()) {
1958+
number_of_close_clusters++;
1959+
close_cluster = candidate;
1960+
}
1961+
}
1962+
}
1963+
1964+
if (number_of_close_clusters == 1) {
1965+
return close_cluster;
1966+
}
1967+
1968+
return nullptr;
1969+
}
1970+
18631971
bool ClusteringEngine::attemptMerge(Cluster* receiver, Cluster* incomer)
18641972
{
18651973
// Cache incomer data in case it is deleted.
@@ -1910,6 +2018,8 @@ void ClusteringEngine::clearConnections()
19102018

19112019
void ClusteringEngine::buildNetListConnections()
19122020
{
2021+
const float connection_weight = 1.0;
2022+
19132023
for (odb::dbNet* net : block_->getNets()) {
19142024
if (!isValidNet(net)) {
19152025
continue;
@@ -1929,11 +2039,9 @@ void ClusteringEngine::buildNetListConnections()
19292039
}
19302040
}
19312041

1932-
bool net_has_io_pin = false;
19332042
if (tree_->io_pads.empty()) {
19342043
for (odb::dbBTerm* bterm : net->getBTerms()) {
19352044
const int cluster_id = tree_->maps.bterm_to_cluster_id.at(bterm);
1936-
net_has_io_pin = true;
19372045

19382046
if (bterm->getIoType() == odb::dbIoType::INPUT) {
19392047
driver_cluster_id = cluster_id;
@@ -1945,13 +2053,12 @@ void ClusteringEngine::buildNetListConnections()
19452053

19462054
if (driver_cluster_id != -1 && !load_clusters_ids.empty()
19472055
&& load_clusters_ids.size() < tree_->large_net_threshold) {
1948-
const float weight = net_has_io_pin ? tree_->virtual_weight : 1.0;
19492056
Cluster* driver_cluster = tree_->maps.id_to_cluster.at(driver_cluster_id);
19502057

19512058
for (const int load_cluster_id : load_clusters_ids) {
19522059
if (load_cluster_id != driver_cluster_id) {
19532060
Cluster* load_cluster = tree_->maps.id_to_cluster.at(load_cluster_id);
1954-
connect(driver_cluster, load_cluster, weight);
2061+
connect(driver_cluster, load_cluster, connection_weight);
19552062
}
19562063
}
19572064
}
@@ -2210,8 +2317,7 @@ void ClusteringEngine::classifyMacrosByConnSignature(
22102317
continue;
22112318
}
22122319

2213-
if (macro_clusters[i]->isSameConnSignature(
2214-
*macro_clusters[j], tree_->min_net_count_for_connection)) {
2320+
if (sameConnectionSignature(macro_clusters[i], macro_clusters[j])) {
22152321
signature_class[j] = i;
22162322
}
22172323
}
@@ -2239,8 +2345,11 @@ void ClusteringEngine::classifyMacrosByInterconn(
22392345
if (interconn_class[i] == -1) {
22402346
interconn_class[i] = i;
22412347
for (int j = 0; j < macro_clusters.size(); j++) {
2242-
if (macro_clusters[i]->hasMacroConnectionWith(
2243-
*macro_clusters[j], tree_->min_net_count_for_connection)) {
2348+
if (macro_clusters[i] == macro_clusters[j]) {
2349+
continue;
2350+
}
2351+
2352+
if (strongConnection(macro_clusters[i], macro_clusters[j])) {
22442353
if (interconn_class[j] != -1) {
22452354
interconn_class[i] = interconn_class[j];
22462355
break;

src/mpl/src/clusterEngine.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ struct PhysicalHierarchy
117117

118118
int max_level{0};
119119
int large_net_threshold{0}; // used to ignore global nets
120-
int min_net_count_for_connection{0};
121120
float cluster_size_ratio{0.0f};
122121
float cluster_size_tolerance{0.0f};
123122

@@ -212,6 +211,15 @@ class ClusteringEngine
212211
bool partitionerSolutionIsFullyUnbalanced(const std::vector<int>& solution,
213212
int num_other_cluster_vertices);
214213
void mergeChildrenBelowThresholds(std::vector<Cluster*>& small_children);
214+
bool sameConnectionSignature(Cluster* a, Cluster* b) const;
215+
bool strongConnection(Cluster* a,
216+
Cluster* b,
217+
const float* connection_weight = nullptr) const;
218+
Cluster* findSingleWellFormedConnectedCluster(
219+
Cluster* target_cluster,
220+
const std::vector<int>& small_clusters_id_list) const;
221+
std::vector<int> findNeighbors(Cluster* target_cluster,
222+
Cluster* ignored_cluster) const;
215223
bool attemptMerge(Cluster* receiver, Cluster* incomer);
216224
void fetchMixedLeaves(Cluster* parent,
217225
std::vector<std::vector<Cluster*>>& mixed_leaves);
@@ -304,6 +312,8 @@ class ClusteringEngine
304312
// them to be considered connected when creating data flow.
305313
const int max_num_of_hops_ = 5;
306314

315+
const float minimum_connection_ratio_{0.08};
316+
307317
int first_io_bundle_id_{-1};
308318
IOBundleSpans io_bundle_spans_;
309319
};

src/mpl/src/hier_rtlmp.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,6 @@ void HierRTLMP::setLargeNetThreshold(int large_net_threshold)
158158
tree_->large_net_threshold = large_net_threshold;
159159
}
160160

161-
void HierRTLMP::setSignatureNetThreshold(int signature_net_threshold)
162-
{
163-
tree_->min_net_count_for_connection = signature_net_threshold;
164-
}
165-
166161
void HierRTLMP::setTargetUtil(float target_util)
167162
{
168163
target_util_ = target_util;
@@ -2170,7 +2165,7 @@ void HierRTLMP::placeMacros(Cluster* cluster)
21702165

21712166
// Large arrays need more steps to properly converge.
21722167
if (large_macro_cluster) {
2173-
perturbations_per_step *= 2;
2168+
perturbations_per_step = num_perturb_per_step_;
21742169
}
21752170
}
21762171

src/mpl/src/hier_rtlmp.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ class HierRTLMP
9292
void setMaxNumLevel(int max_num_level);
9393
void setClusterSizeRatioPerLevel(float coarsening_ratio);
9494
void setLargeNetThreshold(int large_net_threshold);
95-
void setSignatureNetThreshold(int signature_net_threshold);
9695
void setAreaWeight(float area_weight);
9796
void setOutlineWeight(float outline_weight);
9897
void setWirelengthWeight(float wirelength_weight);

src/mpl/src/mpl.i

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ bool rtl_macro_placer_cmd(const int max_num_macro,
3434
const int max_num_level,
3535
const float coarsening_ratio,
3636
const int large_net_threshold,
37-
const int signature_net_threshold,
3837
const float halo_width,
3938
const float halo_height,
4039
const float fence_lx,
@@ -66,7 +65,6 @@ bool rtl_macro_placer_cmd(const int max_num_macro,
6665
max_num_level,
6766
coarsening_ratio,
6867
large_net_threshold,
69-
signature_net_threshold,
7068
halo_width,
7169
halo_height,
7270
fence_lx,

src/mpl/src/mpl.tcl

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ sta::define_cmd_args "rtl_macro_placer" { -max_num_macro max_num_macro \
99
-max_num_level max_num_level \
1010
-coarsening_ratio coarsening_ratio \
1111
-large_net_threshold large_net_threshold \
12-
-signature_net_threshold signature_net_threshold \
1312
-halo_width halo_width \
1413
-halo_height halo_height \
1514
-fence_lx fence_lx \
@@ -35,7 +34,7 @@ proc rtl_macro_placer { args } {
3534
sta::parse_key_args "rtl_macro_placer" args \
3635
keys {-max_num_macro -min_num_macro -max_num_inst -min_num_inst -tolerance \
3736
-max_num_level -coarsening_ratio -large_net_threshold \
38-
-signature_net_threshold -halo_width -halo_height \
37+
-halo_width -halo_height \
3938
-fence_lx -fence_ly -fence_ux -fence_uy \
4039
-area_weight -outline_weight -wirelength_weight -guidance_weight -fence_weight \
4140
-boundary_weight -notch_weight \
@@ -63,7 +62,6 @@ proc rtl_macro_placer { args } {
6362
set max_num_level 2
6463
set coarsening_ratio 10.0
6564
set large_net_threshold 50
66-
set signature_net_threshold 50
6765
set halo_width 0.0
6866
set halo_height 0.0
6967
set fence_lx 0.0
@@ -110,9 +108,6 @@ proc rtl_macro_placer { args } {
110108
if { [info exists keys(-large_net_threshold)] } {
111109
set large_net_threshold $keys(-large_net_threshold)
112110
}
113-
if { [info exists keys(-signature_net_threshold)] } {
114-
set signature_net_threshold $keys(-signature_net_threshold)
115-
}
116111

117112
if { [info exists keys(-halo_width)] && [info exists keys(-halo_height)] } {
118113
set halo_width $keys(-halo_width)
@@ -189,7 +184,6 @@ proc rtl_macro_placer { args } {
189184
$max_num_level \
190185
$coarsening_ratio \
191186
$large_net_threshold \
192-
$signature_net_threshold \
193187
$halo_width \
194188
$halo_height \
195189
$fence_lx $fence_ly $fence_ux $fence_uy \

0 commit comments

Comments
 (0)