Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/mpl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ rtl_macro_placer
[-max_num_level max_num_level]
[-coarsening_ratio coarsening_ratio]
[-large_net_threshold large_net_threshold]
[-signature_net_threshold signature_net_threshold]
[-halo_width halo_width]
[-halo_height halo_height]
[-fence_lx fence_lx]
Expand Down Expand Up @@ -59,7 +58,6 @@ rtl_macro_placer
| `-max_num_level` | Maximum depth of physical hierarchical tree. The default value is `2`, and the allowed values are integers `[0, MAX_INT]`. |
| `-coarsening_ratio` | The larger the coarsening_ratio, the faster the convergence process. The allowed values are floats, and the default value is `10.0`. |
| `-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]`. |
| `-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]`. |
| `-halo_width` | Horizontal/vertical halo around macros (microns). The allowed values are floats, and the default value is `0.0`. |
| `-fence_lx`, `-fence_ly`, `-fence_ux`, `-fence_uy` | Defines the global fence bounding box coordinates. The default values are the core area coordinates). |
| `-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`. |
Expand Down
1 change: 0 additions & 1 deletion src/mpl/include/mpl/rtl_mp.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class MacroPlacer
int max_num_level,
float coarsening_ratio,
int large_net_threshold,
int signature_net_threshold,
float halo_width,
float halo_height,
float fence_lx,
Expand Down
164 changes: 137 additions & 27 deletions src/mpl/src/clusterEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1743,23 +1743,10 @@ void ClusteringEngine::mergeChildrenBelowThresholds(
}
// Firstly we perform Type 1 merge
for (int i = 0; i < num_small_children; i++) {
const int cluster_id = small_children[i]->getCloseCluster(
small_children_ids, tree_->min_net_count_for_connection);
debugPrint(
logger_,
MPL,
"multilevel_autoclustering",
1,
"Candidate cluster: {} - {}",
small_children[i]->getName(),
(cluster_id != -1 ? tree_->maps.id_to_cluster[cluster_id]->getName()
: " "));
if (cluster_id != -1
&& !tree_->maps.id_to_cluster[cluster_id]->isIOCluster()) {
Cluster* close_cluster = tree_->maps.id_to_cluster[cluster_id];
if (attemptMerge(close_cluster, small_children[i])) {
cluster_class[i] = close_cluster->getId();
}
Cluster* close_cluster = findSingleWellFormedConnectedCluster(
small_children[i], small_children_ids);
if (close_cluster && attemptMerge(close_cluster, small_children[i])) {
cluster_class[i] = close_cluster->getId();
}
}

Expand All @@ -1772,8 +1759,7 @@ void ClusteringEngine::mergeChildrenBelowThresholds(
continue;
}

if (small_children[i]->isSameConnSignature(
*small_children[j], tree_->min_net_count_for_connection)) {
if (sameConnectionSignature(small_children[i], small_children[j])) {
if (attemptMerge(small_children[i], small_children[j])) {
cluster_class[j] = i;
} else {
Expand Down Expand Up @@ -1860,6 +1846,129 @@ void ClusteringEngine::mergeChildrenBelowThresholds(
"Finished merging clusters");
}

bool ClusteringEngine::sameConnectionSignature(Cluster* a, Cluster* b) const
{
std::vector<int> a_neighbors = findNeighbors(a, /* ignore */ b);
if (a_neighbors.empty()) {
return false;
}

std::vector<int> b_neighbors = findNeighbors(b, /* ignore */ a);
if (b_neighbors.size() != a_neighbors.size()) {
return false;
}

std::sort(a_neighbors.begin(), a_neighbors.end());
std::sort(b_neighbors.begin(), b_neighbors.end());

for (int i = 0; i < a_neighbors.size(); i++) {
if (a_neighbors[i] != b_neighbors[i]) {
return false;
}
}

return true;
}

std::vector<int> ClusteringEngine::findNeighbors(Cluster* target_cluster,
Cluster* ignored_cluster) const
{
std::vector<int> neighbors;
const ConnectionsMap& target_connections
= target_cluster->getConnectionsMap();

for (const auto& [cluster_id, connection_weight] : target_connections) {
if (cluster_id == target_cluster->getId()) {
logger_->error(MPL,
53,
"Cluster {} is connected to itself.",
target_cluster->getName());
}

if (cluster_id == ignored_cluster->getId()) {
continue;
}

const float connection_ratio
= connection_weight / target_cluster->allConnectionsWeight();

if (connection_ratio >= minimum_connection_ratio_) {
neighbors.push_back(cluster_id);
}
}

return neighbors;
}

bool ClusteringEngine::strongConnection(Cluster* a,
Cluster* b,
const float* connection_weight) const
{
if (a == b) {
logger_->error(
MPL,
61,
"Attempt to evaluate if cluster {} has strong connection with itself.",
a->getName());
}

// Attention that we need to subtract the weight of the connection that
// we're evaluating otherwise we'll be taking it into account twice.
float total_weight = a->allConnectionsWeight() + b->allConnectionsWeight();
float connection_ratio = 0.0;
if (connection_weight) {
total_weight -= *connection_weight;
connection_ratio = *connection_weight / total_weight;
} else {
const ConnectionsMap& a_connections = a->getConnectionsMap();
auto itr = a_connections.find(b->getId());

if (itr != a_connections.end()) {
const float conn_weight = itr->second;
total_weight -= conn_weight;
connection_ratio = conn_weight / total_weight;
}
}

return connection_ratio >= minimum_connection_ratio_;
}

Cluster* ClusteringEngine::findSingleWellFormedConnectedCluster(
Cluster* target_cluster,
const std::vector<int>& small_clusters_id_list) const
{
int number_of_close_clusters = 0;
Cluster* close_cluster = nullptr;
const ConnectionsMap& target_connections
= target_cluster->getConnectionsMap();

for (auto& [cluster_id, connection_weight] : target_connections) {
Cluster* candidate = tree_->maps.id_to_cluster.at(cluster_id);

if (candidate->isIOCluster()) {
continue;
}

if (strongConnection(target_cluster, candidate, &connection_weight)) {
auto small_child_found = std::find(small_clusters_id_list.begin(),
small_clusters_id_list.end(),
cluster_id);

// A small child is not well-formed, so we avoid them.
if (small_child_found == small_clusters_id_list.end()) {
number_of_close_clusters++;
close_cluster = candidate;
}
}
}

if (number_of_close_clusters == 1) {
return close_cluster;
}

return nullptr;
}

bool ClusteringEngine::attemptMerge(Cluster* receiver, Cluster* incomer)
{
// Cache incomer data in case it is deleted.
Expand Down Expand Up @@ -1910,6 +2019,8 @@ void ClusteringEngine::clearConnections()

void ClusteringEngine::buildNetListConnections()
{
const float connection_weight = 1.0;

for (odb::dbNet* net : block_->getNets()) {
if (!isValidNet(net)) {
continue;
Expand All @@ -1929,11 +2040,9 @@ void ClusteringEngine::buildNetListConnections()
}
}

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

if (bterm->getIoType() == odb::dbIoType::INPUT) {
driver_cluster_id = cluster_id;
Expand All @@ -1945,13 +2054,12 @@ void ClusteringEngine::buildNetListConnections()

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

for (const int load_cluster_id : load_clusters_ids) {
if (load_cluster_id != driver_cluster_id) {
Cluster* load_cluster = tree_->maps.id_to_cluster.at(load_cluster_id);
connect(driver_cluster, load_cluster, weight);
connect(driver_cluster, load_cluster, connection_weight);
}
}
}
Expand Down Expand Up @@ -2210,8 +2318,7 @@ void ClusteringEngine::classifyMacrosByConnSignature(
continue;
}

if (macro_clusters[i]->isSameConnSignature(
*macro_clusters[j], tree_->min_net_count_for_connection)) {
if (sameConnectionSignature(macro_clusters[i], macro_clusters[j])) {
signature_class[j] = i;
}
}
Expand Down Expand Up @@ -2239,8 +2346,11 @@ void ClusteringEngine::classifyMacrosByInterconn(
if (interconn_class[i] == -1) {
interconn_class[i] = i;
for (int j = 0; j < macro_clusters.size(); j++) {
if (macro_clusters[i]->hasMacroConnectionWith(
*macro_clusters[j], tree_->min_net_count_for_connection)) {
if (macro_clusters[i] == macro_clusters[j]) {
continue;
}

if (strongConnection(macro_clusters[i], macro_clusters[j])) {
if (interconn_class[j] != -1) {
interconn_class[i] = interconn_class[j];
break;
Expand Down
12 changes: 11 additions & 1 deletion src/mpl/src/clusterEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ struct PhysicalHierarchy

int max_level{0};
int large_net_threshold{0}; // used to ignore global nets
int min_net_count_for_connection{0};
float cluster_size_ratio{0.0f};
float cluster_size_tolerance{0.0f};

Expand Down Expand Up @@ -212,6 +211,15 @@ class ClusteringEngine
bool partitionerSolutionIsFullyUnbalanced(const std::vector<int>& solution,
int num_other_cluster_vertices);
void mergeChildrenBelowThresholds(std::vector<Cluster*>& small_children);
bool sameConnectionSignature(Cluster* a, Cluster* b) const;
bool strongConnection(Cluster* a,
Cluster* b,
const float* connection_weight = nullptr) const;
Cluster* findSingleWellFormedConnectedCluster(
Cluster* target_cluster,
const std::vector<int>& small_clusters_id_list) const;
std::vector<int> findNeighbors(Cluster* target_cluster,
Cluster* ignored_cluster) const;
bool attemptMerge(Cluster* receiver, Cluster* incomer);
void fetchMixedLeaves(Cluster* parent,
std::vector<std::vector<Cluster*>>& mixed_leaves);
Expand Down Expand Up @@ -304,6 +312,8 @@ class ClusteringEngine
// them to be considered connected when creating data flow.
const int max_num_of_hops_ = 5;

const float minimum_connection_ratio_{0.08};

int first_io_bundle_id_{-1};
IOBundleSpans io_bundle_spans_;
};
Expand Down
7 changes: 1 addition & 6 deletions src/mpl/src/hier_rtlmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,6 @@ void HierRTLMP::setLargeNetThreshold(int large_net_threshold)
tree_->large_net_threshold = large_net_threshold;
}

void HierRTLMP::setSignatureNetThreshold(int signature_net_threshold)
{
tree_->min_net_count_for_connection = signature_net_threshold;
}

void HierRTLMP::setTargetUtil(float target_util)
{
target_util_ = target_util;
Expand Down Expand Up @@ -2170,7 +2165,7 @@ void HierRTLMP::placeMacros(Cluster* cluster)

// Large arrays need more steps to properly converge.
if (large_macro_cluster) {
perturbations_per_step *= 2;
perturbations_per_step = num_perturb_per_step_;
}
}

Expand Down
1 change: 0 additions & 1 deletion src/mpl/src/hier_rtlmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class HierRTLMP
void setMaxNumLevel(int max_num_level);
void setClusterSizeRatioPerLevel(float coarsening_ratio);
void setLargeNetThreshold(int large_net_threshold);
void setSignatureNetThreshold(int signature_net_threshold);
void setAreaWeight(float area_weight);
void setOutlineWeight(float outline_weight);
void setWirelengthWeight(float wirelength_weight);
Expand Down
2 changes: 0 additions & 2 deletions src/mpl/src/mpl.i
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ bool rtl_macro_placer_cmd(const int max_num_macro,
const int max_num_level,
const float coarsening_ratio,
const int large_net_threshold,
const int signature_net_threshold,
const float halo_width,
const float halo_height,
const float fence_lx,
Expand Down Expand Up @@ -66,7 +65,6 @@ bool rtl_macro_placer_cmd(const int max_num_macro,
max_num_level,
coarsening_ratio,
large_net_threshold,
signature_net_threshold,
halo_width,
halo_height,
fence_lx,
Expand Down
8 changes: 1 addition & 7 deletions src/mpl/src/mpl.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ sta::define_cmd_args "rtl_macro_placer" { -max_num_macro max_num_macro \
-max_num_level max_num_level \
-coarsening_ratio coarsening_ratio \
-large_net_threshold large_net_threshold \
-signature_net_threshold signature_net_threshold \
-halo_width halo_width \
-halo_height halo_height \
-fence_lx fence_lx \
Expand All @@ -35,7 +34,7 @@ proc rtl_macro_placer { args } {
sta::parse_key_args "rtl_macro_placer" args \
keys {-max_num_macro -min_num_macro -max_num_inst -min_num_inst -tolerance \
-max_num_level -coarsening_ratio -large_net_threshold \
-signature_net_threshold -halo_width -halo_height \
-halo_width -halo_height \
-fence_lx -fence_ly -fence_ux -fence_uy \
-area_weight -outline_weight -wirelength_weight -guidance_weight -fence_weight \
-boundary_weight -notch_weight \
Expand Down Expand Up @@ -63,7 +62,6 @@ proc rtl_macro_placer { args } {
set max_num_level 2
set coarsening_ratio 10.0
set large_net_threshold 50
set signature_net_threshold 50
set halo_width 0.0
set halo_height 0.0
set fence_lx 0.0
Expand Down Expand Up @@ -110,9 +108,6 @@ proc rtl_macro_placer { args } {
if { [info exists keys(-large_net_threshold)] } {
set large_net_threshold $keys(-large_net_threshold)
}
if { [info exists keys(-signature_net_threshold)] } {
set signature_net_threshold $keys(-signature_net_threshold)
}

if { [info exists keys(-halo_width)] && [info exists keys(-halo_height)] } {
set halo_width $keys(-halo_width)
Expand Down Expand Up @@ -189,7 +184,6 @@ proc rtl_macro_placer { args } {
$max_num_level \
$coarsening_ratio \
$large_net_threshold \
$signature_net_threshold \
$halo_width \
$halo_height \
$fence_lx $fence_ly $fence_ux $fence_uy \
Expand Down
Loading
Loading