(1)support ispd18/19 (2)fix bugs (3)improve runtime
This commit is contained in:
parent
eaad4838f9
commit
ba01cd3652
@ -78,10 +78,14 @@ python main.py --dataset ispd2015_fix --design_name mgc_fft_1 --load_from_raw Tr
|
|||||||
python main.py --dataset ispd2015_fix --run_all True --load_from_raw True --detail_placement True
|
python main.py --dataset ispd2015_fix --run_all True --load_from_raw True --detail_placement True
|
||||||
```
|
```
|
||||||
|
|
||||||
- To run Routability GP + DP flow for ISPD2015 dataset:
|
- To run Routability GP + DP flow for ISPD2015/2018/2019 dataset:
|
||||||
```bash
|
```bash
|
||||||
# run all the designs in ispd2015 with routability optimization
|
# run all the designs with routability optimization
|
||||||
python main.py --dataset ispd2015_fix --run_all True --load_from_raw True --detail_placement True --use_cell_inflate True
|
python main.py --dataset ispd2015_fix --run_all True --load_from_raw True --detail_placement True --use_cell_inflate True
|
||||||
|
|
||||||
|
python main.py --dataset ispd2018 --run_all True --load_from_raw True --detail_placement True --use_cell_inflate True
|
||||||
|
|
||||||
|
python main.py --dataset ispd2019_no_fence --run_all True --load_from_raw True --detail_placement True --use_cell_inflate True
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: We default enable the deterministic mode. If you don't need determinism and want to run placement in an extremely fast mode, please try to set `--deterministic False` in the Python arguments.
|
**NOTE**: We default enable the deterministic mode. If you don't need determinism and want to run placement in an extremely fast mode, please try to set `--deterministic False` in the Python arguments.
|
||||||
|
|||||||
@ -37,19 +37,8 @@ void Cell::ctype(CellType* t) {
|
|||||||
|
|
||||||
int Cell::lx() const { return _lx; }
|
int Cell::lx() const { return _lx; }
|
||||||
int Cell::ly() const { return _ly; }
|
int Cell::ly() const { return _ly; }
|
||||||
bool Cell::flipX() const { return _flipX; }
|
|
||||||
bool Cell::flipY() const { return _flipY; }
|
|
||||||
int Cell::orient() const {
|
int Cell::orient() const {
|
||||||
if (!flipX() && !flipY()) {
|
return _orient;
|
||||||
return 0; // N
|
|
||||||
} else if (flipX() && flipY()) {
|
|
||||||
return 2; // S
|
|
||||||
} else if (flipX() && !flipY()) {
|
|
||||||
return 4; // FN
|
|
||||||
} else if (!flipX() && flipY()) {
|
|
||||||
return 6; // FS
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cell::placed() const { return (lx() != INT_MIN) && (ly() != INT_MIN); }
|
bool Cell::placed() const { return (lx() != INT_MIN) && (ly() != INT_MIN); }
|
||||||
@ -70,38 +59,7 @@ void Cell::place(int x, int y, int orient) {
|
|||||||
}
|
}
|
||||||
_lx = x;
|
_lx = x;
|
||||||
_ly = y;
|
_ly = y;
|
||||||
switch (orient) {
|
_orient = orient;
|
||||||
case 0:
|
|
||||||
_flipX = false;
|
|
||||||
_flipY = false;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_flipX = true;
|
|
||||||
_flipY = true;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_flipX = true;
|
|
||||||
_flipY = false;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
_flipX = false;
|
|
||||||
_flipY = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_flipX = false;
|
|
||||||
_flipY = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cell::place(int x, int y, bool flipX, bool flipY) {
|
|
||||||
if (_fixed) {
|
|
||||||
logger.warning("moving fixed cell %s to (%d,%d)", _name.c_str(), x, y);
|
|
||||||
}
|
|
||||||
_lx = x;
|
|
||||||
_ly = y;
|
|
||||||
_flipX = flipX;
|
|
||||||
_flipY = flipY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cell::unplace() {
|
void Cell::unplace() {
|
||||||
@ -109,7 +67,7 @@ void Cell::unplace() {
|
|||||||
logger.warning("unplace fixed cell %s", _name.c_str());
|
logger.warning("unplace fixed cell %s", _name.c_str());
|
||||||
}
|
}
|
||||||
_lx = _ly = INT_MIN;
|
_lx = _ly = INT_MIN;
|
||||||
_flipX = _flipY = false;
|
_orient = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Cell Type *****/
|
/***** Cell Type *****/
|
||||||
|
|||||||
@ -14,19 +14,19 @@ private:
|
|||||||
char _topPower = 'x';
|
char _topPower = 'x';
|
||||||
vector<Geometry> _obs;
|
vector<Geometry> _obs;
|
||||||
|
|
||||||
// _nonRegularRects.size() > 0 implies that this cell is a fixed cell and
|
// _nonRegularRects.size() > 0 implies that this cell is a fixed cell and
|
||||||
// its shape is a polygon. Each rectangle is also appended into
|
// its shape is a polygon. Each rectangle is also appended into
|
||||||
// Databased.placeBlockages during parsing the polygon-shape cell.
|
// Databased.placeBlockages during parsing the polygon-shape cell.
|
||||||
// NOTE: We only support this feature for ICCAD/DAC 2012 benchmarks.
|
// NOTE: We only support this feature for ICCAD/DAC 2012 benchmarks.
|
||||||
// When processing GPDatabase, we will set this kind of cells' width and
|
// When processing GPDatabase, we will set this kind of cells' width and
|
||||||
// height as 0 and use placeement blockages to represent their shapes.
|
// height as 0 and use placeement blockages to represent their shapes.
|
||||||
vector<Rectangle> _nonRegularRects;
|
vector<Rectangle> _nonRegularRects;
|
||||||
|
|
||||||
int _libcell = -1;
|
int _libcell = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
char cls = 'x';
|
std::string cls = "x";
|
||||||
bool stdcell = false;
|
bool stdcell = false;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
@ -84,8 +84,7 @@ private:
|
|||||||
|
|
||||||
int _lx = INT_MIN;
|
int _lx = INT_MIN;
|
||||||
int _ly = INT_MIN;
|
int _ly = INT_MIN;
|
||||||
bool _flipX = false;
|
int _orient = -1; // 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
bool _flipY = false;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool highlighted = false;
|
bool highlighted = false;
|
||||||
@ -107,8 +106,6 @@ public:
|
|||||||
int hy() const { return ly() + height(); }
|
int hy() const { return ly() + height(); }
|
||||||
int cx() const { return lx() + width() / 2; }
|
int cx() const { return lx() + width() / 2; }
|
||||||
int cy() const { return ly() + height() / 2; }
|
int cy() const { return ly() + height() / 2; }
|
||||||
bool flipX() const;
|
|
||||||
bool flipY() const;
|
|
||||||
int orient() const;
|
int orient() const;
|
||||||
int width() const { return _type->width + _spaceL + _spaceR; }
|
int width() const { return _type->width + _spaceL + _spaceR; }
|
||||||
int height() const { return _type->height + _spaceB + _spaceT; }
|
int height() const { return _type->height + _spaceB + _spaceT; }
|
||||||
@ -119,7 +116,6 @@ public:
|
|||||||
bool placed() const;
|
bool placed() const;
|
||||||
void place(int x, int y);
|
void place(int x, int y);
|
||||||
void place(int x, int y, int orient);
|
void place(int x, int y, int orient);
|
||||||
void place(int x, int y, bool flipX, bool flipY);
|
|
||||||
void unplace();
|
void unplace();
|
||||||
unsigned numPins() const { return _pins.size(); }
|
unsigned numPins() const { return _pins.size(); }
|
||||||
|
|
||||||
|
|||||||
@ -490,9 +490,11 @@ void Database::SetupRows() {
|
|||||||
// verify row flipping conflict
|
// verify row flipping conflict
|
||||||
bool flipCheckPass = true;
|
bool flipCheckPass = true;
|
||||||
std::vector<char> flip(nSitesY, 0);
|
std::vector<char> flip(nSitesY, 0);
|
||||||
|
std::vector<int> orients(nSitesY, -1);
|
||||||
for (Row* row : rows) {
|
for (Row* row : rows) {
|
||||||
char isFlip = (row->flip() ? 1 : 2);
|
char isFlip = (row->flip() ? 1 : 2);
|
||||||
int y = (row->y() - coreLY) / siteH;
|
int y = (row->y() - coreLY) / siteH;
|
||||||
|
orients[y] = row->orient(); // TODO: how to handle multiple ROW definitions on same y?
|
||||||
if (flip[y] == 0) {
|
if (flip[y] == 0) {
|
||||||
flip[y] = isFlip;
|
flip[y] = isFlip;
|
||||||
} else if (flip[y] != isFlip) {
|
} else if (flip[y] != isFlip) {
|
||||||
@ -525,6 +527,7 @@ void Database::SetupRows() {
|
|||||||
rows[y]->xNum(nSitesX);
|
rows[y]->xNum(nSitesX);
|
||||||
rows[y]->yNum(1);
|
rows[y]->yNum(1);
|
||||||
rows[y]->flip(flip[y] == 1);
|
rows[y]->flip(flip[y] == 1);
|
||||||
|
rows[y]->orient(orients[y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set row power-rail
|
// set row power-rail
|
||||||
@ -722,10 +725,11 @@ Row* Database::addRow(const string& name,
|
|||||||
const int y,
|
const int y,
|
||||||
const unsigned xNum,
|
const unsigned xNum,
|
||||||
const unsigned yNum,
|
const unsigned yNum,
|
||||||
|
const int orient,
|
||||||
const bool flip,
|
const bool flip,
|
||||||
const unsigned xStep,
|
const unsigned xStep,
|
||||||
const unsigned yStep) {
|
const unsigned yStep) {
|
||||||
Row* newrow = new Row(name, macro, x, y, xNum, yNum, flip, xStep, yStep);
|
Row* newrow = new Row(name, macro, x, y, xNum, yNum, orient, flip, xStep, yStep);
|
||||||
rows.push_back(newrow);
|
rows.push_back(newrow);
|
||||||
return newrow;
|
return newrow;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -154,6 +154,7 @@ public:
|
|||||||
const int y,
|
const int y,
|
||||||
const unsigned xNum = 0,
|
const unsigned xNum = 0,
|
||||||
const unsigned yNum = 0,
|
const unsigned yNum = 0,
|
||||||
|
const int orient = 0,
|
||||||
const bool flip = false,
|
const bool flip = false,
|
||||||
const unsigned xStep = 0,
|
const unsigned xStep = 0,
|
||||||
const unsigned yStep = 0);
|
const unsigned yStep = 0);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ public:
|
|||||||
string name = "";
|
string name = "";
|
||||||
int x = INT_MIN;
|
int x = INT_MIN;
|
||||||
int y = INT_MIN;
|
int y = INT_MIN;
|
||||||
int _orient = 0; // 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE
|
int _orient = -1; // 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
PinType* type;
|
PinType* type;
|
||||||
Pin* pin;
|
Pin* pin;
|
||||||
int gpdb_id = -1;
|
int gpdb_id = -1;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ private:
|
|||||||
int _y = 0;
|
int _y = 0;
|
||||||
unsigned _xNum = 0;
|
unsigned _xNum = 0;
|
||||||
unsigned _yNum = 0;
|
unsigned _yNum = 0;
|
||||||
|
int _orient = 0; // 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
bool _flip = false;
|
bool _flip = false;
|
||||||
unsigned _xStep = 0;
|
unsigned _xStep = 0;
|
||||||
unsigned _yStep = 0;
|
unsigned _yStep = 0;
|
||||||
@ -20,13 +21,14 @@ private:
|
|||||||
public:
|
public:
|
||||||
std::vector<RowSegment> segments;
|
std::vector<RowSegment> segments;
|
||||||
|
|
||||||
Row(const string& name, const string& macro, const int x, const int y, const unsigned xNum = 0, const unsigned yNum = 0, const bool flip = false, const unsigned xStep = 0, const unsigned yStep = 0)
|
Row(const string& name, const string& macro, const int x, const int y, const unsigned xNum = 0, const unsigned yNum = 0, const int orient = 0, const bool flip = false, const unsigned xStep = 0, const unsigned yStep = 0)
|
||||||
: _name(name)
|
: _name(name)
|
||||||
, _macro(macro)
|
, _macro(macro)
|
||||||
, _x(x)
|
, _x(x)
|
||||||
, _y(y)
|
, _y(y)
|
||||||
, _xNum(xNum)
|
, _xNum(xNum)
|
||||||
, _yNum(yNum)
|
, _yNum(yNum)
|
||||||
|
, _orient(orient)
|
||||||
, _flip(flip)
|
, _flip(flip)
|
||||||
, _xStep(xStep)
|
, _xStep(xStep)
|
||||||
, _yStep(yStep) {}
|
, _yStep(yStep) {}
|
||||||
@ -46,6 +48,7 @@ public:
|
|||||||
int y() const { return _y; }
|
int y() const { return _y; }
|
||||||
unsigned xNum() const { return _xNum; }
|
unsigned xNum() const { return _xNum; }
|
||||||
unsigned yNum() const { return _yNum; }
|
unsigned yNum() const { return _yNum; }
|
||||||
|
int orient() const { return _orient; }
|
||||||
bool flip() const { return _flip; }
|
bool flip() const { return _flip; }
|
||||||
unsigned xStep() const { return _xStep; }
|
unsigned xStep() const { return _xStep; }
|
||||||
unsigned yStep() const { return _yStep; }
|
unsigned yStep() const { return _yStep; }
|
||||||
@ -56,6 +59,7 @@ public:
|
|||||||
void y(const int value) { _y = value; }
|
void y(const int value) { _y = value; }
|
||||||
void xNum(const unsigned value) { _xNum = value; }
|
void xNum(const unsigned value) { _xNum = value; }
|
||||||
void yNum(const unsigned value) { _yNum = value; }
|
void yNum(const unsigned value) { _yNum = value; }
|
||||||
|
void orient(const int value) { _orient = value; }
|
||||||
void flip(const bool value) { _flip = value; }
|
void flip(const bool value) { _flip = value; }
|
||||||
void xStep(const unsigned value) { _xStep = value; }
|
void xStep(const unsigned value) { _xStep = value; }
|
||||||
void yStep(const unsigned value) { _yStep = value; }
|
void yStep(const unsigned value) { _yStep = value; }
|
||||||
|
|||||||
@ -417,6 +417,7 @@ bool Database::readBSAux(const std::string& auxFile, const std::string& plFile)
|
|||||||
row->xNum(bsData.rowSites[i]);
|
row->xNum(bsData.rowSites[i]);
|
||||||
row->yNum(1);
|
row->yNum(1);
|
||||||
row->flip((i % 2) == 1);
|
row->flip((i % 2) == 1);
|
||||||
|
row->orient((i % 2) * 6); // 0:N or 6:FS
|
||||||
this->dieLX = std::min(this->dieLX, row->x());
|
this->dieLX = std::min(this->dieLX, row->x());
|
||||||
this->dieLY = std::min(this->dieLY, row->y());
|
this->dieLY = std::min(this->dieLY, row->y());
|
||||||
this->dieHX = std::max(this->dieHX, row->x() + (int)row->width());
|
this->dieHX = std::max(this->dieHX, row->x() + (int)row->width());
|
||||||
@ -575,7 +576,8 @@ bool Database::readBSAux(const std::string& auxFile, const std::string& plFile)
|
|||||||
} else {
|
} else {
|
||||||
string celltypename(bsData.typeName[typeID]);
|
string celltypename(bsData.typeName[typeID]);
|
||||||
Cell* cell = this->addCell(bsData.cellName[i], this->getCellType(celltypename));
|
Cell* cell = this->addCell(bsData.cellName[i], this->getCellType(celltypename));
|
||||||
cell->place(bsData.cellX[i], bsData.cellY[i], false, false);
|
// In Bookshelf, we don't need to consider the cell orient, set it as -1
|
||||||
|
cell->place(bsData.cellX[i], bsData.cellY[i], -1);
|
||||||
// cout<<cell->x<<","<<cell->y<<endl;
|
// cout<<cell->x<<","<<cell->y<<endl;
|
||||||
cell->fixed((bsData.cellFixed[i] == (char)1));
|
cell->fixed((bsData.cellFixed[i] == (char)1));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ bool isFlipX(int orient) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFlipY(int orient) {
|
bool isFlipY(int orient) {
|
||||||
switch (orient) {
|
switch (orient) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -36,7 +37,7 @@ bool isFlipY(int orient) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string getOrient(bool flipX, bool flipY) {
|
string getRowOrient(bool flipX, bool flipY) {
|
||||||
if (flipX) {
|
if (flipX) {
|
||||||
if (flipY) {
|
if (flipY) {
|
||||||
return "S";
|
return "S";
|
||||||
@ -52,6 +53,32 @@ string getOrient(bool flipX, bool flipY) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string getOrient(int orient) {
|
||||||
|
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
|
switch (orient) {
|
||||||
|
case 0:
|
||||||
|
return "N";
|
||||||
|
case 1:
|
||||||
|
return "W";
|
||||||
|
case 2:
|
||||||
|
return "S";
|
||||||
|
case 3:
|
||||||
|
return "E";
|
||||||
|
case 4:
|
||||||
|
return "FN";
|
||||||
|
case 5:
|
||||||
|
return "FW";
|
||||||
|
case 6:
|
||||||
|
return "FS";
|
||||||
|
case 7:
|
||||||
|
return "FE";
|
||||||
|
case -1:
|
||||||
|
return "NONE";
|
||||||
|
default:
|
||||||
|
return "N";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define DIR_UP 1
|
#define DIR_UP 1
|
||||||
#define DIR_DOWN 2
|
#define DIR_DOWN 2
|
||||||
#define DIR_LEFT 4
|
#define DIR_LEFT 4
|
||||||
@ -360,16 +387,16 @@ bool Database::writeComponents(ofstream& ofs) {
|
|||||||
oss << " - " << cell->name() << " " << cell->ctype()->name << endl;
|
oss << " - " << cell->name() << " " << cell->ctype()->name << endl;
|
||||||
// ofs << " - " << cell->name() << " " << cell->ctype()->name << endl;
|
// ofs << " - " << cell->name() << " " << cell->ctype()->name << endl;
|
||||||
if (cell->fixed()) {
|
if (cell->fixed()) {
|
||||||
oss << " + FIXED ( " << cell->lx() << " " << cell->ly() << " ) "
|
oss << " + FIXED ( " << cell->lx() << " " << cell->ly() << " ) " << getOrient(cell->orient()) << " ;"
|
||||||
<< getOrient(cell->flipX(), cell->flipY()) << " ;" << endl;
|
<< endl;
|
||||||
// ofs << " + FIXED ( " << cell->lx() << " " << cell->ly() << " ) "
|
// ofs << " + FIXED ( " << cell->lx() << " " << cell->ly() << " ) "
|
||||||
// << getOrient(cell->flipX(), cell->flipY())
|
// << getOrient(cell->orient())
|
||||||
// << " ;" << endl;
|
// << " ;" << endl;
|
||||||
} else if (cell->placed()) {
|
} else if (cell->placed()) {
|
||||||
oss << " + PLACED ( " << cell->lx() << " " << cell->ly() << " ) "
|
oss << " + PLACED ( " << cell->lx() << " " << cell->ly() << " ) " << getOrient(cell->orient()) << " ;"
|
||||||
<< getOrient(cell->flipX(), cell->flipY()) << " ;" << endl;
|
<< endl;
|
||||||
// ofs << " + PLACED ( " << cell->lx() << " " << cell->ly() << " ) "
|
// ofs << " + PLACED ( " << cell->lx() << " " << cell->ly() << " ) "
|
||||||
// << getOrient(cell->flipX(), cell->flipY())
|
// << getOrient(cell->orient())
|
||||||
// << " ;" << endl;
|
// << " ;" << endl;
|
||||||
} else {
|
} else {
|
||||||
oss << " + UNPLACED ;" << endl;
|
oss << " + UNPLACED ;" << endl;
|
||||||
@ -461,7 +488,7 @@ bool Database::writeDEF(const string& file) {
|
|||||||
|
|
||||||
for (Row* row : rows) {
|
for (Row* row : rows) {
|
||||||
ofs << "ROW " << row->name() << ' ' << row->macro() << ' ' << row->x() << ' ' << row->y() << ' ';
|
ofs << "ROW " << row->name() << ' ' << row->macro() << ' ' << row->x() << ' ' << row->y() << ' ';
|
||||||
ofs << getOrient(false, row->flip());
|
ofs << getRowOrient(false, row->flip());
|
||||||
ofs << " DO " << row->xNum() << " BY " << row->yNum() << " STEP " << row->xStep() << ' ' << row->yStep()
|
ofs << " DO " << row->xNum() << " BY " << row->yNum() << " STEP " << row->xStep() << ' ' << row->yStep()
|
||||||
<< " ;\n";
|
<< " ;\n";
|
||||||
}
|
}
|
||||||
@ -1158,19 +1185,18 @@ int readLefMacro(lefrCallbackType_e c, lefiMacro* macro, lefiUserData ud) {
|
|||||||
celltype->height = round(macro->sizeY() * convertFactor);
|
celltype->height = round(macro->sizeY() * convertFactor);
|
||||||
|
|
||||||
if (macro->lefiMacro::hasClass()) {
|
if (macro->lefiMacro::hasClass()) {
|
||||||
char clsname[64] = {0};
|
std::string clsname(macro->macroClass());
|
||||||
strcpy(clsname, macro->macroClass());
|
if (clsname == "CORE") {
|
||||||
if (!strcmp(clsname, "CORE")) {
|
celltype->cls = clsname;
|
||||||
celltype->cls = 'c';
|
|
||||||
celltype->stdcell = true;
|
celltype->stdcell = true;
|
||||||
} else if (!strcmp(clsname, "BLOCK")) {
|
} else if (clsname == "BLOCK") {
|
||||||
celltype->cls = 'b';
|
celltype->cls = clsname;
|
||||||
} else {
|
} else {
|
||||||
celltype->cls = clsname[0];
|
celltype->cls = clsname;
|
||||||
logger.warning("Class type is not defined: %s", clsname);
|
logger.warning("Class type is not defined: %s", celltype->cls.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
celltype->cls = 'c';
|
celltype->cls = "CORE"; // default value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (macro->lefiMacro::hasOrigin()) {
|
if (macro->lefiMacro::hasOrigin()) {
|
||||||
@ -1273,6 +1299,7 @@ int readDefRow(defrCallbackType_e c, defiRow* drow, defiUserData ud) {
|
|||||||
drow->y(),
|
drow->y(),
|
||||||
drow->xNum(),
|
drow->xNum(),
|
||||||
drow->yNum(),
|
drow->yNum(),
|
||||||
|
drow->orient(),
|
||||||
isFlipY(drow->orient()),
|
isFlipY(drow->orient()),
|
||||||
drow->xStep(),
|
drow->xStep(),
|
||||||
drow->yStep());
|
drow->yStep());
|
||||||
@ -1442,27 +1469,36 @@ int readDefComponentStart(defrCallbackType_e c, int num, defiUserData ud) {
|
|||||||
|
|
||||||
int readDefComponent(defrCallbackType_e c, defiComponent* co, defiUserData ud) {
|
int readDefComponent(defrCallbackType_e c, defiComponent* co, defiUserData ud) {
|
||||||
Database* db = (Database*)ud;
|
Database* db = (Database*)ud;
|
||||||
|
CellType* celltype = db->getCellType(co->name());
|
||||||
Cell* cell = db->addCell(co->id(), db->getCellType(co->name()));
|
Cell* cell = db->addCell(co->id(), celltype);
|
||||||
|
|
||||||
if (co->isUnplaced()) {
|
if (co->isUnplaced()) {
|
||||||
cell->fixed(false);
|
cell->fixed(false);
|
||||||
cell->unplace();
|
cell->unplace();
|
||||||
} else if (co->isPlaced()) {
|
} else if (co->isPlaced()) {
|
||||||
cell->place(co->placementX(), co->placementY(), isFlipX(co->placementOrient()), isFlipY(co->placementOrient()));
|
cell->place(co->placementX(), co->placementY(), co->placementOrient());
|
||||||
cell->fixed(false);
|
if (celltype->cls == "CORE") {
|
||||||
|
cell->fixed(false);
|
||||||
|
} else {
|
||||||
|
// Set all non-CORE cells as fixed cells
|
||||||
|
cell->fixed(true);
|
||||||
|
}
|
||||||
if (co->placementOrient() % 2 == 1) {
|
if (co->placementOrient() % 2 == 1) {
|
||||||
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE
|
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
logger.warning(
|
logger.warning("Cell [%s]'s placementOrient [%s] is not supported, CLASS: %s.",
|
||||||
"Cell [%s]'s placementOrient [%d] is not supported.", cell->name().c_str(), co->placementOrient());
|
cell->name().c_str(),
|
||||||
|
getOrient(co->placementOrient()).c_str(),
|
||||||
|
celltype->cls.c_str());
|
||||||
}
|
}
|
||||||
} else if (co->isFixed()) {
|
} else if (co->isFixed()) {
|
||||||
cell->place(co->placementX(), co->placementY(), isFlipX(co->placementOrient()), isFlipY(co->placementOrient()));
|
cell->place(co->placementX(), co->placementY(), co->placementOrient());
|
||||||
cell->fixed(true);
|
cell->fixed(true);
|
||||||
if (co->placementOrient() % 2 == 1) {
|
if (co->placementOrient() % 2 == 1) {
|
||||||
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE
|
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
logger.warning(
|
logger.warning("Fixed Cell [%s]'s placementOrient [%s] is not supported, CLASS: %s.",
|
||||||
"Cell [%s]'s placementOrient [%d] is not supported.", cell->name().c_str(), co->placementOrient());
|
cell->name().c_str(),
|
||||||
|
getOrient(co->placementOrient()).c_str(),
|
||||||
|
celltype->cls.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -63,6 +63,7 @@ class PrintfLogger {
|
|||||||
static constexpr bool write_log = false;
|
static constexpr bool write_log = false;
|
||||||
FILE* f;
|
FILE* f;
|
||||||
bool tmp_verbose_parser_log = false;
|
bool tmp_verbose_parser_log = false;
|
||||||
|
int _global_log_level = LOG_INFO;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// void setup_logger(argparse::ArgumentParser parser);
|
// void setup_logger(argparse::ArgumentParser parser);
|
||||||
@ -84,12 +85,16 @@ public:
|
|||||||
verbose_parser_log = tmp_verbose_parser_log;
|
verbose_parser_log = tmp_verbose_parser_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_global_log_level(int value) {
|
||||||
|
_global_log_level = value;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void log(int log_level, const char* format, Args&&... args) {
|
void log(int log_level, const char* format, Args&&... args) {
|
||||||
if (!verbose_parser_log) {
|
if (!verbose_parser_log) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (log_level >= GLOBAL_LOG_LEVEL) {
|
if (log_level >= _global_log_level) {
|
||||||
std::string curr_log = tstamp.get_time_stamp();
|
std::string curr_log = tstamp.get_time_stamp();
|
||||||
if (log_level > LOG_INFO) {
|
if (log_level > LOG_INFO) {
|
||||||
curr_log += log_level_ANSI_color(log_level);
|
curr_log += log_level_ANSI_color(log_level);
|
||||||
@ -111,7 +116,7 @@ public:
|
|||||||
if (!verbose_parser_log) {
|
if (!verbose_parser_log) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (log_level >= GLOBAL_LOG_LEVEL) {
|
if (log_level >= _global_log_level) {
|
||||||
std::string curr_log = tstamp.get_time_stamp();
|
std::string curr_log = tstamp.get_time_stamp();
|
||||||
if (log_level > LOG_INFO) {
|
if (log_level > LOG_INFO) {
|
||||||
curr_log += log_level_ANSI_color(log_level);
|
curr_log += log_level_ANSI_color(log_level);
|
||||||
|
|||||||
@ -14,7 +14,6 @@ inline constexpr int LOG_WARN = 4; // 4
|
|||||||
inline constexpr int LOG_ERROR = 5; // 5
|
inline constexpr int LOG_ERROR = 5; // 5
|
||||||
inline constexpr int LOG_FATAL = 6; // 6
|
inline constexpr int LOG_FATAL = 6; // 6
|
||||||
inline constexpr int LOG_OK = 7; // 7
|
inline constexpr int LOG_OK = 7; // 7
|
||||||
inline int GLOBAL_LOG_LEVEL = LOG_INFO; // change verbose level in Setting.h
|
|
||||||
|
|
||||||
} // namespace utils::log_level
|
} // namespace utils::log_level
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|||||||
float,
|
float,
|
||||||
int,
|
int,
|
||||||
int,
|
int,
|
||||||
|
int,
|
||||||
float,
|
float,
|
||||||
float>())
|
float>())
|
||||||
.def("check", &dp::DPTorchRawDB::check)
|
.def("check", &dp::DPTorchRawDB::check)
|
||||||
@ -57,6 +58,7 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|||||||
float xh_,
|
float xh_,
|
||||||
float yl_,
|
float yl_,
|
||||||
float yh_,
|
float yh_,
|
||||||
|
int num_conn_movable_nodes_,
|
||||||
int num_movable_nodes_,
|
int num_movable_nodes_,
|
||||||
int num_nodes_,
|
int num_nodes_,
|
||||||
float site_width_,
|
float site_width_,
|
||||||
@ -79,6 +81,7 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|||||||
xh_,
|
xh_,
|
||||||
yl_,
|
yl_,
|
||||||
yh_,
|
yh_,
|
||||||
|
num_conn_movable_nodes_,
|
||||||
num_movable_nodes_,
|
num_movable_nodes_,
|
||||||
num_nodes_,
|
num_nodes_,
|
||||||
site_width_,
|
site_width_,
|
||||||
@ -90,9 +93,10 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|||||||
m.def("abacusLegalization", [](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, int num_bins_x, int num_bins_y) {
|
m.def("abacusLegalization", [](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, int num_bins_x, int num_bins_y) {
|
||||||
return dp::abacusLegalization(*at_db_ptr, num_bins_x, num_bins_y);
|
return dp::abacusLegalization(*at_db_ptr, num_bins_x, num_bins_y);
|
||||||
});
|
});
|
||||||
m.def("greedyLegalization", [](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, int num_bins_x, int num_bins_y) {
|
m.def("greedyLegalization",
|
||||||
return dp::greedyLegalization(*at_db_ptr, num_bins_x, num_bins_y);
|
[](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, int num_bins_x, int num_bins_y, bool legalize_filler) {
|
||||||
});
|
return dp::greedyLegalization(*at_db_ptr, num_bins_x, num_bins_y, legalize_filler);
|
||||||
|
});
|
||||||
m.def("kReorder",
|
m.def("kReorder",
|
||||||
[](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, int num_bins_x, int num_bins_y, int K, int max_iters) {
|
[](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, int num_bins_x, int num_bins_y, int K, int max_iters) {
|
||||||
return dp::kReorder(*at_db_ptr, num_bins_x, num_bins_y, K, max_iters);
|
return dp::kReorder(*at_db_ptr, num_bins_x, num_bins_y, K, max_iters);
|
||||||
@ -114,6 +118,8 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|||||||
m.def("legalityCheck", [](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, float scale_factor) {
|
m.def("legalityCheck", [](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr, float scale_factor) {
|
||||||
return dp::legalityCheck(*at_db_ptr, scale_factor);
|
return dp::legalityCheck(*at_db_ptr, scale_factor);
|
||||||
});
|
});
|
||||||
|
m.def("fillerLegalization",
|
||||||
|
[](std::shared_ptr<dp::DPTorchRawDB> at_db_ptr) { return dp::fillerLegalization(*at_db_ptr); });
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Xplace
|
} // namespace Xplace
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
namespace dp {
|
namespace dp {
|
||||||
|
|
||||||
|
float floatRound(float a, float prec) { return std::round(a / prec) * prec; }
|
||||||
|
|
||||||
bool boundaryCheck(const float* x,
|
bool boundaryCheck(const float* x,
|
||||||
const float* y,
|
const float* y,
|
||||||
const float* node_size_x,
|
const float* node_size_x,
|
||||||
@ -94,14 +96,15 @@ bool fenceRegionCheck(const float* x,
|
|||||||
const int* flat_region_boxes_start,
|
const int* flat_region_boxes_start,
|
||||||
const int* node2fence_region_map,
|
const int* node2fence_region_map,
|
||||||
int num_movable_nodes,
|
int num_movable_nodes,
|
||||||
int num_regions) {
|
int num_regions,
|
||||||
|
float scale_factor) {
|
||||||
bool legal_flag = true;
|
bool legal_flag = true;
|
||||||
// check fence regions
|
// check fence regions
|
||||||
for (int i = 0; i < num_movable_nodes; ++i) {
|
for (int i = 0; i < num_movable_nodes; ++i) {
|
||||||
float node_xl = x[i];
|
float node_xl = x[i];
|
||||||
float node_yl = y[i];
|
float node_yl = floatRound(y[i], scale_factor);
|
||||||
float node_xh = node_xl + node_size_x[i];
|
float node_xh = node_xl + node_size_x[i];
|
||||||
float node_yh = node_yl + node_size_y[i];
|
float node_yh = floatRound(node_yl + node_size_y[i], scale_factor);
|
||||||
|
|
||||||
int region_id = node2fence_region_map[i];
|
int region_id = node2fence_region_map[i];
|
||||||
if (region_id < num_regions) {
|
if (region_id < num_regions) {
|
||||||
@ -112,10 +115,12 @@ bool fenceRegionCheck(const float* x,
|
|||||||
// otherwise, preprocessing is required
|
// otherwise, preprocessing is required
|
||||||
for (int box_id = box_bgn; box_id < box_end; ++box_id) {
|
for (int box_id = box_bgn; box_id < box_end; ++box_id) {
|
||||||
int box_offset = box_id * 4;
|
int box_offset = box_id * 4;
|
||||||
|
|
||||||
float box_xl = flat_region_boxes[box_offset];
|
float box_xl = flat_region_boxes[box_offset];
|
||||||
float box_xh = flat_region_boxes[box_offset + 1];
|
float box_xh = flat_region_boxes[box_offset + 1];
|
||||||
float box_yl = flat_region_boxes[box_offset + 2];
|
|
||||||
float box_yh = flat_region_boxes[box_offset + 3];
|
float box_yl = floatRound(flat_region_boxes[box_offset + 2], scale_factor);
|
||||||
|
float box_yh = floatRound(flat_region_boxes[box_offset + 3], scale_factor);
|
||||||
|
|
||||||
float dx = std::max(std::min(node_xh, box_xh) - std::max(node_xl, box_xl), (float)0);
|
float dx = std::max(std::min(node_xh, box_xh) - std::max(node_xl, box_xl), (float)0);
|
||||||
float dy = std::max(std::min(node_yh, box_yh) - std::max(node_yl, box_yl), (float)0);
|
float dy = std::max(std::min(node_yh, box_yh) - std::max(node_yl, box_yl), (float)0);
|
||||||
@ -333,8 +338,19 @@ bool legalityCheckKernelCPU(const float* x,
|
|||||||
std::cerr << "site alignment check error!" << std::endl;
|
std::cerr << "site alignment check error!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overlapCheck(
|
if (!overlapCheck(x,
|
||||||
x, y, node_size_x, node_size_y, site_width, row_height, scale_factor, xl, yl, xh, yh, num_nodes, num_movable_nodes)) {
|
y,
|
||||||
|
node_size_x,
|
||||||
|
node_size_y,
|
||||||
|
site_width,
|
||||||
|
row_height,
|
||||||
|
scale_factor,
|
||||||
|
xl,
|
||||||
|
yl,
|
||||||
|
xh,
|
||||||
|
yh,
|
||||||
|
num_nodes,
|
||||||
|
num_movable_nodes)) {
|
||||||
legal_flag = false;
|
legal_flag = false;
|
||||||
std::cerr << "overlap check error!" << std::endl;
|
std::cerr << "overlap check error!" << std::endl;
|
||||||
}
|
}
|
||||||
@ -348,7 +364,8 @@ bool legalityCheckKernelCPU(const float* x,
|
|||||||
flat_region_boxes_start,
|
flat_region_boxes_start,
|
||||||
node2fence_region_map,
|
node2fence_region_map,
|
||||||
num_movable_nodes,
|
num_movable_nodes,
|
||||||
num_regions)) {
|
num_regions,
|
||||||
|
scale_factor)) {
|
||||||
legal_flag = false;
|
legal_flag = false;
|
||||||
std::cerr << "fence region check error!" << std::endl;
|
std::cerr << "fence region check error!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ DPTorchRawDB::DPTorchRawDB(torch::Tensor node_lpos_init_,
|
|||||||
float xh_,
|
float xh_,
|
||||||
float yl_,
|
float yl_,
|
||||||
float yh_,
|
float yh_,
|
||||||
|
int num_conn_movable_nodes_,
|
||||||
int num_movable_nodes_,
|
int num_movable_nodes_,
|
||||||
int num_nodes_,
|
int num_nodes_,
|
||||||
float site_width_,
|
float site_width_,
|
||||||
@ -45,6 +46,7 @@ DPTorchRawDB::DPTorchRawDB(torch::Tensor node_lpos_init_,
|
|||||||
num_nets = hyperedge_list_end_.size(0);
|
num_nets = hyperedge_list_end_.size(0);
|
||||||
num_regions = region_boxes_end_.size(0);
|
num_regions = region_boxes_end_.size(0);
|
||||||
num_movable_nodes = num_movable_nodes_;
|
num_movable_nodes = num_movable_nodes_;
|
||||||
|
num_conn_movable_nodes = num_conn_movable_nodes_;
|
||||||
|
|
||||||
flat_node2pin_start_map =
|
flat_node2pin_start_map =
|
||||||
torch::cat({torch::zeros({1}, torch::dtype(torch::kInt32).device(torch::Device(node_size.device()))),
|
torch::cat({torch::zeros({1}, torch::dtype(torch::kInt32).device(torch::Device(node_size.device()))),
|
||||||
@ -92,12 +94,20 @@ bool DPTorchRawDB::check(float scale_factor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DPTorchRawDB::scale(float scale_factor, bool use_round) {
|
void DPTorchRawDB::scale(float scale_factor, bool use_round) {
|
||||||
pin_rel_lpos.mul_(scale_factor);
|
|
||||||
if (use_round) {
|
if (use_round) {
|
||||||
|
pin_rel_lpos.mul_(scale_factor);
|
||||||
node_size.mul_(scale_factor).round_();
|
node_size.mul_(scale_factor).round_();
|
||||||
node_lpos_init.mul_(scale_factor).round_();
|
node_lpos_init.mul_(scale_factor).round_();
|
||||||
|
|
||||||
|
node_size_x.mul_(scale_factor).round_();
|
||||||
|
node_size_y.mul_(scale_factor).round_();
|
||||||
|
init_x.mul_(scale_factor).round_();
|
||||||
|
init_y.mul_(scale_factor).round_();
|
||||||
|
pin_offset_x.mul_(scale_factor).round_();
|
||||||
|
pin_offset_y.mul_(scale_factor).round_();
|
||||||
x.mul_(scale_factor).round_();
|
x.mul_(scale_factor).round_();
|
||||||
y.mul_(scale_factor).round_();
|
y.mul_(scale_factor).round_();
|
||||||
|
|
||||||
flat_region_boxes.mul_(scale_factor).round_();
|
flat_region_boxes.mul_(scale_factor).round_();
|
||||||
site_width = round(site_width * scale_factor);
|
site_width = round(site_width * scale_factor);
|
||||||
row_height = round(row_height * scale_factor);
|
row_height = round(row_height * scale_factor);
|
||||||
@ -106,17 +116,27 @@ void DPTorchRawDB::scale(float scale_factor, bool use_round) {
|
|||||||
yl = round(yl * scale_factor);
|
yl = round(yl * scale_factor);
|
||||||
yh = round(yh * scale_factor);
|
yh = round(yh * scale_factor);
|
||||||
} else {
|
} else {
|
||||||
node_size.mul_(scale_factor);
|
float inv_scale_factor = std::round(1.0 / scale_factor);
|
||||||
node_lpos_init.mul_(scale_factor);
|
pin_rel_lpos.div_(inv_scale_factor);
|
||||||
x.mul_(scale_factor);
|
node_size.div_(inv_scale_factor);
|
||||||
y.mul_(scale_factor);
|
node_lpos_init.div_(inv_scale_factor);
|
||||||
flat_region_boxes.mul_(scale_factor);
|
|
||||||
site_width = site_width * scale_factor;
|
node_size_x.div_(inv_scale_factor);
|
||||||
row_height = row_height * scale_factor;
|
node_size_y.div_(inv_scale_factor);
|
||||||
xl = xl * scale_factor;
|
init_x.div_(inv_scale_factor);
|
||||||
xh = xh * scale_factor;
|
init_y.div_(inv_scale_factor);
|
||||||
yl = yl * scale_factor;
|
pin_offset_x.div_(inv_scale_factor);
|
||||||
yh = yh * scale_factor;
|
pin_offset_y.div_(inv_scale_factor);
|
||||||
|
x.div_(inv_scale_factor);
|
||||||
|
y.div_(inv_scale_factor);
|
||||||
|
|
||||||
|
flat_region_boxes.div_(inv_scale_factor);
|
||||||
|
site_width = site_width / inv_scale_factor;
|
||||||
|
row_height = row_height / inv_scale_factor;
|
||||||
|
xl = xl / inv_scale_factor;
|
||||||
|
xh = xh / inv_scale_factor;
|
||||||
|
yl = yl / inv_scale_factor;
|
||||||
|
yh = yh / inv_scale_factor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@ public:
|
|||||||
float xh_,
|
float xh_,
|
||||||
float yl_,
|
float yl_,
|
||||||
float yh_,
|
float yh_,
|
||||||
|
int num_conn_movable_nodes_,
|
||||||
int num_movable_nodes_,
|
int num_movable_nodes_,
|
||||||
int num_nodes_,
|
int num_nodes_,
|
||||||
float site_width_,
|
float site_width_,
|
||||||
@ -88,6 +89,7 @@ public:
|
|||||||
int num_nets;
|
int num_nets;
|
||||||
int num_nodes;
|
int num_nodes;
|
||||||
int num_movable_nodes;
|
int num_movable_nodes;
|
||||||
|
int num_conn_movable_nodes;
|
||||||
int num_regions;
|
int num_regions;
|
||||||
|
|
||||||
float site_width;
|
float site_width;
|
||||||
@ -100,7 +102,8 @@ public:
|
|||||||
// Legalization
|
// Legalization
|
||||||
bool macroLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y);
|
bool macroLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y);
|
||||||
void abacusLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y);
|
void abacusLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y);
|
||||||
void greedyLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y);
|
void greedyLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y, bool legalize_filler);
|
||||||
|
void fillerLegalization(DPTorchRawDB& at_db);
|
||||||
|
|
||||||
// Detailed Placement
|
// Detailed Placement
|
||||||
void kReorder(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y, int K, int max_iters);
|
void kReorder(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y, int K, int max_iters);
|
||||||
|
|||||||
@ -162,6 +162,10 @@ void construct_spaces(DetailedPlaceData& db,
|
|||||||
int right_node_id = row2nodes[j + 1];
|
int right_node_id = row2nodes[j + 1];
|
||||||
right_bound = min(right_bound, host_x[right_node_id]);
|
right_bound = min(right_bound, host_x[right_node_id]);
|
||||||
}
|
}
|
||||||
|
// space.xh = right_bound;
|
||||||
|
// NOTE: some designs' fixed nodes are not placed on site (e.g. mgc_edit_dist_a),
|
||||||
|
// fix these cases by aligning them to site
|
||||||
|
// FIXME: need regression
|
||||||
space.xh = std::floor(right_bound);
|
space.xh = std::floor(right_bound);
|
||||||
space.xh = floorDiv(space.xh - db.xl, db.site_width) * db.site_width + db.xl;
|
space.xh = floorDiv(space.xh - db.xl, db.site_width) * db.site_width + db.xl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,8 +178,30 @@ __global__ void move_nodes_kernel(DetailedPlaceDBType db, IndependentSetMatching
|
|||||||
if (j != sol_k) {
|
if (j != sol_k) {
|
||||||
atomicAdd(state.device_num_moved, 1);
|
atomicAdd(state.device_num_moved, 1);
|
||||||
auto const& orig_space = orig_spaces[sol_k];
|
auto const& orig_space = orig_spaces[sol_k];
|
||||||
|
// printf(
|
||||||
|
// "apply cost matrix %d, j %d, node_id %d, sol_k %d, pos_id %d, space (%g, %g), "
|
||||||
|
// "orig_space (%g, %g) xy (%g, %g) orig_xy (%g, %g)\n",
|
||||||
|
// i,
|
||||||
|
// j,
|
||||||
|
// node_id,
|
||||||
|
// sol_k,
|
||||||
|
// independent_set[sol_k],
|
||||||
|
// space.xl,
|
||||||
|
// space.xh,
|
||||||
|
// orig_space.xl,
|
||||||
|
// orig_space.xh,
|
||||||
|
// x,
|
||||||
|
// y,
|
||||||
|
// orig_x[sol_k],
|
||||||
|
// orig_y[sol_k]);
|
||||||
x = orig_x[sol_k];
|
x = orig_x[sol_k];
|
||||||
bool ret = adjust_pos(x, node_width, orig_space);
|
bool ret = adjust_pos(x, node_width, orig_space);
|
||||||
|
if (!ret) {
|
||||||
|
printf("ERROR: ism adjust_pos, node_width: %g, orig_space(%g, %g)\n",
|
||||||
|
node_width,
|
||||||
|
orig_space.xl,
|
||||||
|
orig_space.xh);
|
||||||
|
}
|
||||||
assert(ret);
|
assert(ret);
|
||||||
y = orig_y[sol_k];
|
y = orig_y[sol_k];
|
||||||
space = orig_space;
|
space = orig_space;
|
||||||
|
|||||||
264
cpp_to_py/gpudp/lg/filler_legalize.cpp
Normal file
264
cpp_to_py/gpudp/lg/filler_legalize.cpp
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
#include "gpudp/lg/legalization_db.h"
|
||||||
|
|
||||||
|
namespace dp {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FillerBlank {
|
||||||
|
T xl;
|
||||||
|
T yl;
|
||||||
|
T xh;
|
||||||
|
T yh;
|
||||||
|
int bucket_list_level;
|
||||||
|
|
||||||
|
FillerBlank() {}
|
||||||
|
FillerBlank(T xl_, T yl_, T xh_, T yh_) : xl(xl_), yl(yl_), xh(xh_), yh(yh_) {}
|
||||||
|
void intersect(const FillerBlank& rhs) {
|
||||||
|
xl = std::max(xl, rhs.xl);
|
||||||
|
xh = std::min(xh, rhs.xh);
|
||||||
|
yl = std::max(yl, rhs.yl);
|
||||||
|
yh = std::min(yh, rhs.yh);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void fixCells2Bins(const LegalizationData& db,
|
||||||
|
const float* x,
|
||||||
|
const float* y,
|
||||||
|
const float* node_size_x,
|
||||||
|
const float* node_size_y,
|
||||||
|
float bin_size_x,
|
||||||
|
float bin_size_y,
|
||||||
|
float xl,
|
||||||
|
float yl,
|
||||||
|
float xh,
|
||||||
|
float yh,
|
||||||
|
int num_bins_x,
|
||||||
|
int num_bins_y,
|
||||||
|
int num_nodes,
|
||||||
|
int num_movable_nodes,
|
||||||
|
int num_conn_movable_nodes,
|
||||||
|
std::vector<std::vector<int>>& bin_cells) {
|
||||||
|
// do not handle large macros
|
||||||
|
// one cell cannot be distributed to one bin
|
||||||
|
for (int i = 0; i < num_nodes; i += 1) {
|
||||||
|
if (i < num_conn_movable_nodes || i >= num_movable_nodes) {
|
||||||
|
int bin_id_x = (x[i] + node_size_x[i] / 2 - xl) / bin_size_x;
|
||||||
|
int bin_id_y = (y[i] + node_size_y[i] / 2 - yl) / bin_size_y;
|
||||||
|
|
||||||
|
bin_id_x = std::min(std::max(bin_id_x, 0), num_bins_x - 1);
|
||||||
|
bin_id_y = std::min(std::max(bin_id_y, 0), num_bins_y - 1);
|
||||||
|
|
||||||
|
int bin_id = bin_id_x * num_bins_y + bin_id_y;
|
||||||
|
|
||||||
|
bin_cells[bin_id].push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sort bin cells
|
||||||
|
for (int i = 0; i < num_bins_x * num_bins_y; i += 1) {
|
||||||
|
std::vector<int>& cells = bin_cells.at(i);
|
||||||
|
std::sort(cells.begin(), cells.end(), [&](int node_id1, int node_id2) {
|
||||||
|
float x1 = x[node_id1];
|
||||||
|
float x2 = x[node_id2];
|
||||||
|
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reduceBlanks(const float* x,
|
||||||
|
const float* y,
|
||||||
|
const float* node_size_x,
|
||||||
|
const float* node_size_y,
|
||||||
|
const std::vector<std::vector<int>>& bin_cells,
|
||||||
|
float bin_size_x,
|
||||||
|
float bin_size_y,
|
||||||
|
float xl,
|
||||||
|
float yl,
|
||||||
|
float xh,
|
||||||
|
float yh,
|
||||||
|
float site_width,
|
||||||
|
float row_height,
|
||||||
|
int num_bins_x,
|
||||||
|
int num_bins_y,
|
||||||
|
std::vector<std::vector<FillerBlank<float>>>& bin_blanks) {
|
||||||
|
for (int i = 0; i < num_bins_x * num_bins_y; i += 1) {
|
||||||
|
int bin_id_x = i / num_bins_y;
|
||||||
|
int bin_id_y = i - bin_id_x * num_bins_y;
|
||||||
|
int bin_id = bin_id_x * num_bins_y + bin_id_y;
|
||||||
|
|
||||||
|
float bin_xl = xl + bin_id_x * bin_size_x;
|
||||||
|
float bin_xh = std::min(bin_xl + bin_size_x, xh);
|
||||||
|
float bin_yl = yl + bin_id_y * bin_size_y;
|
||||||
|
float bin_yh = std::min(bin_yl + bin_size_y, yh);
|
||||||
|
|
||||||
|
FillerBlank<float> blank;
|
||||||
|
blank.xl = floorDiv((bin_xl - xl), site_width) * site_width + xl; // align blanks to sites
|
||||||
|
blank.xh = floorDiv((bin_xh - xl), site_width) * site_width + xl; // align blanks to sites
|
||||||
|
blank.yl = bin_yl;
|
||||||
|
blank.yh = bin_yl + row_height;
|
||||||
|
|
||||||
|
bin_blanks.at(bin_id).push_back(blank);
|
||||||
|
|
||||||
|
const std::vector<int>& cells = bin_cells.at(i);
|
||||||
|
std::vector<FillerBlank<float>>& blanks = bin_blanks.at(bin_id);
|
||||||
|
|
||||||
|
for (unsigned int ci = 0; ci < cells.size(); ++ci) {
|
||||||
|
int node_id = cells.at(ci);
|
||||||
|
float node_xl = x[node_id];
|
||||||
|
float node_yl = y[node_id];
|
||||||
|
float node_xh = node_xl + node_size_x[node_id];
|
||||||
|
float node_yh = node_yl + node_size_y[node_id];
|
||||||
|
|
||||||
|
if (blanks.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FillerBlank<float>& blank = blanks.back();
|
||||||
|
|
||||||
|
if (node_xh > blank.xl && node_xl < blank.xh) // overlap
|
||||||
|
{
|
||||||
|
if (node_xl == blank.xl && node_xh == blank.xh) // remove
|
||||||
|
{
|
||||||
|
blanks.pop_back();
|
||||||
|
}
|
||||||
|
if (node_xl == blank.xl && node_xh < blank.xh) // reduce
|
||||||
|
{
|
||||||
|
blank.xl = node_xh;
|
||||||
|
}
|
||||||
|
if (node_xl > blank.xl && node_xh == blank.xh) // reduce
|
||||||
|
{
|
||||||
|
blank.xh = node_xl;
|
||||||
|
}
|
||||||
|
if (node_xl > blank.xl && node_xh < blank.xh) // split
|
||||||
|
{
|
||||||
|
FillerBlank<float> new_blank(node_xh, blank.yl, blank.xh, blank.yh);
|
||||||
|
blank.xh = node_xl;
|
||||||
|
blanks.push_back(new_blank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // print blanks
|
||||||
|
// for (int i = 0; i < num_bins_x * num_bins_y; i += 1) {
|
||||||
|
// const std::vector<FillerBlank<float>>& blanks = bin_blanks.at(i);
|
||||||
|
// for (unsigned int j = 0; j < blanks.size(); ++j) {
|
||||||
|
// const FillerBlank<float>& blank = blanks.at(j);
|
||||||
|
// logger.info(
|
||||||
|
// "bin %d: blank %d: xl = %g, xh = %g, yl = %g, yh = %g", i, j, blank.xl, blank.xh, blank.yl, blank.yh);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillerLegalization(DPTorchRawDB& at_db) {
|
||||||
|
LegalizationData db(at_db);
|
||||||
|
|
||||||
|
int num_blanks_x = 1;
|
||||||
|
int num_bins_x = 1;
|
||||||
|
|
||||||
|
// bin dimension in y direction for blanks is different from that for cells
|
||||||
|
int num_blanks_y = floorDiv((db.yh - db.yl), db.row_height);
|
||||||
|
int num_bins_y = num_blanks_y;
|
||||||
|
logger.info("%s num_blanks_y = %d", "Standard cell legalization", num_blanks_y);
|
||||||
|
|
||||||
|
// adjust bin sizes
|
||||||
|
float bin_size_x = (db.xh - db.xl) / static_cast<float>(num_bins_x);
|
||||||
|
float bin_size_y = db.row_height;
|
||||||
|
|
||||||
|
// allocate bin blanks
|
||||||
|
std::vector<std::vector<FillerBlank<float>>> bin_blanks(num_blanks_x * num_blanks_y);
|
||||||
|
std::vector<std::vector<FillerBlank<float>>> bin_blanks_copy(num_blanks_x * num_blanks_y);
|
||||||
|
std::vector<std::vector<int>> bin_cells(num_bins_x * num_bins_y);
|
||||||
|
|
||||||
|
// distribute cells to bins
|
||||||
|
fixCells2Bins(db,
|
||||||
|
db.x,
|
||||||
|
db.y,
|
||||||
|
db.node_size_x,
|
||||||
|
db.node_size_y,
|
||||||
|
bin_size_x,
|
||||||
|
db.row_height,
|
||||||
|
db.xl,
|
||||||
|
db.yl,
|
||||||
|
db.xh,
|
||||||
|
db.yh,
|
||||||
|
num_bins_x,
|
||||||
|
num_bins_y,
|
||||||
|
db.num_nodes,
|
||||||
|
db.num_movable_nodes,
|
||||||
|
db.num_conn_movable_nodes,
|
||||||
|
bin_cells);
|
||||||
|
|
||||||
|
// distribute blanks to bins
|
||||||
|
reduceBlanks(db.x,
|
||||||
|
db.y,
|
||||||
|
db.node_size_x,
|
||||||
|
db.node_size_y,
|
||||||
|
bin_cells,
|
||||||
|
bin_size_x,
|
||||||
|
db.row_height,
|
||||||
|
db.xl,
|
||||||
|
db.yl,
|
||||||
|
db.xh,
|
||||||
|
db.yh,
|
||||||
|
db.site_width,
|
||||||
|
db.row_height,
|
||||||
|
num_bins_x,
|
||||||
|
num_bins_y,
|
||||||
|
bin_blanks);
|
||||||
|
|
||||||
|
// sort all blanks and create blank bucket list
|
||||||
|
int maxDegree = 0;
|
||||||
|
robin_hood::unordered_map<int, vector<FillerBlank<float>>> blank_bucket_list;
|
||||||
|
for (int i = 0; i < num_blanks_x * num_blanks_y; i += 1) {
|
||||||
|
std::vector<FillerBlank<float>>& blanks = bin_blanks.at(i);
|
||||||
|
for (unsigned int j = 0; j < blanks.size(); ++j) {
|
||||||
|
FillerBlank<float>& blank = blanks.at(j);
|
||||||
|
blank.bucket_list_level = roundDiv(blank.xh - blank.xl, db.site_width);
|
||||||
|
maxDegree = std::max(maxDegree, blank.bucket_list_level);
|
||||||
|
blank_bucket_list[blank.bucket_list_level].push_back(blank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("%s maxDegree = %d", "Blanks", maxDegree);
|
||||||
|
|
||||||
|
// sorted filler cell id
|
||||||
|
vector<int> fillers_to_blank(db.num_movable_nodes - db.num_conn_movable_nodes);
|
||||||
|
for (int i = 0; i < db.num_movable_nodes - db.num_conn_movable_nodes; i += 1) {
|
||||||
|
fillers_to_blank[i] = db.num_conn_movable_nodes + i;
|
||||||
|
}
|
||||||
|
std::sort(fillers_to_blank.begin(), fillers_to_blank.end(), [&](int node_id1, int node_id2) {
|
||||||
|
float size_x1 = db.node_size_x[node_id1];
|
||||||
|
float size_x2 = db.node_size_x[node_id2];
|
||||||
|
return size_x1 < size_x2 || (size_x1 == size_x2 && node_id1 < node_id2);
|
||||||
|
});
|
||||||
|
// for (int i = 0; i < db.num_movable_nodes - db.num_conn_movable_nodes; i += 1) {
|
||||||
|
// logger.info("filler %d: size_x = %g", filler_id[i], db.node_size_x[filler_id[i]]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// put filler cells into blanks
|
||||||
|
while (!fillers_to_blank.empty()) {
|
||||||
|
int filler_id = fillers_to_blank.back();
|
||||||
|
int filler_size_int = roundDiv(db.node_size_x[filler_id], db.site_width);
|
||||||
|
FillerBlank<float>& max_blank = blank_bucket_list[maxDegree].back();
|
||||||
|
assert(max_blank.bucket_list_level >= filler_size_int);
|
||||||
|
// update filler position
|
||||||
|
db.x[filler_id] = max_blank.xl;
|
||||||
|
db.y[filler_id] = max_blank.yl;
|
||||||
|
max_blank.xl += db.node_size_x[filler_id];
|
||||||
|
max_blank.bucket_list_level -= filler_size_int;
|
||||||
|
blank_bucket_list[max_blank.bucket_list_level].push_back(max_blank);
|
||||||
|
blank_bucket_list[maxDegree].pop_back();
|
||||||
|
while (blank_bucket_list[maxDegree].empty()) {
|
||||||
|
maxDegree -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillers_to_blank.pop_back();
|
||||||
|
|
||||||
|
// logger.info("put filler %d into blank %d: blank_xl = %g, blank_xh = %g",
|
||||||
|
// filler_id,
|
||||||
|
// max_blank.bucket_list_level,
|
||||||
|
// max_blank.xl,
|
||||||
|
// max_blank.xh);
|
||||||
|
|
||||||
|
// logger.info("num_remaining_fillers = %d, max degree = %d", fillers_to_blank.size(), maxDegree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dp
|
||||||
@ -45,10 +45,16 @@ void distributeCells2Bins(const LegalizationData& db,
|
|||||||
int num_bins_y,
|
int num_bins_y,
|
||||||
int num_nodes,
|
int num_nodes,
|
||||||
int num_movable_nodes,
|
int num_movable_nodes,
|
||||||
std::vector<std::vector<int>>& bin_cells) {
|
int num_conn_movable_nodes,
|
||||||
|
std::vector<std::vector<int>>& bin_cells,
|
||||||
|
bool legalize_filler) {
|
||||||
// do not handle large macros
|
// do not handle large macros
|
||||||
// one cell cannot be distributed to one bin
|
// one cell cannot be distributed to one bin
|
||||||
for (int i = 0; i < num_movable_nodes; i += 1) {
|
int num_legalized_nodes = num_conn_movable_nodes;
|
||||||
|
if (legalize_filler) {
|
||||||
|
num_legalized_nodes = num_movable_nodes;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < num_legalized_nodes; i += 1) {
|
||||||
if (!db.is_dummy_fixed(i)) {
|
if (!db.is_dummy_fixed(i)) {
|
||||||
int bin_id_x = (x[i] + node_size_x[i] / 2 - xl) / bin_size_x;
|
int bin_id_x = (x[i] + node_size_x[i] / 2 - xl) / bin_size_x;
|
||||||
int bin_id_y = (y[i] + node_size_y[i] / 2 - yl) / bin_size_y;
|
int bin_id_y = (y[i] + node_size_y[i] / 2 - yl) / bin_size_y;
|
||||||
@ -527,7 +533,7 @@ void minNodeSize(const std::vector<std::vector<int>>& bin_cells,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void greedyLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y) {
|
void greedyLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y, bool legalize_filler) {
|
||||||
LegalizationData db(at_db);
|
LegalizationData db(at_db);
|
||||||
db.set_num_bins(num_bins_x, num_bins_y);
|
db.set_num_bins(num_bins_x, num_bins_y);
|
||||||
// first from right to left
|
// first from right to left
|
||||||
@ -566,7 +572,9 @@ void greedyLegalization(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y) {
|
|||||||
num_bins_y,
|
num_bins_y,
|
||||||
db.num_nodes,
|
db.num_nodes,
|
||||||
db.num_movable_nodes,
|
db.num_movable_nodes,
|
||||||
bin_cells);
|
db.num_conn_movable_nodes,
|
||||||
|
bin_cells,
|
||||||
|
legalize_filler);
|
||||||
|
|
||||||
// allocate bin fixed cells
|
// allocate bin fixed cells
|
||||||
std::vector<std::vector<int>> bin_fixed_cells(num_bins_x * num_bins_y);
|
std::vector<std::vector<int>> bin_fixed_cells(num_bins_x * num_bins_y);
|
||||||
|
|||||||
@ -82,6 +82,7 @@ public:
|
|||||||
num_threads(at_db.num_threads),
|
num_threads(at_db.num_threads),
|
||||||
num_nodes(at_db.num_nodes),
|
num_nodes(at_db.num_nodes),
|
||||||
num_movable_nodes(at_db.num_movable_nodes),
|
num_movable_nodes(at_db.num_movable_nodes),
|
||||||
|
num_conn_movable_nodes(at_db.num_conn_movable_nodes),
|
||||||
num_nets(at_db.num_nets),
|
num_nets(at_db.num_nets),
|
||||||
num_pins(at_db.num_pins),
|
num_pins(at_db.num_pins),
|
||||||
num_regions(at_db.num_regions) {}
|
num_regions(at_db.num_regions) {}
|
||||||
@ -125,6 +126,7 @@ public:
|
|||||||
float site_width;
|
float site_width;
|
||||||
|
|
||||||
int num_nets;
|
int num_nets;
|
||||||
|
int num_conn_movable_nodes;
|
||||||
int num_movable_nodes;
|
int num_movable_nodes;
|
||||||
int num_nodes;
|
int num_nodes;
|
||||||
int num_pins;
|
int num_pins;
|
||||||
|
|||||||
@ -254,6 +254,7 @@ void GRDatabase::updateUsageLength() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GRDatabase::addFixObs() {
|
void GRDatabase::addFixObs() {
|
||||||
|
logger.info("Marking fixed cell obs...");
|
||||||
fixObs.clear();
|
fixObs.clear();
|
||||||
// 1) add IOPins
|
// 1) add IOPins
|
||||||
for (auto iopin : rawdb.iopins) {
|
for (auto iopin : rawdb.iopins) {
|
||||||
@ -309,6 +310,7 @@ void GRDatabase::addFixObs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GRDatabase::addMovObs() {
|
void GRDatabase::addMovObs() {
|
||||||
|
logger.info("Marking movable cell obs...");
|
||||||
movObs.clear();
|
movObs.clear();
|
||||||
for (auto cell : rawdb.cells) {
|
for (auto cell : rawdb.cells) {
|
||||||
if (!cell->fixed()) {
|
if (!cell->fixed()) {
|
||||||
@ -320,16 +322,7 @@ void GRDatabase::addMovObs() {
|
|||||||
|
|
||||||
void GRDatabase::addCellObs(std::vector<RectOnLayer>& allObs, db::Cell* cell) {
|
void GRDatabase::addCellObs(std::vector<RectOnLayer>& allObs, db::Cell* cell) {
|
||||||
db::CellType* ctype = cell->ctype();
|
db::CellType* ctype = cell->ctype();
|
||||||
int cellOrient = 0;
|
int cellOrient = cell->orient();
|
||||||
if (!cell->flipX() && !cell->flipY()) {
|
|
||||||
cellOrient = 0; // N
|
|
||||||
} else if (cell->flipX() && cell->flipY()) {
|
|
||||||
cellOrient = 2; // S
|
|
||||||
} else if (cell->flipX() && !cell->flipY()) {
|
|
||||||
cellOrient = 4; // FN
|
|
||||||
} else if (!cell->flipX() && cell->flipY()) {
|
|
||||||
cellOrient = 6; // FS
|
|
||||||
}
|
|
||||||
int dx = ctype->originX() + cell->lx();
|
int dx = ctype->originX() + cell->lx();
|
||||||
int dy = ctype->originY() + cell->ly();
|
int dy = ctype->originY() + cell->ly();
|
||||||
// Macro Obs
|
// Macro Obs
|
||||||
@ -386,7 +379,7 @@ void GRDatabase::addCellObs(std::vector<RectOnLayer>& allObs, db::Cell* cell) {
|
|||||||
|
|
||||||
tuple<int, int, int, int> GRDatabase::getOrientOffset(int orient, int lx, int ly, int hx, int hy) {
|
tuple<int, int, int, int> GRDatabase::getOrientOffset(int orient, int lx, int ly, int hx, int hy) {
|
||||||
tuple<int, int, int, int> offset; // lx, ly, hx, hy
|
tuple<int, int, int, int> offset; // lx, ly, hx, hy
|
||||||
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE
|
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
switch (orient) {
|
switch (orient) {
|
||||||
case 0: // N
|
case 0: // N
|
||||||
offset = {lx, ly, hx, hy};
|
offset = {lx, ly, hx, hy};
|
||||||
@ -507,6 +500,19 @@ void GRDatabase::markObs(std::vector<RectOnLayer>& allObs,
|
|||||||
utils::BoxT<int> obsBox(
|
utils::BoxT<int> obsBox(
|
||||||
curObs.lx - margin.x, curObs.ly - margin.y, curObs.hx + margin.x, curObs.hy + margin.y);
|
curObs.lx - margin.x, curObs.ly - margin.y, curObs.hx + margin.x, curObs.hy + margin.y);
|
||||||
|
|
||||||
|
if (obsBox.IsValid()) {
|
||||||
|
if (obsBox.hx() <= gridlines[0][0] || obsBox.hy() <= gridlines[1][0] ||
|
||||||
|
obsBox.lx() >= gridlines[0][gridlines[0].size() - 1] ||
|
||||||
|
obsBox.ly() >= gridlines[1][gridlines[1].size() - 1]) {
|
||||||
|
logger.verbose("ignore obs that is outside gridgraph, obsBox: %d %d %d %d",
|
||||||
|
obsBox.lx(),
|
||||||
|
obsBox.hx(),
|
||||||
|
obsBox.ly(),
|
||||||
|
obsBox.hy());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int xmin =
|
int xmin =
|
||||||
std::upper_bound(gridlines[0].begin(), gridlines[0].end(), obsBox.lx()) - gridlines[0].begin() - 1;
|
std::upper_bound(gridlines[0].begin(), gridlines[0].end(), obsBox.lx()) - gridlines[0].begin() - 1;
|
||||||
int xmax =
|
int xmax =
|
||||||
@ -520,7 +526,15 @@ void GRDatabase::markObs(std::vector<RectOnLayer>& allObs,
|
|||||||
xmax = std::min(xmax, xSize - 1);
|
xmax = std::min(xmax, xSize - 1);
|
||||||
ymax = std::min(ymax, ySize - 1);
|
ymax = std::min(ymax, ySize - 1);
|
||||||
if (xmin > xmax || ymin > ymax) {
|
if (xmin > xmax || ymin > ymax) {
|
||||||
logger.error("continue obs %d %d %d %d", xmin, xmax, ymin, ymax);
|
logger.error("continue, obs: %d %d %d %d, obsBox: %d %d %d %d",
|
||||||
|
xmin,
|
||||||
|
xmax,
|
||||||
|
ymin,
|
||||||
|
ymax,
|
||||||
|
obsBox.lx(),
|
||||||
|
obsBox.hx(),
|
||||||
|
obsBox.ly(),
|
||||||
|
obsBox.hy());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
utils::BoxT<int> grBox(xmin, ymin, xmax, ymax);
|
utils::BoxT<int> grBox(xmin, ymin, xmax, ymax);
|
||||||
@ -745,7 +759,8 @@ void GRDatabase::setupGrNets() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::set<std::tuple<int, int, int>> vis;
|
std::set<std::tuple<int, int, int>> vis;
|
||||||
for (auto& e : pin_shapes) {
|
for (int shapeIdx = 0; shapeIdx < pin_shapes.size(); shapeIdx++) {
|
||||||
|
auto& e = pin_shapes[shapeIdx];
|
||||||
int xmin =
|
int xmin =
|
||||||
std::upper_bound(gridlines[0].begin(), gridlines[0].end(), e.lx) - gridlines[0].begin() - 1;
|
std::upper_bound(gridlines[0].begin(), gridlines[0].end(), e.lx) - gridlines[0].begin() - 1;
|
||||||
int xmax =
|
int xmax =
|
||||||
@ -761,7 +776,37 @@ void GRDatabase::setupGrNets() {
|
|||||||
xmax = std::min(std::max(xmax, 0), xSize - 1);
|
xmax = std::min(std::max(xmax, 0), xSize - 1);
|
||||||
ymax = std::min(std::max(ymax, 0), ySize - 1);
|
ymax = std::min(std::max(ymax, 0), ySize - 1);
|
||||||
if (xmin > xmax || ymin > ymax) {
|
if (xmin > xmax || ymin > ymax) {
|
||||||
logger.error("continue pin %d %d %d %d", xmin, xmax, ymin, ymax);
|
std::string instName = "";
|
||||||
|
std::string instType = "";
|
||||||
|
if (net_pin->iopin != nullptr) {
|
||||||
|
db::IOPin* iopin = net_pin->iopin;
|
||||||
|
instName = iopin->name;
|
||||||
|
instType = iopin->type->name();
|
||||||
|
} else if (net_pin->cell != nullptr) {
|
||||||
|
db::Cell* cell = net_pin->cell;
|
||||||
|
instName = cell->name();
|
||||||
|
instType = cell->ctype()->name;
|
||||||
|
}
|
||||||
|
// NOTE: some benchmarks have strange definition of pin shapes (lx ly hx hy).
|
||||||
|
// For example, in ispd18_test9, one of ADDFHX2 CI shapes is "RECT 2.59 0.40 3.67 0.36".
|
||||||
|
logger.error(
|
||||||
|
"continue netId: %d netName: %s net_pinId: %d | instName: %s instType: %s pinName: %s "
|
||||||
|
"pinShapeId: %d | grid: %d %d %d %d | coord: %d %d %d %d",
|
||||||
|
netId,
|
||||||
|
rawdbNet->name.c_str(),
|
||||||
|
pinIdx,
|
||||||
|
instName.c_str(),
|
||||||
|
instType.c_str(),
|
||||||
|
net_pin->type->name().c_str(),
|
||||||
|
shapeIdx,
|
||||||
|
xmin,
|
||||||
|
xmax,
|
||||||
|
ymin,
|
||||||
|
ymax,
|
||||||
|
e.lx,
|
||||||
|
e.hx,
|
||||||
|
e.ly,
|
||||||
|
e.hy);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int x = xmin; x <= xmax; x++) {
|
for (int x = xmin; x <= xmax; x++) {
|
||||||
|
|||||||
@ -659,6 +659,9 @@ void GPURouter::route(vector<GrNet> &nets, int iter) {
|
|||||||
printf("%d\n", test.check_all(13, 128, 0));
|
printf("%d\n", test.check_all(13, 128, 0));
|
||||||
exit(0);*/
|
exit(0);*/
|
||||||
// const int LEN = 10;
|
// const int LEN = 10;
|
||||||
|
if (std::max(X, Y) >= 2000) {
|
||||||
|
logger.warning("Extremely large gridgraph may cause error during batch generation.");
|
||||||
|
}
|
||||||
if (vis.size() == 0) {
|
if (vis.size() == 0) {
|
||||||
vis.resize(2000, std::vector<short>(2000, 0));
|
vis.resize(2000, std::vector<short>(2000, 0));
|
||||||
visLL.resize(2000, std::vector<short>(2000, 0));
|
visLL.resize(2000, std::vector<short>(2000, 0));
|
||||||
|
|||||||
@ -66,6 +66,41 @@ bool loadParams(const py::dict& kwargs) {
|
|||||||
utils::verbose_parser_log = false;
|
utils::verbose_parser_log = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// global logging level, default is LOG_INFO
|
||||||
|
// need to enable "verbose_parser_log"
|
||||||
|
if (kwargs.contains("global_log_level")) {
|
||||||
|
int log_level = kwargs["global_log_level"].cast<int>();
|
||||||
|
switch (log_level) {
|
||||||
|
case 0:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_DEBUG);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_VERBOSE);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_INFO);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_NOTICE);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_WARN);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_ERROR);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_FATAL);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_OK);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.set_global_log_level(utils::log_level::LOG_INFO);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (kwargs.contains("num_threads")) {
|
if (kwargs.contains("num_threads")) {
|
||||||
db::setting.numThreads = kwargs["num_threads"].cast<int>();
|
db::setting.numThreads = kwargs["num_threads"].cast<int>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -305,6 +305,209 @@ void GPDatabase::setupCheckVar() {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string orient2name(orient_type orient) {
|
||||||
|
switch (orient) {
|
||||||
|
case 0:
|
||||||
|
return "N";
|
||||||
|
case 1:
|
||||||
|
return "W";
|
||||||
|
case 2:
|
||||||
|
return "S";
|
||||||
|
case 3:
|
||||||
|
return "E";
|
||||||
|
case 4:
|
||||||
|
return "FN";
|
||||||
|
case 5:
|
||||||
|
return "FW";
|
||||||
|
case 6:
|
||||||
|
return "FS";
|
||||||
|
case 7:
|
||||||
|
return "FE";
|
||||||
|
case -1:
|
||||||
|
return "NONE";
|
||||||
|
default:
|
||||||
|
return "N";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orient_type hflip_orient(orient_type orient) {
|
||||||
|
// N => FN; W => FW; S => FS; E => FE
|
||||||
|
// FN => N; FW => W; FS => S; FE => E
|
||||||
|
if (orient == -1) {
|
||||||
|
return orient;
|
||||||
|
} else if (orient < 4) {
|
||||||
|
return orient + 4;
|
||||||
|
} else {
|
||||||
|
return orient - 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orient_type rotate_180_orient(orient_type orient) {
|
||||||
|
// N => S; W => E; S => N; E => W
|
||||||
|
// FN => FS; FW => FE; FS => FN; FE => FW
|
||||||
|
if (orient == -1) {
|
||||||
|
return orient;
|
||||||
|
} else if (orient == 0 || orient == 1 || orient == 4 || orient == 5) {
|
||||||
|
return orient + 2;
|
||||||
|
} else {
|
||||||
|
return orient - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orient_type vflip_orient(orient_type orient) { return hflip_orient(rotate_180_orient(orient)); }
|
||||||
|
|
||||||
|
|
||||||
|
void GPDatabase::transferOrient() {
|
||||||
|
// Transfer all gpdb nodes to "N" direction for global placement
|
||||||
|
// NOTE: we don't change rawdb
|
||||||
|
logger.info("Updating gpdb node orient...");
|
||||||
|
|
||||||
|
// 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
|
auto getOrientDegreeFlip = [](orient_type orient) -> std::pair<int, int> {
|
||||||
|
// return value: {degree, flip}
|
||||||
|
if (orient == 0) { // N
|
||||||
|
return {0, 0};
|
||||||
|
} else if (orient == 1) { // W
|
||||||
|
return {90, 0};
|
||||||
|
} else if (orient == 2) { // S
|
||||||
|
return {180, 0};
|
||||||
|
} else if (orient == 3) { // E
|
||||||
|
return {270, 0};
|
||||||
|
} else if (orient == 4) { // FN
|
||||||
|
return {0, 1};
|
||||||
|
} else if (orient == 5) { // FW
|
||||||
|
return {90, 1};
|
||||||
|
} else if (orient == 6) { // FS
|
||||||
|
return {180, 1};
|
||||||
|
} else if (orient == 7) { // FE
|
||||||
|
return {270, 1};
|
||||||
|
} else { // assume NONE is N
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getRotatedSizes = [](int rotDegree, coord_type width, coord_type height) -> std::pair<coord_type, coord_type> {
|
||||||
|
if (rotDegree == 0 || rotDegree == 180) {
|
||||||
|
return {width, height};
|
||||||
|
} else if (rotDegree == 90 || rotDegree == 270) {
|
||||||
|
return {height, width};
|
||||||
|
} else {
|
||||||
|
logger.warning("Unknown rotation degree %d, regarded as 0", rotDegree);
|
||||||
|
return {width, height};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getRotatedPinInfo = [](int rotDegree,
|
||||||
|
coord_type srcNodeWidth,
|
||||||
|
coord_type srcNodeHeight,
|
||||||
|
coord_type srcPinWidth,
|
||||||
|
coord_type srcPinHeight,
|
||||||
|
coord_type srcPinRelLx,
|
||||||
|
coord_type srcPinRelLy) {
|
||||||
|
coord_type dstPinWidth = srcPinWidth;
|
||||||
|
coord_type dstPinHeight = srcPinHeight;
|
||||||
|
coord_type dstPinRelLx = std::numeric_limits<coord_type>::max();
|
||||||
|
coord_type dstPinRelLy = std::numeric_limits<coord_type>::max();
|
||||||
|
switch (rotDegree) {
|
||||||
|
default:
|
||||||
|
logger.warning("Unknown rotation degree %d, regarded as 0", rotDegree);
|
||||||
|
case 0:
|
||||||
|
dstPinRelLx = srcPinRelLx;
|
||||||
|
dstPinRelLy = srcPinRelLy;
|
||||||
|
break;
|
||||||
|
case 180:
|
||||||
|
dstPinRelLx = srcNodeWidth - srcPinRelLx - srcPinWidth;
|
||||||
|
dstPinRelLy = srcNodeHeight - srcPinRelLy - srcPinHeight;
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
dstPinRelLx = srcNodeHeight - srcPinRelLy - srcPinHeight;
|
||||||
|
dstPinRelLy = srcPinRelLx;
|
||||||
|
std::swap(dstPinWidth, dstPinHeight);
|
||||||
|
break;
|
||||||
|
case 270:
|
||||||
|
dstPinRelLx = srcPinRelLy;
|
||||||
|
dstPinRelLy = srcNodeWidth - srcPinRelLx - srcPinWidth;
|
||||||
|
std::swap(dstPinWidth, dstPinHeight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_tuple(dstPinWidth, dstPinHeight, dstPinRelLx, dstPinRelLy);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getFlipYPinRelPos =
|
||||||
|
[](coord_type srcNodeWidth, coord_type srcNodeHeight, coord_type srcPinRelLx, coord_type srcPinRelLy) {
|
||||||
|
// assume the src here are after rotation
|
||||||
|
coord_type dstPinRelLx = srcNodeWidth - srcPinRelLx;
|
||||||
|
coord_type dstPinRelLy = srcPinRelLy;
|
||||||
|
|
||||||
|
return std::make_pair(dstPinRelLx, dstPinRelLy);
|
||||||
|
};
|
||||||
|
|
||||||
|
// create a vector to restore statistics
|
||||||
|
int numOrientTypes = 9; // 0:N, 1:W, 2:S, 3:E, 4:FN, 5:FW, 6:FS, 7:FE, -1:NONE
|
||||||
|
std::vector<int> orient2cnt(numOrientTypes, 0);
|
||||||
|
|
||||||
|
for (auto& node : nodes) {
|
||||||
|
orient_type srcOrient = node.getOrient();
|
||||||
|
if (srcOrient != 0 && srcOrient != -1) {
|
||||||
|
// srcOrient is not "N" or "NONE"
|
||||||
|
orient2cnt[srcOrient]++;
|
||||||
|
auto [srcDegree, srcFlip] = getOrientDegreeFlip(srcOrient);
|
||||||
|
auto [dstDegree, dstFlip] = getOrientDegreeFlip(0); // dst: N
|
||||||
|
|
||||||
|
// compute rotation degree and flipping Y
|
||||||
|
int rotDegree = (dstDegree - srcDegree + 360) % 360;
|
||||||
|
bool flipY = (dstFlip != srcFlip);
|
||||||
|
|
||||||
|
auto [dstNodeWidth, dstNodeHeight] = getRotatedSizes(rotDegree, node.getWidth(), node.getHeight());
|
||||||
|
|
||||||
|
for (auto& pin_id : node.pins()) {
|
||||||
|
auto& pin = pins[pin_id];
|
||||||
|
auto [dstPinWidth, dstPinHeight, dstPinRelLx, dstPinRelLy] = getRotatedPinInfo(rotDegree,
|
||||||
|
node.getWidth(),
|
||||||
|
node.getHeight(),
|
||||||
|
pin.getWidth(),
|
||||||
|
pin.getHeight(),
|
||||||
|
pin.getRelLx(),
|
||||||
|
pin.getRelLy());
|
||||||
|
pin.setWidth(dstPinWidth);
|
||||||
|
pin.setHeight(dstPinHeight);
|
||||||
|
pin.setRelLx(dstPinRelLx);
|
||||||
|
pin.setRelLy(dstPinRelLy);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.setWidth(dstNodeWidth);
|
||||||
|
node.setHeight(dstNodeHeight);
|
||||||
|
|
||||||
|
if (flipY) {
|
||||||
|
for (auto& pin_id : node.pins()) {
|
||||||
|
auto& pin = pins[pin_id];
|
||||||
|
auto [dstPinRelLx, dstPinRelLy] =
|
||||||
|
getFlipYPinRelPos(node.getWidth(), node.getHeight(), pin.getRelLx(), pin.getRelLy());
|
||||||
|
pin.setRelLx(dstPinRelLx);
|
||||||
|
pin.setRelLy(dstPinRelLy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("=== Transfer Node Orient Statistics ===");
|
||||||
|
for (int i = 0; i < orient2cnt.size(); i++) {
|
||||||
|
int count = orient2cnt[i];
|
||||||
|
orient_type orient;
|
||||||
|
if (i == 8) {
|
||||||
|
orient = -1; // NONE
|
||||||
|
} else {
|
||||||
|
orient = i;
|
||||||
|
}
|
||||||
|
std::string orientName = orient2name(orient);
|
||||||
|
if (orient != 0 && orient != -1) {
|
||||||
|
logger.info(" %s => N: %d nodes in gpdb", orientName.c_str(), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("=======================================");
|
||||||
|
}
|
||||||
|
|
||||||
bool GPDatabase::setup() {
|
bool GPDatabase::setup() {
|
||||||
if (db::setting.random_place) {
|
if (db::setting.random_place) {
|
||||||
setup_random_place();
|
setup_random_place();
|
||||||
@ -316,6 +519,7 @@ bool GPDatabase::setup() {
|
|||||||
setupNets();
|
setupNets();
|
||||||
setupIndexMap();
|
setupIndexMap();
|
||||||
setupCheckVar();
|
setupCheckVar();
|
||||||
|
transferOrient();
|
||||||
logger.info("Finish initializing global placement database");
|
logger.info("Finish initializing global placement database");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -600,6 +804,7 @@ std::vector<torch::Tensor> GPDatabase::getSnetInfoTensor() {
|
|||||||
|
|
||||||
void GPDatabase::applyOneNodeOrient(int node_id) {
|
void GPDatabase::applyOneNodeOrient(int node_id) {
|
||||||
auto& node = nodes[node_id];
|
auto& node = nodes[node_id];
|
||||||
|
|
||||||
int rowId;
|
int rowId;
|
||||||
int numRows = database.rows.size();
|
int numRows = database.rows.size();
|
||||||
if (node.getLy() <= database.coreLY) {
|
if (node.getLy() <= database.coreLY) {
|
||||||
@ -611,10 +816,14 @@ void GPDatabase::applyOneNodeOrient(int node_id) {
|
|||||||
rowId = std::max(std::min(rowId, numRows - 1), 0);
|
rowId = std::max(std::min(rowId, numRows - 1), 0);
|
||||||
}
|
}
|
||||||
auto row = database.rows[rowId];
|
auto row = database.rows[rowId];
|
||||||
if (row->flip()) {
|
if (node.getOrient() == -1) {
|
||||||
node.setOrient(6); // FS
|
node.setOrient(row->orient());
|
||||||
} else {
|
} else {
|
||||||
node.setOrient(0); // N
|
if (row->orient() == vflip_orient(node.getOrient())) {
|
||||||
|
node.setOrient(row->orient());
|
||||||
|
} else if (row->orient() == hflip_orient(vflip_orient(node.getOrient()))) {
|
||||||
|
node.setOrient(vflip_orient(node.getOrient()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -186,6 +186,7 @@ public:
|
|||||||
void setupNets();
|
void setupNets();
|
||||||
void setupIndexMap();
|
void setupIndexMap();
|
||||||
void setupCheckVar();
|
void setupCheckVar();
|
||||||
|
void transferOrient();
|
||||||
bool setup();
|
bool setup();
|
||||||
bool reset();
|
bool reset();
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
The following script will automatically download `ispd2005`, `ispd2015`, and `iccad2019` benchmarks in `./data/raw`. It also preprocesses `ispd2015` benchmark to fix some errors when routing them by Innovus®.
|
The following script will automatically download `ispd2005`, `ispd2015`, and `iccad2019` benchmarks in `./data/raw`. It also preprocesses `ispd2015` benchmark to fix some errors when routing them by Innovus®.
|
||||||
```bash
|
```bash
|
||||||
./download_data.sh
|
./download_data.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Note of Fixing ISPD 2015
|
||||||
|
We provide a python scirpt `fix_ispd2015_route.py` to fix some errors in `ispd2015` benchmark. Thus, Innovus now can detailedly routed them.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
**removeDefSNetVias**: Due to numerous DRVs caused by SNet Vias (spacing) after nanoroute routing, we have enabled `removeDefSNetVias` to remove these vias and address the above issue temporarily. It is likely that these vias are oversized, directly violating the spacing rule. While this adjustment has no significant impact on placement, it does result in open SNets. We sincerely encourage and appreciate contributions towards resolving this issue. Your contribution is highly valued and appreciated.
|
||||||
@ -21,7 +21,29 @@ tar xvzf iccad2019.tar.gz
|
|||||||
rm -rf iccad2019.tar.gz
|
rm -rf iccad2019.tar.gz
|
||||||
mv iccad2019/ raw/
|
mv iccad2019/ raw/
|
||||||
|
|
||||||
|
echo "=== Downloading ispd2018 ==="
|
||||||
|
mkdir raw/ispd2018
|
||||||
|
for i in {1..10}
|
||||||
|
do
|
||||||
|
wget --no-check-certificate https://www.ispd.cc/contests/18/ispd18_test$i.tgz
|
||||||
|
tar xvzf ispd18_test$i.tgz
|
||||||
|
rm -rf ispd18_test$i.tgz
|
||||||
|
mv ispd18_test$i/ raw/ispd2018/
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "=== Downloading ispd2019 ==="
|
||||||
|
mkdir raw/ispd2019
|
||||||
|
for i in {1..10}
|
||||||
|
do
|
||||||
|
wget --no-check-certificate https://www.ispd.cc/contests/19/benchmarks/ispd19_test$i.tgz
|
||||||
|
tar xvzf ispd19_test$i.tgz
|
||||||
|
rm -rf ispd19_test$i.tgz
|
||||||
|
mv ispd19_test$i/ raw/ispd2019/
|
||||||
|
done
|
||||||
|
python remove_fence_in_ispd19_test5.py
|
||||||
|
|
||||||
# echo "=== (Optional) Converting raw design to torch data ==="
|
# echo "=== (Optional) Converting raw design to torch data ==="
|
||||||
# python convert_design_to_torch_data.py --dataset ispd2005
|
# python convert_design_to_torch_data.py --dataset ispd2005
|
||||||
# python convert_design_to_torch_data.py --dataset ispd2015_fix
|
# python convert_design_to_torch_data.py --dataset ispd2015_fix
|
||||||
# python convert_design_to_torch_data.py --dataset iccad2019
|
# python convert_design_to_torch_data.py --dataset iccad2019
|
||||||
|
# python convert_design_to_torch_data.py --dataset ispd2019
|
||||||
@ -9,8 +9,12 @@ sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
|||||||
dataset_root = "./raw"
|
dataset_root = "./raw"
|
||||||
# remove fence region related information, including GROUP, REGION
|
# remove fence region related information, including GROUP, REGION
|
||||||
removeDefFence = True
|
removeDefFence = True
|
||||||
# Since there are so many DRCs caused by SNet Vias (spacing) when routing by nanoroute,
|
# Due to numerous DRVs caused by SNet Vias (spacing) after nanoroute routing, we have
|
||||||
# we remove these SNet Vias to avoid them. Note that such modification won't affect placement.
|
# removed these vias to address the issue. It is likely that these vias are oversized,
|
||||||
|
# directly violating the spacing rule. While this adjustment has no significant impact
|
||||||
|
# on placement, it does result in an open SNet. We sincerely encourage and appreciate
|
||||||
|
# contributions towards resolving this issue. Your contribution is highly valued and
|
||||||
|
# appreciated.
|
||||||
removeDefSNetVias = True
|
removeDefSNetVias = True
|
||||||
# Some fixed cell is not placed on manufacture grid, we move them to the nearest grid
|
# Some fixed cell is not placed on manufacture grid, we move them to the nearest grid
|
||||||
fixDefPlaceOnManGrid = True # only for mgc_fft_b, mgc_matrix_mult_b
|
fixDefPlaceOnManGrid = True # only for mgc_fft_b, mgc_matrix_mult_b
|
||||||
@ -27,8 +31,9 @@ moveNDRToLef = True
|
|||||||
# Add default to fix nanoroute via error.
|
# Add default to fix nanoroute via error.
|
||||||
# FIXME: I dont' know which vias in superblue should be set with default...
|
# FIXME: I dont' know which vias in superblue should be set with default...
|
||||||
addDefaultForLefVia = True # only for mgc_superblue_*
|
addDefaultForLefVia = True # only for mgc_superblue_*
|
||||||
# PG Nets will cause a lot of violations with macro OBS, use EXCEPTPGNET to avoid that
|
# PG Nets will cause a lot of violations with macro OBS/Route Blkg, use EXCEPTPGNET to avoid that
|
||||||
eceptPGNetsForObs = True
|
eceptPGNetsForObs = True
|
||||||
|
eceptPGNetsForBlkg = True
|
||||||
|
|
||||||
|
|
||||||
def generate_one_raw_design(input_root, output_root, design_name):
|
def generate_one_raw_design(input_root, output_root, design_name):
|
||||||
@ -207,6 +212,7 @@ def generateDefContent(defLines, design_name):
|
|||||||
|
|
||||||
isSNet, isVia, isNdr = False, False, False
|
isSNet, isVia, isNdr = False, False, False
|
||||||
isRegion, isGroup = False, False
|
isRegion, isGroup = False, False
|
||||||
|
isBlockages = False
|
||||||
jumpToEndComponents = False
|
jumpToEndComponents = False
|
||||||
for lid, line in enumerate(defLines):
|
for lid, line in enumerate(defLines):
|
||||||
if fixDefTracksLayers:
|
if fixDefTracksLayers:
|
||||||
@ -266,6 +272,15 @@ def generateDefContent(defLines, design_name):
|
|||||||
if isGroup or isRegion:
|
if isGroup or isRegion:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if eceptPGNetsForBlkg:
|
||||||
|
if "BLOCKAGES" in line and "END" not in line:
|
||||||
|
isBlockages = True
|
||||||
|
if "END BLOCKAGES" in line:
|
||||||
|
isBlockages = False
|
||||||
|
if isBlockages:
|
||||||
|
if "LAYER" in line:
|
||||||
|
line = line.replace("\n", " + EXCEPTPGNET\n")
|
||||||
|
|
||||||
if fixDefPlaceOnManGrid and "fft_b" in design_name:
|
if fixDefPlaceOnManGrid and "fft_b" in design_name:
|
||||||
if "+ PLACED ( 661359 799490 ) N" in line:
|
if "+ PLACED ( 661359 799490 ) N" in line:
|
||||||
line = line.replace("661359", "661360")
|
line = line.replace("661359", "661360")
|
||||||
|
|||||||
75
data/remove_fence_in_ispd19_test5.py
Normal file
75
data/remove_fence_in_ispd19_test5.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# This script removes the fence region in ispd2019_test5
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||||
|
|
||||||
|
# set dataset root
|
||||||
|
dataset_root = "./raw"
|
||||||
|
# remove fence region related information, including GROUP, REGION
|
||||||
|
removeDefFence = True
|
||||||
|
|
||||||
|
|
||||||
|
def generate_one_raw_design(input_root, output_root, design_name):
|
||||||
|
print("==============")
|
||||||
|
design_root = os.path.join(input_root, design_name)
|
||||||
|
#################### lef ####################
|
||||||
|
defFile = os.path.join(design_root, "%s.input.def" % design_name)
|
||||||
|
lefFile = os.path.join(design_root, "%s.input.lef" % design_name)
|
||||||
|
outputLef = "%s/%s/%s.input.lef" % (output_root, design_name, design_name)
|
||||||
|
if not os.path.exists(os.path.dirname(outputLef)):
|
||||||
|
os.makedirs(os.path.dirname(outputLef))
|
||||||
|
|
||||||
|
if design_name == "ispd19_test5":
|
||||||
|
with open(defFile) as t:
|
||||||
|
defLines = t.readlines()
|
||||||
|
|
||||||
|
#################### def ####################
|
||||||
|
defoutputFile = "%s/%s/%s.input.def" % (output_root, design_name, design_name)
|
||||||
|
|
||||||
|
defcontent = generateDefContent(defLines, design_name)
|
||||||
|
|
||||||
|
with open(defoutputFile, 'w') as f:
|
||||||
|
f.write(defcontent)
|
||||||
|
|
||||||
|
print(defoutputFile)
|
||||||
|
else:
|
||||||
|
os.system("cp %s %s/%s/%s.input.def" % (defFile, output_root, design_name, design_name))
|
||||||
|
|
||||||
|
os.system("cp %s %s/%s/%s.input.lef" % (lefFile, output_root, design_name, design_name))
|
||||||
|
|
||||||
|
def generateDefContent(defLines, design_name):
|
||||||
|
defcontent = ""
|
||||||
|
|
||||||
|
isRegion, isGroup = False, False
|
||||||
|
for lid, line in enumerate(defLines):
|
||||||
|
|
||||||
|
if removeDefFence:
|
||||||
|
if "REGIONS" in line and "END" not in line:
|
||||||
|
isRegion = True
|
||||||
|
continue
|
||||||
|
if "END REGIONS" in line:
|
||||||
|
isRegion = False
|
||||||
|
continue
|
||||||
|
if "GROUPS" in line and "END" not in line:
|
||||||
|
isGroup = True
|
||||||
|
continue
|
||||||
|
if "END GROUPS" in line:
|
||||||
|
isGroup = False
|
||||||
|
continue
|
||||||
|
if isGroup or isRegion:
|
||||||
|
continue
|
||||||
|
|
||||||
|
defcontent += line
|
||||||
|
return defcontent
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raw_root = os.path.join(dataset_root, "ispd2019")
|
||||||
|
all_designs = os.listdir(raw_root)
|
||||||
|
sorted(all_designs)
|
||||||
|
|
||||||
|
# Raw design clean
|
||||||
|
print("-------------------------------------------------")
|
||||||
|
output_root = os.path.join(dataset_root, "ispd2019_no_fence")
|
||||||
|
for design_name in all_designs:
|
||||||
|
generate_one_raw_design(raw_root, output_root, design_name)
|
||||||
11
main.py
11
main.py
@ -39,6 +39,7 @@ def get_option():
|
|||||||
|
|
||||||
# global routing params
|
# global routing params
|
||||||
parser.add_argument('--use_cell_inflate', type=str2bool, default=False, help='use cell inflation')
|
parser.add_argument('--use_cell_inflate', type=str2bool, default=False, help='use cell inflation')
|
||||||
|
parser.add_argument('--min_area_inc', type=float, default=0.01, help='threshold of terminating inflation')
|
||||||
parser.add_argument('--use_route_force', type=str2bool, default=False, help='use routing force')
|
parser.add_argument('--use_route_force', type=str2bool, default=False, help='use routing force')
|
||||||
parser.add_argument('--route_freq', type=int, default=1000, help='routing freq')
|
parser.add_argument('--route_freq', type=int, default=1000, help='routing freq')
|
||||||
parser.add_argument('--num_route_iter', type=int, default=400, help='number of routing iters')
|
parser.add_argument('--num_route_iter', type=int, default=400, help='number of routing iters')
|
||||||
@ -54,7 +55,9 @@ def get_option():
|
|||||||
parser.add_argument('--final_route_eval', type=str2bool, default=False, help='eval placement solution by GR')
|
parser.add_argument('--final_route_eval', type=str2bool, default=False, help='eval placement solution by GR')
|
||||||
|
|
||||||
# logging and saver
|
# logging and saver
|
||||||
parser.add_argument('--log_freq', type=int, default=100)
|
parser.add_argument('--log_freq', type=int, default=100)
|
||||||
|
parser.add_argument('--verbose_cpp_log', type=str2bool, default=False, help='verbose cpp log for debugging')
|
||||||
|
parser.add_argument('--cpp_log_level', type=int, default=2, help='0: DEBUG, 1: VERBOSE, 2:INFO')
|
||||||
parser.add_argument('--result_dir', type=str, default='result', help='log/model root directory')
|
parser.add_argument('--result_dir', type=str, default='result', help='log/model root directory')
|
||||||
parser.add_argument('--exp_id', type=str, default='', help='experiment id')
|
parser.add_argument('--exp_id', type=str, default='', help='experiment id')
|
||||||
parser.add_argument('--log_dir', type=str, default='log', help='log directory')
|
parser.add_argument('--log_dir', type=str, default='log', help='log directory')
|
||||||
@ -76,6 +79,10 @@ def get_option():
|
|||||||
print("We haven't yet support fence region in ispd2015, use ispd2015_fix instead")
|
print("We haven't yet support fence region in ispd2015, use ispd2015_fix instead")
|
||||||
args.dataset = "ispd2015_fix"
|
args.dataset = "ispd2015_fix"
|
||||||
|
|
||||||
|
if args.dataset == "ispd2019":
|
||||||
|
print("We haven't yet support fence region in ispd2019, use ispd2019_no_fence instead")
|
||||||
|
args.dataset = "ispd2019_no_fence"
|
||||||
|
|
||||||
if args.custom_path != "":
|
if args.custom_path != "":
|
||||||
get_custom_design_params(args)
|
get_custom_design_params(args)
|
||||||
|
|
||||||
@ -92,4 +99,4 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@ -58,7 +58,7 @@ def calc_obj_and_grad(
|
|||||||
data.hyperedge_list, data.hyperedge_list_end, data.net_mask,
|
data.hyperedge_list, data.hyperedge_list_end, data.net_mask,
|
||||||
data.hpwl_scale, ps.wa_coeff, args.deterministic
|
data.hpwl_scale, ps.wa_coeff, args.deterministic
|
||||||
)
|
)
|
||||||
mov_node_pos.grad[mov_lhs:mov_rhs] = conn_node_grad_by_wl[mov_lhs:mov_rhs]
|
mov_node_pos.grad[mov_lhs:mov_rhs] += conn_node_grad_by_wl[mov_lhs:mov_rhs]
|
||||||
if ps.enable_sample_force:
|
if ps.enable_sample_force:
|
||||||
if ps.iter > 3 and ps.iter % 20 == 0:
|
if ps.iter > 3 and ps.iter % 20 == 0:
|
||||||
# ps.iter > 3 for warmup
|
# ps.iter > 3 for warmup
|
||||||
|
|||||||
@ -26,9 +26,11 @@ class RouteCache:
|
|||||||
self.original_filler_area_total = None
|
self.original_filler_area_total = None
|
||||||
self.original_pin_rel_cpos: torch.Tensor = None
|
self.original_pin_rel_cpos: torch.Tensor = None
|
||||||
self.original_target_density = None
|
self.original_target_density = None
|
||||||
|
self.original_total_mov_area_without_filler = None
|
||||||
self.original_num_fillers = None
|
self.original_num_fillers = None
|
||||||
self.original_mov_node_size: torch.Tensor = None
|
self.original_mov_node_size: torch.Tensor = None
|
||||||
self.original_mov_node_size_real: torch.Tensor = None
|
self.original_mov_node_size_real: torch.Tensor = None
|
||||||
|
self.original_init_density_map: torch.Tensor = None
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.first_run = True
|
self.first_run = True
|
||||||
@ -44,9 +46,11 @@ class RouteCache:
|
|||||||
self.original_filler_area_total = None
|
self.original_filler_area_total = None
|
||||||
self.original_pin_rel_cpos = None
|
self.original_pin_rel_cpos = None
|
||||||
self.original_target_density = None
|
self.original_target_density = None
|
||||||
|
self.original_total_mov_area_without_filler = None
|
||||||
self.original_num_fillers = None
|
self.original_num_fillers = None
|
||||||
self.original_mov_node_size = None
|
self.original_mov_node_size = None
|
||||||
self.original_mov_node_size_real = None
|
self.original_mov_node_size_real = None
|
||||||
|
self.original_init_density_map = None
|
||||||
|
|
||||||
|
|
||||||
route_cache = RouteCache()
|
route_cache = RouteCache()
|
||||||
@ -471,13 +475,21 @@ def filler_pseudo_wire_force(data, ps, mov_node_pos, mov_node_size, routeforce,
|
|||||||
def route_inflation(
|
def route_inflation(
|
||||||
args, logger, data, rawdb, gpdb, ps, mov_node_pos, mov_node_size, expand_ratio,
|
args, logger, data, rawdb, gpdb, ps, mov_node_pos, mov_node_size, expand_ratio,
|
||||||
constraint_fn=None, skip_m1_route=True, use_weighted_inflation=True, hv_same_ratio=True,
|
constraint_fn=None, skip_m1_route=True, use_weighted_inflation=True, hv_same_ratio=True,
|
||||||
min_area_inc=0.01, decrease_target_density=False, **kwargs
|
dynamic_target_density=True, **kwargs
|
||||||
):
|
):
|
||||||
mov_lhs, mov_rhs = data.movable_index
|
mov_lhs, mov_rhs = data.movable_index
|
||||||
fix_lhs, fix_rhs = data.fixed_connected_index
|
fix_lhs, fix_rhs = data.fixed_connected_index
|
||||||
_, filler_lhs = data.movable_connected_index
|
_, filler_lhs = data.movable_connected_index
|
||||||
filler_rhs = mov_node_pos.shape[0]
|
filler_rhs = mov_node_pos.shape[0]
|
||||||
num_fillers = filler_rhs - filler_lhs
|
num_fillers = filler_rhs - filler_lhs
|
||||||
|
decrease_target_density = False
|
||||||
|
|
||||||
|
# FIXME: How can we dynamically set args.min_area_inc according to the congestion map?
|
||||||
|
# I believe there should be elegant ways to do that like computing local statistics...
|
||||||
|
if args.design_name == "ispd18_test10":
|
||||||
|
# This design is extremely congested in its center.
|
||||||
|
# Temporarily hard coded. This value may not be the best...
|
||||||
|
args.min_area_inc = 0.001
|
||||||
|
|
||||||
if route_cache.first_run:
|
if route_cache.first_run:
|
||||||
# TODO: check args.target_density should be changed or not?
|
# TODO: check args.target_density should be changed or not?
|
||||||
@ -500,6 +512,8 @@ def route_inflation(
|
|||||||
route_cache.original_filler_area_total = torch.sum(torch.prod(filler_size, 1)).item()
|
route_cache.original_filler_area_total = torch.sum(torch.prod(filler_size, 1)).item()
|
||||||
route_cache.original_pin_rel_cpos = data.pin_rel_cpos.clone()
|
route_cache.original_pin_rel_cpos = data.pin_rel_cpos.clone()
|
||||||
route_cache.original_target_density = copy.deepcopy(args.target_density)
|
route_cache.original_target_density = copy.deepcopy(args.target_density)
|
||||||
|
route_cache.original_total_mov_area_without_filler = copy.deepcopy(data.__total_mov_area_without_filler__)
|
||||||
|
route_cache.original_init_density_map = data.init_density_map.clone()
|
||||||
|
|
||||||
ori_mov_node_size = route_cache.original_mov_node_size
|
ori_mov_node_size = route_cache.original_mov_node_size
|
||||||
ori_mov_node_size_real = route_cache.original_mov_node_size_real
|
ori_mov_node_size_real = route_cache.original_mov_node_size_real
|
||||||
@ -508,6 +522,7 @@ def route_inflation(
|
|||||||
# 1) check remain space
|
# 1) check remain space
|
||||||
last_mov_area = torch.prod(mov_node_size_real[mov_lhs:filler_lhs], 1)
|
last_mov_area = torch.prod(mov_node_size_real[mov_lhs:filler_lhs], 1)
|
||||||
last_mov_area_total = last_mov_area.sum().item()
|
last_mov_area_total = last_mov_area.sum().item()
|
||||||
|
last_filler_area_total = torch.sum(torch.prod(mov_node_size_real[filler_lhs:filler_rhs], 1)).item()
|
||||||
max_inc_area_total = min(0.1 * route_cache.whitespace_area, route_cache.placeable_area - last_mov_area_total) # TODO: tune
|
max_inc_area_total = min(0.1 * route_cache.whitespace_area, route_cache.placeable_area - last_mov_area_total) # TODO: tune
|
||||||
if max_inc_area_total <= 0:
|
if max_inc_area_total <= 0:
|
||||||
logger.warning("No space to inflate. Terminate inflation.")
|
logger.warning("No space to inflate. Terminate inflation.")
|
||||||
@ -521,6 +536,7 @@ def route_inflation(
|
|||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
grdb, routeforce, input_mat, cg_mapHV, _, _, route_gradmat, gr_metrics = output
|
grdb, routeforce, input_mat, cg_mapHV, _, _, route_gradmat, gr_metrics = output
|
||||||
|
numOvflNets, gr_wirelength, gr_numVias, gr_numShorts, rc_hor_mean, rc_ver_mean = gr_metrics
|
||||||
|
|
||||||
num_bin_x, num_bin_y = input_mat.shape[0], input_mat.shape[1]
|
num_bin_x, num_bin_y = input_mat.shape[0], input_mat.shape[1]
|
||||||
unit_len_x, unit_len_y = routeforce.gcell_steps()
|
unit_len_x, unit_len_y = routeforce.gcell_steps()
|
||||||
@ -534,6 +550,13 @@ def route_inflation(
|
|||||||
inflate_mat: torch.Tensor = torch.stack((input_mat + 1, input_mat + 1)).contiguous().pow_(2)
|
inflate_mat: torch.Tensor = torch.stack((input_mat + 1, input_mat + 1)).contiguous().pow_(2)
|
||||||
else:
|
else:
|
||||||
inflate_mat: torch.Tensor = (cg_mapHV + 1).permute(0, 2, 1).contiguous()
|
inflate_mat: torch.Tensor = (cg_mapHV + 1).permute(0, 2, 1).contiguous()
|
||||||
|
if dynamic_target_density and last_filler_area_total / last_mov_area_total > 1.1 and numOvflNets / data.num_nets > 0.04:
|
||||||
|
# filler area too large => low utilization, can adjust size more aggressively to reduce GR overflow
|
||||||
|
max_inc_area_total = route_cache.placeable_area - last_mov_area_total
|
||||||
|
logger.info("Low utilization detect, globally inflate...")
|
||||||
|
global_ratio = (rc_hor_mean + rc_ver_mean) / 2
|
||||||
|
inflate_mat *= global_ratio
|
||||||
|
decrease_target_density = True
|
||||||
inflate_mat.clamp_(min=1.0, max=2.0)
|
inflate_mat.clamp_(min=1.0, max=2.0)
|
||||||
|
|
||||||
# NOTE: 1) If use_weighted_inflation == False, use max congestion as inflation ratio.
|
# NOTE: 1) If use_weighted_inflation == False, use max congestion as inflation ratio.
|
||||||
@ -556,6 +579,10 @@ def route_inflation(
|
|||||||
inc_mov_area = expect_new_mov_area - last_mov_area
|
inc_mov_area = expect_new_mov_area - last_mov_area
|
||||||
inc_mov_area_total = inc_mov_area.sum().item()
|
inc_mov_area_total = inc_mov_area.sum().item()
|
||||||
inc_area_scale = max_inc_area_total / inc_mov_area_total
|
inc_area_scale = max_inc_area_total / inc_mov_area_total
|
||||||
|
if inc_mov_area_total <= 0:
|
||||||
|
logger.warning("Negative area increment %.4f. Early terminate cell inflation." % (inc_mov_area_total))
|
||||||
|
ps.use_cell_inflate = False # not inflation anymore
|
||||||
|
return gr_metrics, None, None
|
||||||
if inc_area_scale < 1:
|
if inc_area_scale < 1:
|
||||||
logger.warning("Not enough space to inflate. Scale down.")
|
logger.warning("Not enough space to inflate. Scale down.")
|
||||||
inc_mov_area *= inc_area_scale
|
inc_mov_area *= inc_area_scale
|
||||||
@ -569,10 +596,10 @@ def route_inflation(
|
|||||||
new_mov_node_size_real: torch.Tensor = mov_node_size_real.clone()
|
new_mov_node_size_real: torch.Tensor = mov_node_size_real.clone()
|
||||||
new_mov_node_size_real[mov_lhs:filler_lhs].mul_(this_mov_conn_inflate_ratio)
|
new_mov_node_size_real[mov_lhs:filler_lhs].mul_(this_mov_conn_inflate_ratio)
|
||||||
|
|
||||||
if inc_mov_area_total / last_mov_area_total < min_area_inc:
|
if inc_mov_area_total / last_mov_area_total < args.min_area_inc:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Too small relative area increment (%.4f < %.4f). Early terminate cell inflation." % (
|
"Too small relative area increment (%.4f < %.4f). Early terminate cell inflation." % (
|
||||||
inc_mov_area_total / last_mov_area_total, min_area_inc
|
inc_mov_area_total / last_mov_area_total, args.min_area_inc
|
||||||
))
|
))
|
||||||
ps.use_cell_inflate = False # not inflation anymore
|
ps.use_cell_inflate = False # not inflation anymore
|
||||||
return gr_metrics, None, None
|
return gr_metrics, None, None
|
||||||
@ -580,13 +607,13 @@ def route_inflation(
|
|||||||
# 5) update total filler inflation ratio
|
# 5) update total filler inflation ratio
|
||||||
new_mov_area_total = last_mov_area_total + inc_mov_area_total
|
new_mov_area_total = last_mov_area_total + inc_mov_area_total
|
||||||
new_filler_area_total = 0.0
|
new_filler_area_total = 0.0
|
||||||
last_filler_area_total = torch.sum(torch.prod(mov_node_size_real[filler_lhs:filler_rhs], 1)).item()
|
|
||||||
filler_scale = 0.0
|
filler_scale = 0.0
|
||||||
if new_mov_area_total + last_filler_area_total > route_cache.target_area:
|
if new_mov_area_total + last_filler_area_total > route_cache.target_area:
|
||||||
new_filler_area_total = max(route_cache.target_area - new_mov_area_total, 0)
|
new_filler_area_total = max(route_cache.target_area - new_mov_area_total, 0)
|
||||||
if decrease_target_density and new_filler_area_total / route_cache.placeable_area > 0.2:
|
if decrease_target_density:
|
||||||
# remove some pre-inserted fillers / FloatMov nodes to decrease the target density
|
logger.info("Removing some pre-inserted fillers / FloatMov nodes to decrease the target density...")
|
||||||
new_target_density = max(0.8, 0.85 * 1.0)
|
# standard cell density: 1 / (1 + 1.1) = 0.4762
|
||||||
|
new_target_density = max(0.4762, 0.85 * args.target_density)
|
||||||
new_target_area = new_target_density * route_cache.placeable_area
|
new_target_area = new_target_density * route_cache.placeable_area
|
||||||
new_filler_area_total = max(new_target_area - new_mov_area_total, 0)
|
new_filler_area_total = max(new_target_area - new_mov_area_total, 0)
|
||||||
filler_scale = new_filler_area_total / route_cache.original_filler_area_total
|
filler_scale = new_filler_area_total / route_cache.original_filler_area_total
|
||||||
@ -594,11 +621,9 @@ def route_inflation(
|
|||||||
num_remain_cells = filler_lhs + math.ceil(filler_scale * original_num_fillers)
|
num_remain_cells = filler_lhs + math.ceil(filler_scale * original_num_fillers)
|
||||||
|
|
||||||
route_cache.target_area = new_target_area
|
route_cache.target_area = new_target_area
|
||||||
new_mov_node_size_real = new_mov_node_size_real[:num_remain_cells]
|
# set filler size as 0 to remove
|
||||||
mov_node_size_real = mov_node_size_real[:num_remain_cells]
|
new_mov_node_size_real[num_remain_cells:] = 0
|
||||||
logger.warning("Remove nodes to reduce target density from %.4f to %.4f. \
|
mov_node_size_real[num_remain_cells:] = 0
|
||||||
This step may remove some FloatMov. #Nodes from %d to %d" %
|
|
||||||
(old_target_density, args.target_density, filler_rhs, num_remain_cells))
|
|
||||||
elif route_cache.original_filler_area_total > 0:
|
elif route_cache.original_filler_area_total > 0:
|
||||||
filler_scale = math.sqrt(new_filler_area_total / route_cache.original_filler_area_total)
|
filler_scale = math.sqrt(new_filler_area_total / route_cache.original_filler_area_total)
|
||||||
new_mov_node_size_real[filler_lhs:filler_rhs] = filler_scale * ori_mov_node_size_real[filler_lhs:filler_rhs]
|
new_mov_node_size_real[filler_lhs:filler_rhs] = filler_scale * ori_mov_node_size_real[filler_lhs:filler_rhs]
|
||||||
@ -620,7 +645,19 @@ def route_inflation(
|
|||||||
args.target_density = (new_mov_area_total + new_filler_area_total) / route_cache.placeable_area
|
args.target_density = (new_mov_area_total + new_filler_area_total) / route_cache.placeable_area
|
||||||
logger.info("Update target density from %.4f to %.4f" % (old_target_density, args.target_density))
|
logger.info("Update target density from %.4f to %.4f" % (old_target_density, args.target_density))
|
||||||
|
|
||||||
logger.info("Relative area | increment: %.4f, mov: %.4f, filler: %.4f, all_cells: %.4f" % (
|
if decrease_target_density:
|
||||||
|
# since we decrease target density, update the init density map correspondingly
|
||||||
|
logger.warning("Remove nodes to reduce target density from %.4f to %.4f. This step may remove some FloatMov. #Nodes from %d to %d" %
|
||||||
|
(old_target_density, args.target_density, filler_rhs, num_remain_cells))
|
||||||
|
data.init_density_map.clamp_(min=0.0, max=1.0).div_(old_target_density).mul_(args.target_density)
|
||||||
|
|
||||||
|
logger.info("Absolute area (last) | mov: %.4E, filler: %.4E, all_cells: %.4E" % (
|
||||||
|
last_mov_area_total, last_filler_area_total, last_mov_area_total + last_filler_area_total
|
||||||
|
))
|
||||||
|
logger.info("Absolute area (this) | mov: %.4E, filler: %.4E, all_cells: %.4E" % (
|
||||||
|
new_mov_area_total, new_filler_area_total, new_mov_area_total + new_filler_area_total
|
||||||
|
))
|
||||||
|
logger.info("Relative area change | increment: %.4f, mov: %.4f, filler: %.4f, all_cells: %.4f" % (
|
||||||
inc_mov_area_total / last_mov_area_total,
|
inc_mov_area_total / last_mov_area_total,
|
||||||
new_mov_area_total / last_mov_area_total,
|
new_mov_area_total / last_mov_area_total,
|
||||||
new_filler_area_total / last_filler_area_total if last_filler_area_total > 1e-5 else 0,
|
new_filler_area_total / last_filler_area_total if last_filler_area_total > 1e-5 else 0,
|
||||||
@ -656,6 +693,11 @@ def route_inflation(
|
|||||||
expand_ratio = mov_node_area / clamp_mov_node_area
|
expand_ratio = mov_node_area / clamp_mov_node_area
|
||||||
mov_node_size = clamp_mov_node_size
|
mov_node_size = clamp_mov_node_size
|
||||||
|
|
||||||
|
if decrease_target_density:
|
||||||
|
# FIXME: should we update total_mov_area_without_filler when decrease_target_density == False?
|
||||||
|
mov_cell_area = torch.prod(new_mov_node_size_real[mov_lhs:mov_rhs, ...], 1)
|
||||||
|
data.__total_mov_area_without_filler__ = torch.sum(mov_cell_area).item()
|
||||||
|
|
||||||
ps.use_cell_inflate = True
|
ps.use_cell_inflate = True
|
||||||
return gr_metrics, mov_node_size, expand_ratio
|
return gr_metrics, mov_node_size, expand_ratio
|
||||||
|
|
||||||
@ -665,5 +707,8 @@ def route_inflation_roll_back(args, logger, data, mov_node_size):
|
|||||||
mov_lhs, mov_rhs = data.movable_index
|
mov_lhs, mov_rhs = data.movable_index
|
||||||
mov_node_size[mov_lhs:mov_rhs].copy_(route_cache.original_mov_node_size[mov_lhs:mov_rhs])
|
mov_node_size[mov_lhs:mov_rhs].copy_(route_cache.original_mov_node_size[mov_lhs:mov_rhs])
|
||||||
data.pin_rel_cpos.copy_(route_cache.original_pin_rel_cpos)
|
data.pin_rel_cpos.copy_(route_cache.original_pin_rel_cpos)
|
||||||
args.target_density = route_cache.original_target_density
|
data.__total_mov_area_without_filler__ = route_cache.original_total_mov_area_without_filler
|
||||||
|
if args.target_density != route_cache.original_target_density:
|
||||||
|
args.target_density = route_cache.original_target_density
|
||||||
|
data.init_density_map.copy_(route_cache.original_init_density_map)
|
||||||
route_cache.reset()
|
route_cache.reset()
|
||||||
|
|||||||
@ -17,14 +17,16 @@ def load_dataset(args, logger, placement=None):
|
|||||||
if args.load_from_raw:
|
if args.load_from_raw:
|
||||||
logger.info("loading from original benchmark...")
|
logger.info("loading from original benchmark...")
|
||||||
rawdb, gpdb = parser.read(
|
rawdb, gpdb = parser.read(
|
||||||
params, verbose_log=False, lite_mode=True, random_place=False, num_threads=args.num_threads
|
params, verbose_log=args.verbose_cpp_log, log_level=args.cpp_log_level,
|
||||||
|
lite_mode=True, random_place=False, num_threads=args.num_threads
|
||||||
)
|
)
|
||||||
design_info = parser.preprocess_design_info(gpdb)
|
design_info = parser.preprocess_design_info(gpdb)
|
||||||
else:
|
else:
|
||||||
logger.info("loading from pt benchmark...")
|
logger.info("loading from pt benchmark...")
|
||||||
design_pt_path = "./data/cad/%s/%s.pt" % (args.dataset, args.design_name)
|
design_pt_path = "./data/cad/%s/%s.pt" % (args.dataset, args.design_name)
|
||||||
parser.load_params(
|
parser.load_params(
|
||||||
params, verbose_log=False, lite_mode=True, random_place=False, num_threads=args.num_threads
|
params, verbose_log=args.verbose_cpp_log, log_level=args.cpp_log_level,
|
||||||
|
lite_mode=True, random_place=False, num_threads=args.num_threads
|
||||||
)
|
)
|
||||||
design_info = torch.load(design_pt_path)
|
design_info = torch.load(design_pt_path)
|
||||||
gpdb = None
|
gpdb = None
|
||||||
@ -140,10 +142,11 @@ class PlaceData(object):
|
|||||||
self.__site_height__ = site_info[1]
|
self.__site_height__ = site_info[1]
|
||||||
self.__row_height__ = site_info[1] # the same as site height
|
self.__row_height__ = site_info[1] # the same as site height
|
||||||
|
|
||||||
self.__ori_die_lx__ = die_info[0].item()
|
lx, hx, ly, hy = die_info.cpu().numpy()
|
||||||
self.__ori_die_hx__ = die_info[1].item()
|
self.__ori_die_lx__ = lx
|
||||||
self.__ori_die_ly__ = die_info[2].item()
|
self.__ori_die_hx__ = hx
|
||||||
self.__ori_die_hy__ = die_info[3].item()
|
self.__ori_die_ly__ = ly
|
||||||
|
self.__ori_die_hy__ = hy
|
||||||
|
|
||||||
self.__num_nodes__ = node_pos.shape[0]
|
self.__num_nodes__ = node_pos.shape[0]
|
||||||
self.__num_pins__ = pin_id2node_id.shape[0]
|
self.__num_pins__ = pin_id2node_id.shape[0]
|
||||||
@ -489,7 +492,7 @@ class PlaceData(object):
|
|||||||
|
|
||||||
def preshift(self):
|
def preshift(self):
|
||||||
# shift die info to (0.0, hx, 0.0, hy)
|
# shift die info to (0.0, hx, 0.0, hy)
|
||||||
die_lx, _, die_ly, _ = self.die_info.tolist()
|
die_lx, _, die_ly, _ = self.die_info.cpu().numpy()
|
||||||
die_shift = torch.tensor(
|
die_shift = torch.tensor(
|
||||||
[die_lx, die_ly], dtype=self.die_info.dtype, device=self.die_info.device,
|
[die_lx, die_ly], dtype=self.die_info.dtype, device=self.die_info.device,
|
||||||
)
|
)
|
||||||
@ -519,7 +522,7 @@ class PlaceData(object):
|
|||||||
|
|
||||||
def prescale(self):
|
def prescale(self):
|
||||||
# scale die info to (0.0, 1.0, 0.0, 1.0)
|
# scale die info to (0.0, 1.0, 0.0, 1.0)
|
||||||
die_lx, die_hx, die_ly, die_hy = self.die_info.tolist()
|
die_lx, die_hx, die_ly, die_hy = self.die_info.cpu().numpy()
|
||||||
die_scale = torch.tensor(
|
die_scale = torch.tensor(
|
||||||
[die_hx - die_lx, die_hy - die_ly],
|
[die_hx - die_lx, die_hy - die_ly],
|
||||||
dtype=self.die_info.dtype,
|
dtype=self.die_info.dtype,
|
||||||
@ -543,10 +546,11 @@ class PlaceData(object):
|
|||||||
def pre_compute_var(self):
|
def pre_compute_var(self):
|
||||||
args = self.__args__
|
args = self.__args__
|
||||||
device = self.node_size.get_device()
|
device = self.node_size.get_device()
|
||||||
|
dtype = self.node_size.dtype
|
||||||
# die related
|
# die related
|
||||||
lx, hx, ly, hy = self.die_info.tolist()
|
lx, hx, ly, hy = self.die_info.cpu().numpy()
|
||||||
self.unit_len = torch.tensor(
|
self.unit_len = torch.tensor(
|
||||||
[(hx - lx) / self.num_bin_x, (hy - ly) / self.num_bin_y], device=device
|
[(hx - lx) / self.num_bin_x, (hy - ly) / self.num_bin_y], device=device, dtype=dtype
|
||||||
)
|
)
|
||||||
self.die_ur = self.die_info.reshape(2, 2).t()[1].clone()
|
self.die_ur = self.die_info.reshape(2, 2).t()[1].clone()
|
||||||
self.die_ll = self.die_info.reshape(2, 2).t()[0].clone()
|
self.die_ll = self.die_info.reshape(2, 2).t()[0].clone()
|
||||||
@ -742,7 +746,7 @@ class PlaceData(object):
|
|||||||
num_fltiopin,
|
num_fltiopin,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
content += "Core Info " + str(self.die_info.tolist()) + "\n"
|
content += "Core Info " + str([i for i in self.die_info.cpu().numpy()]) + "\n"
|
||||||
content += "Site Width = %d, Row Height = %d\n" % (
|
content += "Site Width = %d, Row Height = %d\n" % (
|
||||||
self.site_width,
|
self.site_width,
|
||||||
self.site_height,
|
self.site_height,
|
||||||
|
|||||||
@ -145,14 +145,21 @@ def rearrange_dpdb_node_info(node_pos: torch.Tensor, data: PlaceData):
|
|||||||
|
|
||||||
|
|
||||||
def setup_detailed_rawdb(
|
def setup_detailed_rawdb(
|
||||||
node_pos: torch.Tensor, use_cpu_db_: bool, data: PlaceData, args, logger
|
node_pos: torch.Tensor, use_cpu_db_: bool, data: PlaceData, args, logger, after_lg=True
|
||||||
):
|
):
|
||||||
curr_site_width = 1.0 # prescale_by_site_width
|
curr_site_width = 1.0 # prescale_by_site_width
|
||||||
node_lpos, node_size, node_weight, pin_id2node_id, node2pin_list, node2pin_list_end = rearrange_dpdb_node_info(
|
node_lpos, node_size, node_weight, pin_id2node_id, node2pin_list, node2pin_list_end = rearrange_dpdb_node_info(
|
||||||
node_pos, data
|
node_pos, data
|
||||||
)
|
)
|
||||||
|
if after_lg:
|
||||||
|
# NOTE: we assume all legalized cells are on integer system
|
||||||
|
# this step can avoid some potential floating-point precision errors
|
||||||
|
_, floatmov_rhs, _ = data.node_type_indices[1]
|
||||||
|
inv_scalar = round(1.0 / get_ori_scale_factor(data))
|
||||||
|
node_lpos[:floatmov_rhs].mul_(inv_scalar).round_().div_(inv_scalar)
|
||||||
|
|
||||||
mov_lhs, mov_rhs = data.movable_index
|
mov_lhs, mov_rhs = data.movable_index
|
||||||
|
conn_mov_lhs, conn_mov_rhs = data.movable_connected_index
|
||||||
if args.scale_design:
|
if args.scale_design:
|
||||||
# scale back
|
# scale back
|
||||||
die_scale = data.die_scale / data.site_width # assume site width == 1 in dp
|
die_scale = data.die_scale / data.site_width # assume site width == 1 in dp
|
||||||
@ -179,12 +186,9 @@ def setup_detailed_rawdb(
|
|||||||
num_iopin = iopin_rhs - fix_rhs
|
num_iopin = iopin_rhs - fix_rhs
|
||||||
num_floatiopin = floatiopin_rhs - blkg_rhs
|
num_floatiopin = floatiopin_rhs - blkg_rhs
|
||||||
|
|
||||||
die_info = die_info.cpu()
|
xl, xh, yl, yh = die_info.cpu().numpy()
|
||||||
xl = die_info[0].item()
|
|
||||||
xh = die_info[1].item()
|
|
||||||
yl = die_info[2].item()
|
|
||||||
yh = die_info[3].item()
|
|
||||||
num_movable_nodes = mov_rhs - mov_lhs
|
num_movable_nodes = mov_rhs - mov_lhs
|
||||||
|
num_conn_movable_nodes = conn_mov_rhs - conn_mov_lhs
|
||||||
num_nodes = node_lpos.shape[0] - num_iopin - num_floatiopin
|
num_nodes = node_lpos.shape[0] - num_iopin - num_floatiopin
|
||||||
site_width = curr_site_width
|
site_width = curr_site_width
|
||||||
row_height = data.row_height / data.site_width
|
row_height = data.row_height / data.site_width
|
||||||
@ -213,6 +217,7 @@ def setup_detailed_rawdb(
|
|||||||
xh,
|
xh,
|
||||||
yl,
|
yl,
|
||||||
yh,
|
yh,
|
||||||
|
num_conn_movable_nodes,
|
||||||
num_movable_nodes,
|
num_movable_nodes,
|
||||||
num_nodes,
|
num_nodes,
|
||||||
site_width,
|
site_width,
|
||||||
@ -238,6 +243,7 @@ def setup_detailed_rawdb(
|
|||||||
xh,
|
xh,
|
||||||
yl,
|
yl,
|
||||||
yh,
|
yh,
|
||||||
|
num_conn_movable_nodes,
|
||||||
num_movable_nodes,
|
num_movable_nodes,
|
||||||
num_nodes,
|
num_nodes,
|
||||||
site_width,
|
site_width,
|
||||||
@ -296,7 +302,7 @@ def commit_to_node_pos(node_pos: torch.Tensor, data:PlaceData, dp_rawdb):
|
|||||||
|
|
||||||
def run_lg(node_pos: torch.Tensor, data: PlaceData, args, logger):
|
def run_lg(node_pos: torch.Tensor, data: PlaceData, args, logger):
|
||||||
# CPU legalization
|
# CPU legalization
|
||||||
lg_rawdb = setup_detailed_rawdb(node_pos, True, data, args, logger)
|
lg_rawdb = setup_detailed_rawdb(node_pos, True, data, args, logger, after_lg=False)
|
||||||
|
|
||||||
# run LG
|
# run LG
|
||||||
logger.info("Start running Macro Legalization...")
|
logger.info("Start running Macro Legalization...")
|
||||||
@ -306,13 +312,38 @@ def run_lg(node_pos: torch.Tensor, data: PlaceData, args, logger):
|
|||||||
lg_rawdb.commit()
|
lg_rawdb.commit()
|
||||||
logger.info("Finish Macro Legalization. Time: %.4f" % (time.time() - ml_time))
|
logger.info("Finish Macro Legalization. Time: %.4f" % (time.time() - ml_time))
|
||||||
|
|
||||||
|
total_cell_area = torch.sum(torch.prod(data.node_size, 1)).item()
|
||||||
|
die_area = torch.prod(data.die_ur - data.die_ll).item()
|
||||||
|
is_high_util = (total_cell_area / die_area) > 0.999
|
||||||
|
logger.info("Utilization: %.2f" % (total_cell_area / die_area))
|
||||||
|
|
||||||
logger.info("Start running Greedy Legalization...")
|
logger.info("Start running Greedy Legalization...")
|
||||||
gl_time = time.time()
|
gl_time = time.time()
|
||||||
num_bins_x, num_bins_y = 1, 64
|
num_bins_x, num_bins_y = 1, 64
|
||||||
gpudp.greedyLegalization(lg_rawdb, num_bins_x, num_bins_y)
|
if not is_high_util:
|
||||||
if not lg_rawdb.check(get_ori_scale_factor(data)):
|
gpudp.greedyLegalization(lg_rawdb, num_bins_x, num_bins_y, True)
|
||||||
logger.error("Check failed in Greedy Legalization")
|
if is_high_util or not lg_rawdb.check(get_ori_scale_factor(data)):
|
||||||
logger.info("Finish Greedy Legalization. Time: %.4f" % (time.time() - gl_time))
|
logger.warning("Check failed in Greedy Legalization. Re-try by Greedy + Filler Legalization.")
|
||||||
|
|
||||||
|
# NOTE: this greedy legalization only legalizes movable connected cells
|
||||||
|
logger.info("Start running Greedy Legalization...")
|
||||||
|
gpudp.greedyLegalization(lg_rawdb, num_bins_x, num_bins_y, False)
|
||||||
|
# NOTE: filler legalization only legalizes movable unconnected cells (fillers)
|
||||||
|
logger.info("Start Filler Legalization...")
|
||||||
|
gpudp.fillerLegalization(lg_rawdb)
|
||||||
|
if not lg_rawdb.check(get_ori_scale_factor(data)):
|
||||||
|
logger.error("Check failed in Greedy + Filler Legalization.")
|
||||||
|
logger.info("Finish Greedy + Filler Legalization. Time: %.4f" % (time.time() - gl_time))
|
||||||
|
else:
|
||||||
|
logger.info("Finish Greedy Legalization. Time: %.4f" % (time.time() - gl_time))
|
||||||
|
|
||||||
|
# # Commit result
|
||||||
|
# commit_to_node_pos(node_pos, data, lg_rawdb)
|
||||||
|
# torch.cuda.synchronize(node_pos.device)
|
||||||
|
# if args.scale_design:
|
||||||
|
# node_pos /= data.die_scale
|
||||||
|
# info = (-1, 0, data.design_name)
|
||||||
|
# draw_fig_with_cairo_cpp(node_pos, data.node_size, data, info, args, base_size=4096)
|
||||||
|
|
||||||
logger.info("Start running Abacus Legalization...")
|
logger.info("Start running Abacus Legalization...")
|
||||||
al_time = time.time()
|
al_time = time.time()
|
||||||
@ -380,14 +411,16 @@ def run_dp(node_pos: torch.Tensor, data: PlaceData, args, logger):
|
|||||||
ism_iter = 50
|
ism_iter = 50
|
||||||
|
|
||||||
# use integer coordinate systems in DP for better quality
|
# use integer coordinate systems in DP for better quality
|
||||||
scalar = compute_scalar(get_ori_scale_factor(data))
|
# scalar = compute_scalar(get_ori_scale_factor(data))
|
||||||
|
scalar = 1.0
|
||||||
|
|
||||||
def dp_handler(dp_func, func_name, *func_args):
|
def dp_handler(dp_func, func_name, *func_args):
|
||||||
logger.info("Start running %s..." % func_name)
|
logger.info("Start running %s..." % func_name)
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
if scalar != 1.0:
|
if scalar != 1.0:
|
||||||
logger.info("scale dp_rawdb by %g" % (1.0 / scalar))
|
# NOTE: we assume site_width is integer, so 1 / scalar should be an integer
|
||||||
dp_rawdb.scale(1.0 / scalar, True)
|
logger.info("scale dp_rawdb by %g" % round(1.0 / scalar))
|
||||||
|
dp_rawdb.scale(round(1.0 / scalar), True)
|
||||||
dp_func(dp_rawdb, *func_args)
|
dp_func(dp_rawdb, *func_args)
|
||||||
if scalar != 1.0:
|
if scalar != 1.0:
|
||||||
logger.info("scale dp_rawdb back by %g" % scalar)
|
logger.info("scale dp_rawdb back by %g" % scalar)
|
||||||
@ -431,6 +464,11 @@ def run_dp_route_opt(node_pos: torch.Tensor, gpdb, rawdb, ps, data: PlaceData, a
|
|||||||
node_pos[:mov_rhs].detach() - data.node_size[:mov_rhs] / 2,
|
node_pos[:mov_rhs].detach() - data.node_size[:mov_rhs] / 2,
|
||||||
data.node_lpos[mov_rhs:],
|
data.node_lpos[mov_rhs:],
|
||||||
), dim=0).cpu()
|
), dim=0).cpu()
|
||||||
|
# this step can avoid some potential floating-point precision errors
|
||||||
|
_, floatmov_rhs, _ = data.node_type_indices[1]
|
||||||
|
inv_scalar = round(1.0 / get_ori_scale_factor(data))
|
||||||
|
node_lpos[:floatmov_rhs].mul_(inv_scalar).round_().div_(inv_scalar)
|
||||||
|
|
||||||
node_size = data.node_size.cpu()
|
node_size = data.node_size.cpu()
|
||||||
if args.scale_design:
|
if args.scale_design:
|
||||||
# scale back
|
# scale back
|
||||||
@ -441,10 +479,7 @@ def run_dp_route_opt(node_pos: torch.Tensor, gpdb, rawdb, ps, data: PlaceData, a
|
|||||||
site_width = 1.0
|
site_width = 1.0
|
||||||
row_height = data.row_height / data.site_width
|
row_height = data.row_height / data.site_width
|
||||||
die_info = data.die_info.cpu()
|
die_info = data.die_info.cpu()
|
||||||
dieLX = die_info[0].item()
|
dieLX, dieHX, dieLY, dieHY = die_info.numpy()
|
||||||
dieHX = die_info[1].item()
|
|
||||||
dieLY = die_info[2].item()
|
|
||||||
dieHY = die_info[3].item()
|
|
||||||
K = 5
|
K = 5
|
||||||
new_node_lpos = routedp.dp_route_opt(
|
new_node_lpos = routedp.dp_route_opt(
|
||||||
node_lpos, node_size, dieLX, dieHX, dieLY, dieHY,
|
node_lpos, node_size, dieLX, dieHX, dieLY, dieHY,
|
||||||
|
|||||||
@ -54,6 +54,24 @@ def get_init_density_map(rawdb, gpdb, data: PlaceData, args, logger):
|
|||||||
args.deterministic
|
args.deterministic
|
||||||
)
|
)
|
||||||
init_density_map += snet_density_map.contiguous()
|
init_density_map += snet_density_map.contiguous()
|
||||||
|
|
||||||
|
# compute utilization to determine whether there are sufficient space to enlarge snet density
|
||||||
|
mov_lhs, mov_rhs = data.movable_index
|
||||||
|
mov_node_size = data.node_size[mov_lhs:mov_rhs, ...]
|
||||||
|
total_mov_cell_area = torch.sum(torch.prod(mov_node_size, 1)).item()
|
||||||
|
die_area = torch.prod(data.die_ur - data.die_ll)
|
||||||
|
fixed_node_area = init_density_map.clamp_(min=0.0, max=1.0).sum() * data.bin_area
|
||||||
|
placeable_area = die_area - fixed_node_area
|
||||||
|
total_filler_area = max(args.target_density * placeable_area - total_mov_cell_area, 0.0)
|
||||||
|
if total_filler_area / total_mov_cell_area > 2:
|
||||||
|
# low utilization, can enlarge snet density to further enhance routability
|
||||||
|
tmp_map = init_density_map + (snet_density_map.contiguous() > 0.1).float()
|
||||||
|
diff_area = (tmp_map.clamp_(min=0.0, max=1.0).sum() * data.bin_area - fixed_node_area).item()
|
||||||
|
if diff_area < total_filler_area * 0.5:
|
||||||
|
logger.info("Low utilization detect, enlarge snet density.")
|
||||||
|
init_density_map += (snet_density_map.contiguous() > 0.1).float()
|
||||||
|
init_density_map.clamp_(min=0.0, max=1.0)
|
||||||
|
|
||||||
init_density_map.clamp_(min=0.0, max=1.0).mul_(args.target_density)
|
init_density_map.clamp_(min=0.0, max=1.0).mul_(args.target_density)
|
||||||
if args.use_route_force or args.use_cell_inflate:
|
if args.use_route_force or args.use_cell_inflate:
|
||||||
# inflate connected IOPins
|
# inflate connected IOPins
|
||||||
|
|||||||
@ -114,6 +114,8 @@ class ParamScheduler:
|
|||||||
self.stop_overflow = args.stop_overflow
|
self.stop_overflow = args.stop_overflow
|
||||||
self.skip_update = False if args.enable_skip_update else None
|
self.skip_update = False if args.enable_skip_update else None
|
||||||
self.enable_fence = data.enable_fence
|
self.enable_fence = data.enable_fence
|
||||||
|
self.min_enlarge_density_interval = 1000
|
||||||
|
self.last_enlarge_density_iter = -self.min_enlarge_density_interval
|
||||||
# skip density force
|
# skip density force
|
||||||
self.enable_sample_force = True
|
self.enable_sample_force = True
|
||||||
self.force_ratio = 0.0
|
self.force_ratio = 0.0
|
||||||
@ -202,7 +204,7 @@ class ParamScheduler:
|
|||||||
# self.skip_update = np.random.random() > (np.random.randn() * 0.08 + 0.4)
|
# self.skip_update = np.random.random() > (np.random.randn() * 0.08 + 0.4)
|
||||||
# if self.density_weight > 0.1 or self.recorder.overflow[-1] < 0.2: # 2021 11 13 best
|
# if self.density_weight > 0.1 or self.recorder.overflow[-1] < 0.2: # 2021 11 13 best
|
||||||
# self.skip_update = np.random.random() > 0.4
|
# self.skip_update = np.random.random() > 0.4
|
||||||
if self.weighted_weight > 0.5 and self.weighted_weight < 0.99:
|
if self.weighted_weight > 0.5 and self.weighted_weight < 0.95:
|
||||||
self.skip_update = ((self.iter - self.init_iter) % 3 != 0)
|
self.skip_update = ((self.iter - self.init_iter) % 3 != 0)
|
||||||
elif self.iter - self.init_iter < 50:
|
elif self.iter - self.init_iter < 50:
|
||||||
# slow down the param update of early stage
|
# slow down the param update of early stage
|
||||||
@ -230,6 +232,19 @@ class ParamScheduler:
|
|||||||
self.mu = 1.05 * np.clip(np.power(1.05, -delta_hpwl / 350000), 0.95, 1.05)
|
self.mu = 1.05 * np.clip(np.power(1.05, -delta_hpwl / 350000), 0.95, 1.05)
|
||||||
self.density_weight *= self.mu
|
self.density_weight *= self.mu
|
||||||
|
|
||||||
|
if (
|
||||||
|
not self.enable_fence and
|
||||||
|
self.iter > 15 and
|
||||||
|
self.iter - self.last_enlarge_density_iter > self.min_enlarge_density_interval and
|
||||||
|
self.check_plateau(self.recorder.overflow, window=25, threshold=0.001)
|
||||||
|
):
|
||||||
|
if self.recorder.overflow[-1] > 0.9:
|
||||||
|
self.last_enlarge_density_iter = self.iter
|
||||||
|
self.density_weight *= 2
|
||||||
|
self.__logger__.warning(
|
||||||
|
"Detect plateau at early stage, enlarge density_weight. Iter: %d" %
|
||||||
|
self.iter)
|
||||||
|
|
||||||
def param_smooth_func(self, input, r=0.2, half_iter=30, end_iter=400):
|
def param_smooth_func(self, input, r=0.2, half_iter=30, end_iter=400):
|
||||||
logistic = lambda x,k,x_0: 1 / (1 + math.exp(-k * (x - x_0)))
|
logistic = lambda x,k,x_0: 1 / (1 + math.exp(-k * (x - x_0)))
|
||||||
lhs = 1 - logistic(input, r, end_iter - half_iter)
|
lhs = 1 - logistic(input, r, end_iter - half_iter)
|
||||||
|
|||||||
@ -137,6 +137,7 @@ def run_placement_main_nesterov(args, logger):
|
|||||||
# p.step()
|
# p.step()
|
||||||
# exit(0)
|
# exit(0)
|
||||||
terminate_signal = False
|
terminate_signal = False
|
||||||
|
route_early_terminate_signal = False
|
||||||
for iteration in range(args.inner_iter):
|
for iteration in range(args.inner_iter):
|
||||||
# optimizer.zero_grad() # zero grad inside obj_and_grad_fn
|
# optimizer.zero_grad() # zero grad inside obj_and_grad_fn
|
||||||
obj = optimizer.step(obj_and_grad_fn)
|
obj = optimizer.step(obj_and_grad_fn)
|
||||||
@ -189,7 +190,9 @@ def run_placement_main_nesterov(args, logger):
|
|||||||
constraint_fn=trunc_node_pos_fn,
|
constraint_fn=trunc_node_pos_fn,
|
||||||
) # ps.use_cell_inflate is updated in route_inflation
|
) # ps.use_cell_inflate is updated in route_inflation
|
||||||
if not ps.use_cell_inflate:
|
if not ps.use_cell_inflate:
|
||||||
logger.info("Stop cell inflation...")
|
route_early_terminate_signal = True
|
||||||
|
terminate_signal = True
|
||||||
|
logger.info("Early stop cell inflation...")
|
||||||
if output is not None:
|
if output is not None:
|
||||||
gr_metrics, new_mov_node_size, new_expand_ratio = output
|
gr_metrics, new_mov_node_size, new_expand_ratio = output
|
||||||
ps.push_gr_sol(gr_metrics, hpwl, overflow, mov_node_pos)
|
ps.push_gr_sol(gr_metrics, hpwl, overflow, mov_node_pos)
|
||||||
@ -240,7 +243,7 @@ def run_placement_main_nesterov(args, logger):
|
|||||||
)
|
)
|
||||||
ps.reset_best_sol()
|
ps.reset_best_sol()
|
||||||
|
|
||||||
if iteration % args.log_freq == 0 or iteration == args.inner_iter - 1 or ps.rerun_route:
|
if iteration % args.log_freq == 0 or iteration == args.inner_iter - 1 or ps.rerun_route or terminate_signal:
|
||||||
log_str = (
|
log_str = (
|
||||||
"iter: %d | masked_hpwl: %.2E overflow: %.4f obj: %.4E "
|
"iter: %d | masked_hpwl: %.2E overflow: %.4f obj: %.4E "
|
||||||
"density_weight: %.4E wa_coeff: %.4E"
|
"density_weight: %.4E wa_coeff: %.4E"
|
||||||
@ -287,13 +290,14 @@ def run_placement_main_nesterov(args, logger):
|
|||||||
mov_node_pos[mov_lhs:mov_rhs].data.copy_(best_sol[mov_lhs:mov_rhs])
|
mov_node_pos[mov_lhs:mov_rhs].data.copy_(best_sol[mov_lhs:mov_rhs])
|
||||||
if ps.enable_route:
|
if ps.enable_route:
|
||||||
route_inflation_roll_back(args, logger, data, mov_node_size)
|
route_inflation_roll_back(args, logger, data, mov_node_size)
|
||||||
ps.rerun_route = True
|
if not route_early_terminate_signal:
|
||||||
gr_metrics = run_gr_and_fft_main(
|
ps.rerun_route = True
|
||||||
args, logger, data, rawdb, gpdb, ps, mov_node_pos, constraint_fn=trunc_node_pos_fn,
|
gr_metrics = run_gr_and_fft_main(
|
||||||
skip_m1_route=True, report_gr_metrics_only=True
|
args, logger, data, rawdb, gpdb, ps, mov_node_pos, constraint_fn=trunc_node_pos_fn,
|
||||||
)
|
skip_m1_route=True, report_gr_metrics_only=True
|
||||||
ps.rerun_route = False
|
)
|
||||||
ps.push_gr_sol(gr_metrics, hpwl, overflow, mov_node_pos)
|
ps.rerun_route = False
|
||||||
|
ps.push_gr_sol(gr_metrics, hpwl, overflow, mov_node_pos)
|
||||||
best_sol_gr = ps.get_best_gr_sol()
|
best_sol_gr = ps.get_best_gr_sol()
|
||||||
mov_node_pos[mov_lhs:mov_rhs].data.copy_(best_sol_gr[mov_lhs:mov_rhs])
|
mov_node_pos[mov_lhs:mov_rhs].data.copy_(best_sol_gr[mov_lhs:mov_rhs])
|
||||||
|
|
||||||
|
|||||||
@ -41,8 +41,8 @@ for idx, (lhs, rhs) in enumerate(design_lines):
|
|||||||
if "End route_design" in line:
|
if "End route_design" in line:
|
||||||
DrCpuTimeStr = line.split("total cpu=")[-1].split(", ")[0]
|
DrCpuTimeStr = line.split("total cpu=")[-1].split(", ")[0]
|
||||||
DrTotalTimeStr = line.split("real=")[-1].split(", ")[0]
|
DrTotalTimeStr = line.split("real=")[-1].split(", ")[0]
|
||||||
DrCpuTime = sum(x * int(t) for x, t in zip([3600, 60, 1], DrCpuTimeStr.split(":"))) # seconds
|
DrCpuTime = sum(x * int(float(t)) for x, t in zip([3600, 60, 1], DrCpuTimeStr.split(":"))) # seconds
|
||||||
DrTotalTime = sum(x * int(t) for x, t in zip([3600, 60, 1], DrTotalTimeStr.split(":"))) # seconds
|
DrTotalTime = sum(x * int(float(t)) for x, t in zip([3600, 60, 1], DrTotalTimeStr.split(":"))) # seconds
|
||||||
|
|
||||||
if line.startswith("Wire Length Statistics :"):
|
if line.startswith("Wire Length Statistics :"):
|
||||||
findTotalWL = True
|
findTotalWL = True
|
||||||
|
|||||||
@ -6,9 +6,11 @@ def find_benchmark(dataset_root, benchmark):
|
|||||||
"ispd2005": os.path.join(dataset_root, "ispd2005"),
|
"ispd2005": os.path.join(dataset_root, "ispd2005"),
|
||||||
"dac2012": os.path.join(dataset_root, "iccad2012dac2012"),
|
"dac2012": os.path.join(dataset_root, "iccad2012dac2012"),
|
||||||
"ispd2015": os.path.join(dataset_root, "ispd2015"),
|
"ispd2015": os.path.join(dataset_root, "ispd2015"),
|
||||||
"ispd2015_without_fence": os.path.join(dataset_root, "ispd2015_without_fence"),
|
|
||||||
"ispd2015_fix": os.path.join(dataset_root, "ispd2015_fix"),
|
"ispd2015_fix": os.path.join(dataset_root, "ispd2015_fix"),
|
||||||
|
"ispd2018": os.path.join(dataset_root, "ispd2018"),
|
||||||
|
"ispd2019_no_fence": os.path.join(dataset_root, "ispd2019_no_fence"),
|
||||||
"iccad2019": os.path.join(dataset_root, "iccad2019"),
|
"iccad2019": os.path.join(dataset_root, "iccad2019"),
|
||||||
|
"ispd2018": os.path.join(dataset_root, "ispd2018"),
|
||||||
}
|
}
|
||||||
root = bm_to_root[benchmark]
|
root = bm_to_root[benchmark]
|
||||||
all_designs = [i for i in os.listdir(root) if os.path.isdir(os.path.join(root, i))]
|
all_designs = [i for i in os.listdir(root) if os.path.isdir(os.path.join(root, i))]
|
||||||
@ -22,12 +24,16 @@ def get_single_design_params(dataset_root, benchmark, design_name, placement=Non
|
|||||||
return single_dac2012(dataset_root, design_name, placement)
|
return single_dac2012(dataset_root, design_name, placement)
|
||||||
elif benchmark == "ispd2015":
|
elif benchmark == "ispd2015":
|
||||||
return single_ispd2015(dataset_root, design_name, placement)
|
return single_ispd2015(dataset_root, design_name, placement)
|
||||||
elif benchmark == "ispd2015_without_fence":
|
|
||||||
return single_ispd2015_without_fence(dataset_root, design_name, placement)
|
|
||||||
elif benchmark == "ispd2015_fix":
|
elif benchmark == "ispd2015_fix":
|
||||||
return single_ispd2015_fix(dataset_root, design_name, placement)
|
return single_ispd2015_fix(dataset_root, design_name, placement)
|
||||||
|
elif benchmark == "ispd2018":
|
||||||
|
return single_ispd2018(dataset_root, design_name, placement)
|
||||||
|
elif benchmark == "ispd2019_no_fence":
|
||||||
|
return single_ispd2019_no_fence(dataset_root, design_name, placement)
|
||||||
elif benchmark == "iccad2019":
|
elif benchmark == "iccad2019":
|
||||||
return single_iccad2019(dataset_root, design_name, placement)
|
return single_iccad2019(dataset_root, design_name, placement)
|
||||||
|
elif benchmark == "ispd2018":
|
||||||
|
return single_ispd2018(dataset_root, design_name, placement)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("benchmark %s is not found" % benchmark)
|
raise NotImplementedError("benchmark %s is not found" % benchmark)
|
||||||
|
|
||||||
@ -87,22 +93,6 @@ def single_ispd2015(dataset_root, design_name, placement=None):
|
|||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
def single_ispd2015_without_fence(dataset_root, design_name, placement=None):
|
|
||||||
# configuration
|
|
||||||
benchmark = "ispd2015_without_fence"
|
|
||||||
root, all_designs = find_benchmark(dataset_root, benchmark)
|
|
||||||
if design_name not in all_designs:
|
|
||||||
raise ValueError("Design Name %s should in %s" % (design_name, all_designs))
|
|
||||||
params = {
|
|
||||||
"benchmark": benchmark,
|
|
||||||
"tech_lef": "%s/%s/tech.lef" % (root, design_name),
|
|
||||||
"cell_lef": "%s/%s/cells.lef" % (root, design_name),
|
|
||||||
"def": "%s/%s/floorplan.def" % (root, design_name) if placement is None else placement,
|
|
||||||
"design_name": design_name,
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
|
|
||||||
|
|
||||||
def single_ispd2015_fix(dataset_root, design_name, placement=None):
|
def single_ispd2015_fix(dataset_root, design_name, placement=None):
|
||||||
# configuration
|
# configuration
|
||||||
benchmark = "ispd2015_fix"
|
benchmark = "ispd2015_fix"
|
||||||
@ -118,6 +108,36 @@ def single_ispd2015_fix(dataset_root, design_name, placement=None):
|
|||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def single_ispd2018(dataset_root, design_name, placement=None):
|
||||||
|
# configuration
|
||||||
|
benchmark = "ispd2018"
|
||||||
|
root, all_designs = find_benchmark(dataset_root, benchmark)
|
||||||
|
if design_name not in all_designs:
|
||||||
|
raise ValueError("Design Name %s should in %s" % (design_name, all_designs))
|
||||||
|
params = {
|
||||||
|
"benchmark": benchmark,
|
||||||
|
"lef": "%s/%s/%s.input.lef" % (root, design_name, design_name),
|
||||||
|
"def": "%s/%s/%s.input.def" % (root, design_name, design_name) if placement is None else placement,
|
||||||
|
"design_name": design_name,
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def single_ispd2019_no_fence(dataset_root, design_name, placement=None):
|
||||||
|
# configuration
|
||||||
|
benchmark = "ispd2019_no_fence"
|
||||||
|
root, all_designs = find_benchmark(dataset_root, benchmark)
|
||||||
|
if design_name not in all_designs:
|
||||||
|
raise ValueError("Design Name %s should in %s" % (design_name, all_designs))
|
||||||
|
params = {
|
||||||
|
"benchmark": benchmark,
|
||||||
|
"lef": "%s/%s/%s.input.lef" % (root, design_name, design_name),
|
||||||
|
"def": "%s/%s/%s.input.def" % (root, design_name, design_name) if placement is None else placement,
|
||||||
|
"design_name": design_name,
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
def single_iccad2019(dataset_root, design_name, placement=None):
|
def single_iccad2019(dataset_root, design_name, placement=None):
|
||||||
# configuration
|
# configuration
|
||||||
benchmark = "iccad2019"
|
benchmark = "iccad2019"
|
||||||
@ -133,15 +153,35 @@ def single_iccad2019(dataset_root, design_name, placement=None):
|
|||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def single_ispd2018(dataset_root, design_name, placement=None):
|
||||||
|
# configuration
|
||||||
|
benchmark = "ispd2018"
|
||||||
|
root, all_designs = find_benchmark(dataset_root, benchmark)
|
||||||
|
if design_name not in all_designs:
|
||||||
|
raise ValueError("Design Name %s should in %s" % (design_name, all_designs))
|
||||||
|
params = {
|
||||||
|
"benchmark": benchmark,
|
||||||
|
"lef": "%s/%s/%s.input.lef" % (root, design_name, design_name),
|
||||||
|
"def": "%s/%s/%s.input.def" % (root, design_name, design_name)
|
||||||
|
if placement is None
|
||||||
|
else placement,
|
||||||
|
"design_name": design_name,
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
def get_custom_design_params(args):
|
def get_custom_design_params(args):
|
||||||
params = dict([
|
params = dict(
|
||||||
[item.strip() for item in token.strip().split(":")]
|
[
|
||||||
for token in args.custom_path.split(",") if len(token) > 0
|
[item.strip() for item in token.strip().split(":")]
|
||||||
])
|
for token in args.custom_path.split(",")
|
||||||
|
if len(token) > 0
|
||||||
|
]
|
||||||
|
)
|
||||||
if "benchmark" not in params.keys():
|
if "benchmark" not in params.keys():
|
||||||
raise ValueError("Cannot find 'benchmark' in args.custom_path")
|
raise ValueError("Cannot find 'benchmark' in args.custom_path")
|
||||||
if "design_name" not in params.keys():
|
if "design_name" not in params.keys():
|
||||||
raise ValueError("Cannot find 'design_name' in args.custom_path")
|
raise ValueError("Cannot find 'design_name' in args.custom_path")
|
||||||
args.dataset = params["benchmark"]
|
args.dataset = params["benchmark"]
|
||||||
args.design_name = params["design_name"]
|
args.design_name = params["design_name"]
|
||||||
return params
|
return params
|
||||||
|
|||||||
@ -14,11 +14,12 @@ class IOParser(object):
|
|||||||
self,
|
self,
|
||||||
params: dict,
|
params: dict,
|
||||||
verbose_log: bool = False,
|
verbose_log: bool = False,
|
||||||
|
log_level: int = 2,
|
||||||
lite_mode: bool = False,
|
lite_mode: bool = False,
|
||||||
random_place: bool = True,
|
random_place: bool = True,
|
||||||
num_threads: int = 8,
|
num_threads: int = 8,
|
||||||
):
|
):
|
||||||
check_status = self.check_params(params, verbose_log, lite_mode, random_place, num_threads)
|
check_status = self.check_params(params, verbose_log, log_level, lite_mode, random_place, num_threads)
|
||||||
if not check_status:
|
if not check_status:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Checking failure. Please check the validity of params: %s" % params
|
"Checking failure. Please check the validity of params: %s" % params
|
||||||
@ -31,7 +32,7 @@ class IOParser(object):
|
|||||||
return load_status
|
return load_status
|
||||||
|
|
||||||
def check_params(
|
def check_params(
|
||||||
self, params: dict, verbose_log: bool, lite_mode: bool, random_place: bool, num_threads: int = 8
|
self, params: dict, verbose_log: bool, log_level: int, lite_mode: bool, random_place: bool, num_threads: int = 8
|
||||||
) -> bool:
|
) -> bool:
|
||||||
if "def" not in params.keys() and "aux" not in params.keys():
|
if "def" not in params.keys() and "aux" not in params.keys():
|
||||||
print("def or aux is not found!")
|
print("def or aux is not found!")
|
||||||
@ -82,6 +83,14 @@ class IOParser(object):
|
|||||||
else:
|
else:
|
||||||
self.params["verbose_parser_log"] = False
|
self.params["verbose_parser_log"] = False
|
||||||
|
|
||||||
|
# === LOG_LEVEL ===
|
||||||
|
# 0: DEBUG, 1: VERBOSE, 2: INFO, 3: NOTICE, 4: WARN, 5: ERROR, 6: FATAL, 7: OK
|
||||||
|
if log_level < 0:
|
||||||
|
log_level = 0
|
||||||
|
elif log_level > 7:
|
||||||
|
log_level = 2
|
||||||
|
self.params["global_log_level"] = log_level
|
||||||
|
|
||||||
if lite_mode:
|
if lite_mode:
|
||||||
self.params["lite_mode"] = True
|
self.params["lite_mode"] = True
|
||||||
else:
|
else:
|
||||||
@ -100,12 +109,13 @@ class IOParser(object):
|
|||||||
self,
|
self,
|
||||||
params: dict,
|
params: dict,
|
||||||
verbose_log: bool = False,
|
verbose_log: bool = False,
|
||||||
|
log_level: int = 2,
|
||||||
lite_mode: bool = False,
|
lite_mode: bool = False,
|
||||||
random_place: bool = True,
|
random_place: bool = True,
|
||||||
num_threads: int = 8,
|
num_threads: int = 8,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
):
|
):
|
||||||
check_status = self.check_params(params, verbose_log, lite_mode, random_place, num_threads)
|
check_status = self.check_params(params, verbose_log, log_level, lite_mode, random_place, num_threads)
|
||||||
if not check_status:
|
if not check_status:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Checking failure. Please check the validity of params: %s" % params
|
"Checking failure. Please check the validity of params: %s" % params
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user