HeAP: fine tuning

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2019-01-24 14:05:16 +00:00
parent 2a0c117662
commit eb638c47b3

View File

@ -31,6 +31,7 @@
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include <tuple>
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "place_common.h" #include "place_common.h"
@ -155,6 +156,9 @@ class HeAPPlacer
bool valid = true; bool valid = true;
wirelen_t solved_hpwl = 0, legal_hpwl = 0, best_hpwl = std::numeric_limits<wirelen_t>::max(); wirelen_t solved_hpwl = 0, legal_hpwl = 0, best_hpwl = std::numeric_limits<wirelen_t>::max();
int iter = 0, stalled = 0; int iter = 0, stalled = 0;
std::vector<std::tuple<CellInfo*, BelId, PlaceStrength>> solution;
while (!valid || (stalled < 5 && (solved_hpwl <= legal_hpwl * 0.8))) { while (!valid || (stalled < 5 && (solved_hpwl <= legal_hpwl * 0.8))) {
if (!valid && ((solved_hpwl > legal_hpwl * 0.8) || (stalled > 5))) { if (!valid && ((solved_hpwl > legal_hpwl * 0.8) || (stalled > 5))) {
stalled = 0; stalled = 0;
@ -162,18 +166,24 @@ class HeAPPlacer
valid = true; valid = true;
} }
setup_solve_cells(); for (int i = 0; i < 5; i++) {
setup_solve_cells();
EquationSystem<double> esx(solve_cells.size(), solve_cells.size()); EquationSystem<double> esx(solve_cells.size(), solve_cells.size());
build_equations(esx, false, iter); build_equations(esx, false, (iter == 0) ? -1 : iter);
// log_info("x-axis\n"); // log_info("x-axis\n");
solve_equations(esx, false); solve_equations(esx, false);
EquationSystem<double> esy(solve_cells.size(), solve_cells.size()); EquationSystem<double> esy(solve_cells.size(), solve_cells.size());
build_equations(esy, true, iter); build_equations(esy, true, (iter == 0) ? -1 : iter);
// log_info("y-axis\n"); // log_info("y-axis\n");
solve_equations(esy, true); solve_equations(esy, true);
solved_hpwl = total_hpwl();
update_all_chains();
solved_hpwl = total_hpwl();
log_info("Initial placer iter %d, hpwl = %d\n", i, int(solved_hpwl));
}
log_info("Solved HPWL = %d\n", int(solved_hpwl)); log_info("Solved HPWL = %d\n", int(solved_hpwl));
@ -192,12 +202,40 @@ class HeAPPlacer
if (legal_hpwl < best_hpwl) { if (legal_hpwl < best_hpwl) {
best_hpwl = legal_hpwl; best_hpwl = legal_hpwl;
stalled = 0; stalled = 0;
if (valid) {
// Save solution
solution.clear();
for (auto cell : sorted(ctx->cells)) {
solution.emplace_back(cell.second, cell.second->bel, cell.second->belStrength);
}
}
} else { } else {
++stalled; ++stalled;
} }
for (auto &cl : cell_locs) {
cl.second.legal_x = cl.second.x;
cl.second.legal_y = cl.second.y;
}
ctx->yield(); ctx->yield();
++iter; ++iter;
} }
// Apply saved solution
for (auto &sc : solution) {
CellInfo *cell = std::get<0>(sc);
if (cell->bel != BelId())
ctx->unbindBel(cell->bel);
}
for (auto &sc : solution) {
CellInfo *cell;
BelId bel;
PlaceStrength strength;
std::tie(cell, bel, strength) = sc;
ctx->bindBel(bel, cell, strength);
}
ctx->unlock(); ctx->unlock();
auto endtt = std::chrono::high_resolution_clock::now(); auto endtt = std::chrono::high_resolution_clock::now();
log_info("HeAP Placer Time: %.02fs\n", std::chrono::duration<double>(endtt - startt).count()); log_info("HeAP Placer Time: %.02fs\n", std::chrono::duration<double>(endtt - startt).count());
@ -228,6 +266,7 @@ class HeAPPlacer
struct CellLocation struct CellLocation
{ {
int x, y; int x, y;
int legal_x, legal_y;
double rawx, rawy; double rawx, rawy;
bool locked, global; bool locked, global;
}; };
@ -490,6 +529,7 @@ class HeAPPlacer
{ {
// Return the x or y position of a cell, depending on ydir // Return the x or y position of a cell, depending on ydir
auto cell_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).y : cell_locs.at(cell->name).x; }; auto cell_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).y : cell_locs.at(cell->name).x; };
auto legal_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).legal_y : cell_locs.at(cell->name).legal_x; };
es.reset(); es.reset();
@ -559,12 +599,15 @@ class HeAPPlacer
}); });
} }
if (iter != -1) { if (iter != -1) {
const float alpha = 0.05; const float alpha = 0.3;
float weight = alpha * iter;
for (size_t row = 0; row < solve_cells.size(); row++) { for (size_t row = 0; row < solve_cells.size(); row++) {
int l_pos = legal_pos(solve_cells.at(row));
int c_pos = cell_pos(solve_cells.at(row));
double weight = alpha * iter / std::max<double>(1, std::abs(l_pos - c_pos));
// Add an arc from legalised to current position // Add an arc from legalised to current position
es.add_coeff(row, row, weight); es.add_coeff(row, row, weight);
es.add_rhs(row, weight * cell_pos(solve_cells.at(row))); es.add_rhs(row, weight * l_pos);
} }
} }
} }
@ -677,7 +720,7 @@ class HeAPPlacer
if (nx < 0 || nx > max_x) if (nx < 0 || nx > max_x)
continue; continue;
if (ny < 0 || ny > max_x) if (ny < 0 || ny > max_y)
continue; continue;
// ny = nearest_row_with_bel.at(bt).at(ny); // ny = nearest_row_with_bel.at(bt).at(ny);
@ -692,7 +735,7 @@ class HeAPPlacer
if (ci->constr_children.empty()) { if (ci->constr_children.empty()) {
for (auto sz : fb.at(nx).at(ny)) { for (auto sz : fb.at(nx).at(ny)) {
if (ctx->checkBelAvail(sz) || radius > (max_x / 4)) { if (ctx->checkBelAvail(sz) || radius > 1) {
CellInfo *bound = ctx->getBoundBelCell(sz); CellInfo *bound = ctx->getBoundBelCell(sz);
if (bound != nullptr) { if (bound != nullptr) {
if (bound->constr_parent != nullptr || !bound->constr_children.empty()) if (bound->constr_parent != nullptr || !bound->constr_children.empty())
@ -777,21 +820,41 @@ class HeAPPlacer
auto front = workqueue.front(); auto front = workqueue.front();
workqueue.pop(); workqueue.pop();
auto &r = regions.at(front.first); auto &r = regions.at(front.first);
//log_info("%s (%d, %d) |_> (%d, %d) %d/%d\n", beltype.c_str(ctx), r.x0, r.y0, r.x1, r.y1, r.cells, if (r.cells == 0)
//r.bels); continue;
//log_info("%s (%d, %d) |_> (%d, %d) %d/%d %c\n", beltype.c_str(ctx), r.x0, r.y0, r.x1, r.y1, r.cells, r.bels, front.second ? 'y' : 'x');
auto res = cut_region(r, front.second); auto res = cut_region(r, front.second);
if (res) { if (res) {
workqueue.emplace(res->first, !front.second); workqueue.emplace(res->first, !front.second);
workqueue.emplace(res->second, !front.second); workqueue.emplace(res->second, !front.second);
} else {
// Try the other dir, in case stuck in one direction only
//log_info("RETRY %s (%d, %d) |_> (%d, %d) %d/%d %c\n", beltype.c_str(ctx), r.x0, r.y0, r.x1, r.y1, r.cells, r.bels, front.second ? 'x' : 'y');
auto res2 = cut_region(r, !front.second);
if (res2) {
//log_info("RETRY SUCCESS\n");
workqueue.emplace(res2->first, front.second);
workqueue.emplace(res2->second, front.second);
}
} }
} }
if (ctx->debug) { if (ctx->debug) {
std::ofstream sp("spread" + std::to_string(seq) + ".csv"); std::ofstream sp("spread" + std::to_string(seq) + ".csv");
for (size_t i = 0; i < p->solve_cells.size(); i++) { for (size_t i = 0; i < p->solve_cells.size(); i++) {
auto &c = p->solve_cells.at(i); auto &c = p->solve_cells.at(i);
if (c->type != beltype)
continue;
sp << orig.at(i).first << "," << orig.at(i).second << "," << p->cell_locs[c->name].rawx << "," << p->cell_locs[c->name].rawy << std::endl; sp << orig.at(i).first << "," << orig.at(i).second << "," << p->cell_locs[c->name].rawx << "," << p->cell_locs[c->name].rawy << std::endl;
} }
std::ofstream oc("cells" + std::to_string(seq) + ".csv");
for (size_t y = 0; y <= p->max_y; y++) {
for (size_t x = 0; x <= p->max_x; x++) {
oc << cells_at_location.at(x).at(y).size() << ", ";
}
oc << std::endl;
}
++seq; ++seq;
} }
auto endt = std::chrono::high_resolution_clock::now(); auto endt = std::chrono::high_resolution_clock::now();
@ -848,8 +911,10 @@ class HeAPPlacer
}; };
for (auto &cell : p->cell_locs) { for (auto &cell : p->cell_locs) {
if (ctx->cells.at(cell.first)->type == beltype) if (ctx->cells.at(cell.first)->type != beltype)
occupancy.at(cell.second.x).at(cell.second.y)++; continue;
occupancy.at(cell.second.x).at(cell.second.y)++;
// Compute ultimate extent of each chain root // Compute ultimate extent of each chain root
if (p->chain_root.count(cell.first)) { if (p->chain_root.count(cell.first)) {
set_chain_ext(p->chain_root.at(cell.first)->name, cell.second.x, cell.second.y); set_chain_ext(p->chain_root.at(cell.first)->name, cell.second.x, cell.second.y);
@ -858,6 +923,8 @@ class HeAPPlacer
} }
} }
for (auto &cell : p->cell_locs) { for (auto &cell : p->cell_locs) {
if (ctx->cells.at(cell.first)->type != beltype)
continue;
// Transfer chain extents to the actual chaines structure // Transfer chain extents to the actual chaines structure
ChainExtent *ce = nullptr; ChainExtent *ce = nullptr;
if (p->chain_root.count(cell.first)) if (p->chain_root.count(cell.first))
@ -873,6 +940,8 @@ class HeAPPlacer
} }
} }
for (auto cell : p->solve_cells) { for (auto cell : p->solve_cells) {
if (cell->type != beltype)
continue;
cells_at_location.at(p->cell_locs.at(cell->name).x) cells_at_location.at(p->cell_locs.at(cell->name).x)
.at(p->cell_locs.at(cell->name).y) .at(p->cell_locs.at(cell->name).y)
.push_back(cell); .push_back(cell);
@ -1049,25 +1118,28 @@ class HeAPPlacer
{ {
cut_cells.clear(); cut_cells.clear();
auto &cal = cells_at_location; auto &cal = cells_at_location;
int total_cells = 0, total_bels = 0;
for (int x = r.x0; x <= r.x1; x++) { for (int x = r.x0; x <= r.x1; x++) {
for (int y = r.y0; y <= r.y1; y++) { for (int y = r.y0; y <= r.y1; y++) {
std::copy(cal.at(x).at(y).begin(), cal.at(x).at(y).end(), std::back_inserter(cut_cells)); std::copy(cal.at(x).at(y).begin(), cal.at(x).at(y).end(), std::back_inserter(cut_cells));
total_bels += bels_at(x, y);
} }
} }
for (auto &cell : cut_cells) {
total_cells += p->chain_size.count(cell->name) ? p->chain_size.at(cell->name) : 1;
}
std::sort(cut_cells.begin(), cut_cells.end(), [&](const CellInfo *a, const CellInfo *b) { std::sort(cut_cells.begin(), cut_cells.end(), [&](const CellInfo *a, const CellInfo *b) {
return dir ? (p->cell_locs.at(a->name).rawy < p->cell_locs.at(b->name).rawy) : (p->cell_locs.at(a->name).rawx < p->cell_locs.at(b->name).rawx); return dir ? (p->cell_locs.at(a->name).rawy < p->cell_locs.at(b->name).rawy) : (p->cell_locs.at(a->name).rawx < p->cell_locs.at(b->name).rawx);
}); });
if (cut_cells.empty()) if (cut_cells.size() < 2)
return {}; return {};
// Find the cells midpoint, counting chains in terms of their total size - making the initial source cut // Find the cells midpoint, counting chains in terms of their total size - making the initial source cut
int pivot_cells = 0; int pivot_cells = 0;
int pivot = 0; int pivot = 0;
for (auto &cell : cut_cells) { for (auto &cell : cut_cells) {
pivot_cells += p->chain_size.count(cell->name) ? p->chain_size.at(cell->name) : 1; pivot_cells += p->chain_size.count(cell->name) ? p->chain_size.at(cell->name) : 1;
if (pivot_cells >= r.cells / 2) if (pivot_cells >= total_cells / 2)
break; break;
pivot++; pivot++;
} }
@ -1123,8 +1195,8 @@ class HeAPPlacer
return {}; return {};
// Now find the initial target cut that minimises utilisation imbalance, whilst // Now find the initial target cut that minimises utilisation imbalance, whilst
// meeting the clearance requirements for any large macros // meeting the clearance requirements for any large macros
int left_cells = pivot_cells, right_cells = r.cells - pivot_cells; int left_cells = pivot_cells, right_cells = total_cells - pivot_cells;
int left_bels = 0, right_bels = r.bels; int left_bels = 0, right_bels = total_bels;
int best_tgt_cut = -1; int best_tgt_cut = -1;
double best_deltaU = std::numeric_limits<double>::max(); double best_deltaU = std::numeric_limits<double>::max();
std::pair<int, int> target_cut_bels; std::pair<int, int> target_cut_bels;
@ -1184,8 +1256,8 @@ class HeAPPlacer
bin_bounds.emplace_back(cells_start, area_l); bin_bounds.emplace_back(cells_start, area_l);
for (int i = 1; i < K; i++) for (int i = 1; i < K; i++)
bin_bounds.emplace_back(cells_start + (N * i) / K, bin_bounds.emplace_back(cells_start + (N * i) / K,
area_l + ((area_r - area_l + 0.9) * i) / K); area_l + ((area_r - area_l + 0.99) * i) / K);
bin_bounds.emplace_back(cells_end, area_r + 0.9); bin_bounds.emplace_back(cells_end, area_r + 0.99);
//log("bins "); //log("bins ");
//for (auto b : bin_bounds) log("%d, %.01f; ", b.first, b.second); //for (auto b : bin_bounds) log("%d, %.01f; ", b.first, b.second);
//log("\n"); //log("\n");