1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2018-2020, The Regents of the University of California
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 // list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 // this list of conditions and the following disclaimer in the documentation
15 // and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE
25 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 ///////////////////////////////////////////////////////////////////////////////
33
34 #include "initialPlace.h"
35 #include "placerBase.h"
36 #include <iostream>
37
38 #include <Eigen/IterativeLinearSolvers>
39
40 #include "plot.h"
41 #include "graphics.h"
42
43 #include "utl/Logger.h"
44
45 namespace gpl {
46 using namespace std;
47
48 using Eigen::BiCGSTAB;
49 using Eigen::IdentityPreconditioner;
50 using utl::GPL;
51
52 typedef Eigen::Triplet< float > T;
53
InitialPlaceVars()54 InitialPlaceVars::InitialPlaceVars()
55 {
56 reset();
57 }
58
reset()59 void InitialPlaceVars::reset() {
60 maxIter = 20;
61 minDiffLength = 1500;
62 maxSolverIter = 100;
63 maxFanout = 200;
64 netWeightScale = 800.0;
65 incrementalPlaceMode = false;
66 debug = false;
67 }
68
InitialPlace()69 InitialPlace::InitialPlace()
70 : ipVars_(), pb_(nullptr), log_(nullptr) {}
71
InitialPlace(InitialPlaceVars ipVars,std::shared_ptr<PlacerBase> pb,utl::Logger * log)72 InitialPlace::InitialPlace(InitialPlaceVars ipVars,
73 std::shared_ptr<PlacerBase> pb,
74 utl::Logger* log)
75 : ipVars_(ipVars), pb_(pb), log_(log)
76 {
77 }
78
~InitialPlace()79 InitialPlace::~InitialPlace() {
80 reset();
81 }
82
reset()83 void InitialPlace::reset() {
84 pb_ = nullptr;
85 ipVars_.reset();
86 }
87
88 #ifdef ENABLE_CIMG_LIB
89 static PlotEnv pe;
90 #endif
91
doBicgstabPlace()92 void InitialPlace::doBicgstabPlace() {
93 float errorX = 0.0f, errorY = 0.0f;
94
95 #ifdef ENABLE_CIMG_LIB
96 pe.setPlacerBase(pb_);
97 pe.setLogger(log_);
98 pe.Init();
99 #endif
100
101 std::unique_ptr<Graphics> graphics;
102 if (ipVars_.debug && Graphics::guiActive()) {
103 graphics = make_unique<Graphics>(log_, pb_, this);
104 }
105
106 // normally, initial place will place all cells in the centers.
107 if( !ipVars_.incrementalPlaceMode ) {
108 placeInstsCenter();
109 }
110
111 // set ExtId for idx reference // easy recovery
112 setPlaceInstExtId();
113 for(int i=1; i<=ipVars_.maxIter; i++) {
114 updatePinInfo();
115 createSparseMatrix();
116
117 // BiCGSTAB solver for initial place
118 BiCGSTAB< SMatrix, IdentityPreconditioner > solver;
119 solver.setMaxIterations(ipVars_.maxSolverIter);
120 solver.compute(placeInstForceMatrixX_);
121 instLocVecX_ = solver.solveWithGuess(fixedInstForceVecX_, instLocVecX_);
122 errorX = solver.error();
123
124 solver.compute(placeInstForceMatrixY_);
125 instLocVecY_ = solver.solveWithGuess(fixedInstForceVecY_, instLocVecY_);
126 errorY = solver.error();
127
128 log_->report("[InitialPlace] Iter: {} CG Error: {:0.8f} HPWL: {}",
129 i, max(errorX, errorY), pb_->hpwl());
130 updateCoordi();
131
132 #ifdef ENABLE_CIMG_LIB
133 if (PlotEnv::isPlotEnabled()) pe.SaveCellPlotAsJPEG(
134 string("InitPlace ") + to_string(i), false,
135 string("ip_") + to_string(i));
136 #endif
137
138 if (graphics) {
139 graphics->cellPlot(true);
140 }
141
142 if( max(errorX, errorY) <= 1e-5 && i >= 5 ) {
143 break;
144 }
145 }
146 }
147
148 // starting point of initial place is center.
placeInstsCenter()149 void InitialPlace::placeInstsCenter() {
150 const int centerX = pb_->die().coreCx();
151 const int centerY = pb_->die().coreCy();
152
153 for(auto& inst: pb_->placeInsts()) {
154 inst->setCenterLocation(centerX, centerY);
155 }
156 }
157
setPlaceInstExtId()158 void InitialPlace::setPlaceInstExtId() {
159 // reset ExtId for all instances
160 for(auto& inst : pb_->insts()) {
161 inst->setExtId(INT_MAX);
162 }
163 // set index only with place-able instances
164 for(auto& inst : pb_->placeInsts()) {
165 inst->setExtId(&inst - &(pb_->placeInsts()[0]));
166 }
167 }
168
updatePinInfo()169 void InitialPlace::updatePinInfo() {
170 // reset all MinMax attributes
171 for(auto& pin : pb_->pins()) {
172 pin->unsetMinPinX();
173 pin->unsetMinPinY();
174 pin->unsetMaxPinX();
175 pin->unsetMaxPinY();
176 }
177
178 for(auto& net : pb_->nets()) {
179 Pin* pinMinX = nullptr, *pinMinY = nullptr;
180 Pin* pinMaxX = nullptr, *pinMaxY = nullptr;
181 int lx = INT_MAX, ly = INT_MAX;
182 int ux = INT_MIN, uy = INT_MIN;
183
184 // Mark B2B info on Pin structures
185 for(auto& pin : net->pins()) {
186 if( lx > pin->cx() ) {
187 if( pinMinX ) {
188 pinMinX->unsetMinPinX();
189 }
190 lx = pin->cx();
191 pinMinX = pin;
192 pinMinX->setMinPinX();
193 }
194
195 if( ux < pin->cx() ) {
196 if( pinMaxX ) {
197 pinMaxX->unsetMaxPinX();
198 }
199 ux = pin->cx();
200 pinMaxX = pin;
201 pinMaxX->setMaxPinX();
202 }
203
204 if( ly > pin->cy() ) {
205 if( pinMinY ) {
206 pinMinY->unsetMinPinY();
207 }
208 ly = pin->cy();
209 pinMinY = pin;
210 pinMinY->setMinPinY();
211 }
212
213 if( uy < pin->cy() ) {
214 if( pinMaxY ) {
215 pinMaxY->unsetMaxPinY();
216 }
217 uy = pin->cy();
218 pinMaxY = pin;
219 pinMaxY->setMaxPinY();
220 }
221 }
222 }
223 }
224
225 // solve placeInstForceMatrixX_ * xcg_x_ = xcg_b_ and placeInstForceMatrixY_ * ycg_x_ = ycg_b_ eq.
createSparseMatrix()226 void InitialPlace::createSparseMatrix() {
227 const int placeCnt = pb_->placeInsts().size();
228 instLocVecX_.resize( placeCnt );
229 fixedInstForceVecX_.resize( placeCnt );
230 instLocVecY_.resize( placeCnt );
231 fixedInstForceVecY_.resize( placeCnt );
232
233 placeInstForceMatrixX_.resize( placeCnt, placeCnt );
234 placeInstForceMatrixY_.resize( placeCnt, placeCnt );
235
236
237 //
238 // listX and listY is a temporary vector that have tuples, (idx1, idx2, val)
239 //
240 // listX finally becomes placeInstForceMatrixX_
241 // listY finally becomes placeInstForceMatrixY_
242 //
243 // The triplet vector is recommended usages
244 // to fill in SparseMatrix from Eigen docs.
245 //
246
247 vector< T > listX, listY;
248 listX.reserve(1000000);
249 listY.reserve(1000000);
250
251 // initialize vector
252 for(auto& inst : pb_->placeInsts()) {
253 int idx = inst->extId();
254
255 instLocVecX_(idx) = inst->cx();
256 instLocVecY_(idx) = inst->cy();
257
258 fixedInstForceVecX_(idx) = fixedInstForceVecY_(idx) = 0;
259 }
260
261 // for each net
262 for(auto& net : pb_->nets()) {
263
264 // skip for small nets.
265 if( net->pins().size() <= 1 ) {
266 continue;
267 }
268
269 // escape long time cals on huge fanout.
270 //
271 if( net->pins().size() >= ipVars_.maxFanout) {
272 continue;
273 }
274
275 float netWeight = ipVars_.netWeightScale
276 / (net->pins().size() - 1);
277 //cout << "net: " << net.net()->getConstName() << endl;
278
279 // foreach two pins in single nets.
280 auto& pins = net->pins();
281 for(int pinIdx1 = 1; pinIdx1 < pins.size(); ++pinIdx1) {
282 Pin* pin1 = pins[pinIdx1];
283 for(int pinIdx2 = 0; pinIdx2 < pinIdx1; ++pinIdx2) {
284 Pin* pin2 = pins[pinIdx2];
285
286 // no need to fill in when instance is same
287 if( pin1->instance() == pin2->instance() ) {
288 continue;
289 }
290
291 // B2B modeling on min/maxX pins.
292 if( pin1->isMinPinX() || pin1->isMaxPinX() ||
293 pin2->isMinPinX() || pin2->isMaxPinX() ) {
294 int diffX = abs(pin1->cx() - pin2->cx());
295 float weightX = 0;
296 if( diffX > ipVars_.minDiffLength ) {
297 weightX = netWeight / diffX;
298 }
299 else {
300 weightX = netWeight
301 / ipVars_.minDiffLength;
302 }
303 //cout << weightX << endl;
304
305 // both pin cames from instance
306 if( pin1->isPlaceInstConnected()
307 && pin2->isPlaceInstConnected() ) {
308 const int inst1 = pin1->instance()->extId();
309 const int inst2 = pin2->instance()->extId();
310 //cout << "inst: " << inst1 << " " << inst2 << endl;
311
312 listX.push_back( T(inst1, inst1, weightX) );
313 listX.push_back( T(inst2, inst2, weightX) );
314
315 listX.push_back( T(inst1, inst2, -weightX) );
316 listX.push_back( T(inst2, inst1, -weightX) );
317
318 //cout << pin1->cx() << " "
319 // << pin1->instance()->cx() << endl;
320 fixedInstForceVecX_(inst1) +=
321 -weightX * (
322 (pin1->cx() - pin1->instance()->cx()) -
323 (pin2->cx() - pin2->instance()->cx()));
324
325 fixedInstForceVecX_(inst2) +=
326 -weightX * (
327 (pin2->cx() - pin2->instance()->cx()) -
328 (pin1->cx() - pin1->instance()->cx()));
329 }
330 // pin1 from IO port / pin2 from Instance
331 else if( !pin1->isPlaceInstConnected()
332 && pin2->isPlaceInstConnected() ) {
333 const int inst2 = pin2->instance()->extId();
334 //cout << "inst2: " << inst2 << endl;
335 listX.push_back( T(inst2, inst2, weightX) );
336 fixedInstForceVecX_(inst2) += weightX *
337 ( pin1->cx() -
338 ( pin2->cx() - pin2->instance()->cx()) );
339 }
340 // pin1 from Instance / pin2 from IO port
341 else if( pin1->isPlaceInstConnected()
342 && !pin2->isPlaceInstConnected() ) {
343 const int inst1 = pin1->instance()->extId();
344 //cout << "inst1: " << inst1 << endl;
345 listX.push_back( T(inst1, inst1, weightX) );
346 fixedInstForceVecX_(inst1) += weightX *
347 ( pin2->cx() -
348 ( pin1->cx() - pin1->instance()->cx()) );
349 }
350 }
351
352 // B2B modeling on min/maxY pins.
353 if( pin1->isMinPinY() || pin1->isMaxPinY() ||
354 pin2->isMinPinY() || pin2->isMaxPinY() ) {
355
356 int diffY = abs(pin1->cy() - pin2->cy());
357 float weightY = 0;
358 if( diffY > ipVars_.minDiffLength ) {
359 weightY = netWeight / diffY;
360 }
361 else {
362 weightY = netWeight
363 / ipVars_.minDiffLength;
364 }
365
366 // both pin cames from instance
367 if( pin1->isPlaceInstConnected()
368 && pin2->isPlaceInstConnected() ) {
369 const int inst1 = pin1->instance()->extId();
370 const int inst2 = pin2->instance()->extId();
371
372 listY.push_back( T(inst1, inst1, weightY) );
373 listY.push_back( T(inst2, inst2, weightY) );
374
375 listY.push_back( T(inst1, inst2, -weightY) );
376 listY.push_back( T(inst2, inst1, -weightY) );
377
378 fixedInstForceVecY_(inst1) +=
379 -weightY * (
380 (pin1->cy() - pin1->instance()->cy()) -
381 (pin2->cy() - pin2->instance()->cy()));
382
383 fixedInstForceVecY_(inst2) +=
384 -weightY * (
385 (pin2->cy() - pin2->instance()->cy()) -
386 (pin1->cy() - pin1->instance()->cy()));
387 }
388 // pin1 from IO port / pin2 from Instance
389 else if( !pin1->isPlaceInstConnected()
390 && pin2->isPlaceInstConnected() ) {
391 const int inst2 = pin2->instance()->extId();
392 listY.push_back( T(inst2, inst2, weightY) );
393 fixedInstForceVecY_(inst2) += weightY *
394 ( pin1->cy() -
395 ( pin2->cy() - pin2->instance()->cy()) );
396 }
397 // pin1 from Instance / pin2 from IO port
398 else if( pin1->isPlaceInstConnected()
399 && !pin2->isPlaceInstConnected() ) {
400 const int inst1 = pin1->instance()->extId();
401 listY.push_back( T(inst1, inst1, weightY) );
402 fixedInstForceVecY_(inst1) += weightY *
403 ( pin2->cy() -
404 ( pin1->cy() - pin1->instance()->cy()) );
405 }
406 }
407 }
408 }
409 }
410
411 placeInstForceMatrixX_.setFromTriplets(listX.begin(), listX.end());
412 placeInstForceMatrixY_.setFromTriplets(listY.begin(), listY.end());
413 }
414
updateCoordi()415 void InitialPlace::updateCoordi() {
416 for(auto& inst : pb_->placeInsts()) {
417 int idx = inst->extId();
418 inst->dbSetCenterLocation( instLocVecX_(idx), instLocVecY_(idx) );
419 }
420 }
421
422 }
423