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