Skip to content

Commit d40fdd3

Browse files
Merge pull request The-OpenROAD-Project#7174 from arthurjolo/cts_use_different_parameters_to_cluster_macros
Cts use different parameters to cluster macros
2 parents 6366280 + fee10ea commit d40fdd3

22 files changed

+423
-337
lines changed

src/cts/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ clock_tree_synthesis
5353
[-clustering_unbalance_ratio]
5454
[-sink_clustering_size cluster_size]
5555
[-sink_clustering_max_diameter max_diameter]
56+
[-macro_clustering_size cluster_size]
57+
[-macro_clustering_max_diameter max_diameter]
5658
[-sink_clustering_enable]
5759
[-balance_levels]
5860
[-sink_clustering_levels levels]
@@ -78,8 +80,10 @@ clock_tree_synthesis
7880
| `-clustering_exponent` | Value that determines the power used on the difference between sink and means on the CKMeans clustering algorithm. The default value is `4`, and the allowed values are integers `[0, MAX_INT]`. |
7981
| `-clustering_unbalance_ratio` | Value determines each cluster's maximum capacity during CKMeans. A value of `0.5` (i.e., 50%) means that each cluster will have exactly half of all sinks for a specific region (half for each branch). The default value is `0.6`, and the allowed values are floats `[0, 1.0]`. |
8082
| `-sink_clustering_enable` | Enables pre-clustering of sinks to create one level of sub-tree before building H-tree. Each cluster is driven by buffer which becomes end point of H-tree structure. |
81-
| `-sink_clustering_size` | Specifies the maximum number of sinks per cluster. The default value is `20`, and the allowed values are integers `[0, MAX_INT]`. |
82-
| `-sink_clustering_max_diameter` | Specifies maximum diameter (in microns) of sink cluster. The default value is `50`, and the allowed values are integers `[0, MAX_INT]`. |
83+
| `-sink_clustering_size` | Specifies the maximum number of sinks per cluster for the register tree. The default value is `20`, and the allowed values are integers `[0, MAX_INT]`. |
84+
| `-sink_clustering_max_diameter` | Specifies maximum diameter (in microns) of sink cluster for the register tree. The default value is `50`, and the allowed values are integers `[0, MAX_INT]`. |
85+
| `-macro_clustering_size` | Specifies the maximum number of sinks per cluster for the macro tree. The default value is `4`, and the allowed values are integers `[0, MAX_INT]`. |
86+
| `-macro_clustering_max_diameter` | Specifies maximum diameter (in microns) of sink cluster for the macro tree. The default value is `50`, and the allowed values are integers `[0, MAX_INT]`. |
8387
| `-balance_levels` | Attempt to keep a similar number of levels in the clock tree across non-register cells (e.g., clock-gate or inverter). The default value is `False`, and the allowed values are bool. |
8488
| `-clk_nets` | String containing the names of the clock roots. If this parameter is omitted, `cts` looks for the clock roots automatically. |
8589
| `-num_static_layers` | Set the number of static layers. The default value is `0`, and the allowed values are integers `[0, MAX_INT]`. |

src/cts/src/CtsOptions.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,24 @@ class CtsOptions : public odb::dbBlockCallBackObj
192192
{
193193
sinkClusteringLevels_ = levels;
194194
}
195+
196+
double getMacroMaxDiameter() const { return macroMaxDiameter_; }
197+
void setMacroMaxDiameter(double distance)
198+
{
199+
macroMaxDiameter_ = distance;
200+
macroMaxDiameterSet_ = true;
201+
}
202+
bool isMacroMaxDiameterSet() const { return macroMaxDiameterSet_; }
203+
unsigned getMacroSinkClusteringSize() const { return macroSinkClustersSize_; }
204+
void setMacroClusteringSize(unsigned size)
205+
{
206+
macroSinkClustersSize_ = size;
207+
macroSinkClustersSizeSet_ = true;
208+
}
209+
bool isMacroSinkClusteringSizeSet() const
210+
{
211+
return macroSinkClustersSizeSet_;
212+
}
195213
unsigned getNumStaticLayers() const { return numStaticLayers_; }
196214
void setBalanceLevels(bool balance) { balanceLevels_ = balance; }
197215
bool getBalanceLevels() const { return balanceLevels_; }
@@ -282,6 +300,10 @@ class CtsOptions : public odb::dbBlockCallBackObj
282300
bool maxDiameterSet_ = false;
283301
unsigned sinkClustersSize_ = 20;
284302
bool sinkClustersSizeSet_ = false;
303+
double macroMaxDiameter_ = 50;
304+
bool macroMaxDiameterSet_ = false;
305+
unsigned macroSinkClustersSize_ = 4;
306+
bool macroSinkClustersSizeSet_ = true;
285307
bool balanceLevels_ = false;
286308
unsigned sinkClusteringLevels_ = 0;
287309
unsigned numStaticLayers_ = 0;

src/cts/src/HTreeBuilder.cpp

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ void HTreeBuilder::preSinkClustering(
3030
const unsigned clusterSize,
3131
const bool secondLevel)
3232
{
33+
bool maxDiameterSet = (type_ == TreeType::MacroTree)
34+
? options_->isMacroMaxDiameterSet()
35+
: options_->isMaxDiameterSet();
36+
unsigned clusterSizeSet = (type_ == TreeType::MacroTree)
37+
? options_->isMacroSinkClusteringSizeSet()
38+
: options_->isSinkClusteringSizeSet();
39+
40+
unsigned min_clustering_sinks = (type_ == TreeType::MacroTree)
41+
? min_clustering_macro_sinks_
42+
: min_clustering_sinks_;
43+
3344
const std::vector<std::pair<float, float>>& points = sinks;
3445
if (!secondLevel) {
3546
clock_.forEachSink([&](ClockInst& inst) {
@@ -48,7 +59,7 @@ void HTreeBuilder::preSinkClustering(
4859
});
4960
}
5061

51-
if (sinks.size() <= min_clustering_sinks_
62+
if (sinks.size() <= min_clustering_sinks
5263
|| !(options_->getSinkClustering())) {
5364
topLevelSinksClustered_ = sinks;
5465
return;
@@ -70,32 +81,30 @@ void HTreeBuilder::preSinkClustering(
7081

7182
unsigned bestClusterSize = 0;
7283
float bestDiameter = 0.0;
73-
if (options_->isSinkClusteringSizeSet() && options_->isMaxDiameterSet()) {
84+
if (clusterSizeSet && maxDiameterSet) {
7485
// clang-format off
7586
debugPrint(logger_, CTS, "clustering", 1, "**** match.run({}, {}, {}) ****",
76-
clusterSize, options_->getMaxDiameter(), wireSegmentUnit_);
87+
clusterSize, maxDiameter, wireSegmentUnit_);
7788
// clang-format on
7889
matching.run(clusterSize,
7990
maxDiameter,
8091
wireSegmentUnit_,
8192
bestClusterSize,
8293
bestDiameter);
83-
} else if (!options_->isSinkClusteringSizeSet()
84-
&& options_->isMaxDiameterSet()) {
94+
} else if (!clusterSizeSet && maxDiameterSet) {
8595
// only diameter is set, try clustering sizes of 10, 20 and 30
8696
for (unsigned clusterSize2 : clusterSizes()) {
8797
// clang-format off
8898
debugPrint(logger_, CTS, "clustering", 1, "**** match.run({}, {}, {}) ****",
89-
clusterSize2, options_->getMaxDiameter(), wireSegmentUnit_);
99+
clusterSize2, maxDiameter, wireSegmentUnit_);
90100
// clang-format on
91101
matching.run(clusterSize2,
92102
maxDiameter,
93103
wireSegmentUnit_,
94104
bestClusterSize,
95105
bestDiameter);
96106
}
97-
} else if (options_->isSinkClusteringSizeSet()
98-
&& !options_->isMaxDiameterSet()) {
107+
} else if (clusterSizeSet && !maxDiameterSet) {
99108
// only clustering size is set, try diameters of 50, 100 and 200 um
100109
for (unsigned clusterDiameter2 : clusterDiameters()) {
101110
// clang-format off
@@ -130,7 +139,7 @@ void HTreeBuilder::preSinkClustering(
130139
}
131140
}
132141

133-
if (options_->isSinkClusteringSizeSet() || options_->isMaxDiameterSet()) {
142+
if (clusterSizeSet || maxDiameterSet) {
134143
logger_->info(
135144
CTS,
136145
204,
@@ -240,6 +249,16 @@ void HTreeBuilder::initSinkRegion()
240249
const int dbUnits = options_->getDbUnits();
241250
wireSegmentUnit_ = wireSegmentUnitInDbu;
242251

252+
double clusterDiameter = (type_ == TreeType::MacroTree)
253+
? options_->getMacroMaxDiameter()
254+
: options_->getMaxDiameter();
255+
unsigned clusterSize = (type_ == TreeType::MacroTree)
256+
? options_->getMacroSinkClusteringSize()
257+
: options_->getSinkClusteringSize();
258+
unsigned min_clustering_sinks = (type_ == TreeType::MacroTree)
259+
? min_clustering_macro_sinks_
260+
: min_clustering_sinks_;
261+
243262
logger_->info(CTS,
244263
20,
245264
" Wire segment unit: {} dbu ({} um).",
@@ -270,18 +289,16 @@ void HTreeBuilder::initSinkRegion()
270289
std::vector<const ClockInst*> sinkInsts;
271290
initTopLevelSinks(topLevelSinks, sinkInsts);
272291

273-
const float maxDiameter
274-
= (options_->getMaxDiameter() * dbUnits) / wireSegmentUnit_;
292+
const float maxDiameter = (clusterDiameter * dbUnits) / wireSegmentUnit_;
275293
// clang-format off
276294
debugPrint(logger_, CTS, "clustering", 1, "maxDiameter={:0.3f} = "
277295
"origMaxDiam={} * dbUnits={} / wireSegmentUnit_={}",
278-
maxDiameter, options_->getMaxDiameter(), dbUnits,
296+
maxDiameter, clusterDiameter, dbUnits,
279297
wireSegmentUnit_);
280298
// clang-format on
281299

282-
preSinkClustering(
283-
topLevelSinks, sinkInsts, maxDiameter, options_->getSinkClusteringSize());
284-
if (topLevelSinks.size() <= min_clustering_sinks_
300+
preSinkClustering(topLevelSinks, sinkInsts, maxDiameter, clusterSize);
301+
if (topLevelSinks.size() <= min_clustering_sinks
285302
|| !(options_->getSinkClustering())) {
286303
Box<int> sinkRegionDbu = clock_.computeSinkRegion();
287304
logger_->info(CTS, 23, " Original sink region: {}.", sinkRegionDbu);
@@ -296,7 +313,7 @@ void HTreeBuilder::initSinkRegion()
296313
preSinkClustering(secondLevelLocs,
297314
secondLevelInsts,
298315
maxDiameter * 4,
299-
std::ceil(std::sqrt(options_->getSinkClusteringSize())),
316+
std::ceil(std::sqrt(clusterSize)),
300317
true);
301318
}
302319
sinkRegion_ = clock_.computeSinkRegionClustered(topLevelSinksClustered_);
@@ -963,11 +980,13 @@ void HTreeBuilder::legalizeDummy()
963980
Point<double>& branchPoint = topology.getBranchingPoint(idx);
964981
unsigned parentIdx = topology.getBranchingPointParentIdx(idx);
965982

983+
// clang-format off
966984
Point<double> parentPoint
967985
= (levelIdx == 0)
968986
? topLevelBufferLoc
969987
: topologyForEachLevel_[levelIdx - 1].getBranchingPoint(
970988
parentIdx);
989+
// clang-format on
971990

972991
const std::vector<Point<double>>& sinks
973992
= topology.getBranchSinksLocations(idx);
@@ -1049,11 +1068,13 @@ void HTreeBuilder::legalize()
10491068
Point<double>& branchPoint = topology.getBranchingPoint(bufferIdx);
10501069
unsigned parentIdx = topology.getBranchingPointParentIdx(bufferIdx);
10511070

1071+
// clang-format off
10521072
Point<double> parentPoint
10531073
= (levelIdx == 0)
10541074
? newTopBufferLoc
10551075
: topologyForEachLevel_[levelIdx - 1].getBranchingPoint(
10561076
parentIdx);
1077+
// clang-format on
10571078

10581079
odb::Direction2D::Value branch_point_dir;
10591080
if (isHorizontal(levelIdx + 1)) {
@@ -1150,20 +1171,32 @@ void HTreeBuilder::legalize()
11501171

11511172
void HTreeBuilder::run()
11521173
{
1174+
double clusterDiameter = (type_ == TreeType::MacroTree)
1175+
? options_->getMacroMaxDiameter()
1176+
: options_->getMaxDiameter();
1177+
unsigned clusterSize = (type_ == TreeType::MacroTree)
1178+
? options_->getMacroSinkClusteringSize()
1179+
: options_->getSinkClusteringSize();
1180+
bool useMaxCap = (type_ == TreeType::MacroTree)
1181+
? false
1182+
: options_->getSinkClusteringUseMaxCap();
1183+
11531184
logger_->info(
11541185
CTS, 27, "Generating H-Tree topology for net {}.", clock_.getName());
11551186
logger_->info(CTS, 28, " Total number of sinks: {}.", clock_.getNumSinks());
11561187
if (options_->getSinkClustering()) {
1157-
if (options_->getSinkClusteringUseMaxCap()) {
1188+
if (useMaxCap) {
11581189
logger_->info(
11591190
CTS, 90, " Sinks will be clustered based on buffer max cap.");
11601191
} else {
1161-
logger_->info(CTS,
1162-
29,
1163-
" Sinks will be clustered in groups of up to {} and with "
1164-
"maximum cluster diameter of {:.1f} um.",
1165-
options_->getSinkClusteringSize(),
1166-
options_->getMaxDiameter());
1192+
logger_->info(
1193+
CTS,
1194+
29,
1195+
" {} sinks will be clustered in groups of up to {} and with "
1196+
"maximum cluster diameter of {:.1f} um.",
1197+
type_ == TreeType::MacroTree ? "Macro " : "Register",
1198+
clusterSize,
1199+
clusterDiameter);
11671200
}
11681201
}
11691202
logger_->info(
@@ -1258,6 +1291,7 @@ std::string HTreeBuilder::plotHTree()
12581291
for (int levelIdx = 0; levelIdx < topologyForEachLevel_.size(); ++levelIdx) {
12591292
LevelTopology& topology = topologyForEachLevel_[levelIdx];
12601293

1294+
// clang-format off
12611295
topology.forEachBranchingPoint(
12621296
[&](unsigned idx, Point<double> branchPoint) {
12631297
unsigned parentIdx = topology.getBranchingPointParentIdx(idx);
@@ -1281,6 +1315,7 @@ std::string HTreeBuilder::plotHTree()
12811315
file << levelIdx << " " << x1 << " " << y1 << " " << x2 << " " << y2;
12821316
file << " " << name << '\n';
12831317
});
1318+
// clang-format on
12841319
}
12851320

12861321
LevelTopology& leafTopology = topologyForEachLevel_.back();
@@ -1309,8 +1344,11 @@ std::string HTreeBuilder::plotHTree()
13091344
unsigned HTreeBuilder::computeNumberOfSinksPerSubRegion(
13101345
const unsigned level) const
13111346
{
1347+
unsigned min_clustering_sinks = (type_ == TreeType::MacroTree)
1348+
? min_clustering_macro_sinks_
1349+
: min_clustering_sinks_;
13121350
unsigned totalNumSinks = 0;
1313-
if (clock_.getNumSinks() > min_clustering_sinks_
1351+
if (clock_.getNumSinks() > min_clustering_sinks
13141352
&& options_->getSinkClustering()) {
13151353
totalNumSinks = topLevelSinksClustered_.size();
13161354
} else {
@@ -2052,11 +2090,13 @@ void HTreeBuilder::printHTree()
20522090
Point<double>& branchPoint = topology.getBranchingPoint(idx);
20532091
unsigned parentIdx = topology.getBranchingPointParentIdx(idx);
20542092

2093+
// clang-format off
20552094
Point<double> parentPoint
20562095
= (levelIdx == 0)
20572096
? topLevelBufferLoc
20582097
: topologyForEachLevel_[levelIdx - 1].getBranchingPoint(
20592098
parentIdx);
2099+
// clang-format on
20602100

20612101
const std::vector<Point<double>>& sinks
20622102
= topology.getBranchSinksLocations(idx);

src/cts/src/HTreeBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ class HTreeBuilder : public TreeBuilder
372372
unsigned minLengthSinkRegion_ = 0;
373373
unsigned clockTreeMaxDepth_ = 0;
374374
static constexpr int min_clustering_sinks_ = 200;
375+
static constexpr int min_clustering_macro_sinks_ = 10;
375376
std::vector<unsigned> clusterDiameters_ = {50, 100, 200};
376377
std::vector<unsigned> clusterSizes_ = {10, 20, 30};
377378
};

src/cts/src/SinkClustering.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ SinkClustering::SinkClustering(const CtsOptions* options,
3131
techChar_(techChar),
3232
maxInternalDiameter_(10),
3333
capPerUnit_(0.0),
34-
useMaxCapLimit_(options->getSinkClusteringUseMaxCap()),
34+
useMaxCapLimit_((HTree->getTreeType() == TreeType::MacroTree)
35+
? false
36+
: options->getSinkClusteringUseMaxCap()),
3537
scaleFactor_(1),
3638
HTree_(HTree)
3739
{

src/cts/src/TreeBuilder.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,28 @@ void TreeBuilder::mergeBlockages()
2626
namespace gtl = boost::polygon;
2727
using boost::polygon::operators::operator+=;
2828

29+
uint macros_max_dx = 0, macros_max_dy = 0;
2930
odb::dbBlock* block = db_->getChip()->getBlock();
3031
gtl::polygon_90_set_data<int> blockage_polygons;
3132
// Add the macros into the polygon set
3233
for (odb::dbInst* inst : block->getInsts()) {
3334
if (inst->getMaster()->getType().isBlock()
3435
&& inst->getPlacementStatus().isPlaced()) {
36+
macros_max_dx = std::max(macros_max_dx, inst->getBBox()->getDX());
37+
macros_max_dy = std::max(macros_max_dy, inst->getBBox()->getDY());
3538
blockage_polygons += inst->getBBox()->getBox();
3639
}
3740
}
3841

42+
// Set macros clustering diameter as 2 * macros highest dimention.
43+
double max_diameter
44+
= block->dbuToMicrons(2 * std::max(macros_max_dx, macros_max_dy));
45+
46+
if (max_diameter && !options_->isMacroMaxDiameterSet()) {
47+
options_->setMacroMaxDiameter(
48+
std::max(max_diameter, options_->getMacroMaxDiameter()));
49+
}
50+
3951
// Add the hard blockages into the polygon set
4052
for (odb::dbBlockage* blockage : block->getBlockages()) {
4153
if (!blockage->isSoft()) {

src/cts/src/TritonCTS.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,7 @@ bool TritonCTS::separateMacroRegSinks(
11871187
}
11881188
}
11891189
}
1190+
11901191
return true;
11911192
}
11921193

src/cts/src/TritonCTS.i

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,18 @@ set_clustering_diameter(double distance)
144144
getTritonCts()->getParms()->setMaxDiameter(distance);
145145
}
146146

147+
void
148+
set_macro_clustering_size(unsigned size)
149+
{
150+
getTritonCts()->getParms()->setMacroClusteringSize(size);
151+
}
152+
153+
void
154+
set_macro_clustering_diameter(double distance)
155+
{
156+
getTritonCts()->getParms()->setMacroMaxDiameter(distance);
157+
}
158+
147159
void
148160
set_num_static_layers(unsigned num)
149161
{

0 commit comments

Comments
 (0)