router2: Make magic numbers configurable

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2020-02-03 11:38:15 +00:00
parent 5e1aac67db
commit ad1cc12df1
3 changed files with 86 additions and 40 deletions

View File

@ -26,6 +26,7 @@
*
*/
#include "router2.h"
#include <algorithm>
#include <boost/container/flat_map.hpp>
#include <chrono>
@ -39,8 +40,6 @@
NEXTPNR_NAMESPACE_BEGIN
#define RUNTIME_PROFILE
namespace {
struct Router2
{
@ -105,6 +104,9 @@ struct Router2
}
Context *ctx;
Router2Cfg cfg;
Router2(Context *ctx, const Router2Cfg &cfg) : ctx(ctx), cfg(cfg) {}
// Use 'udata' for fast net lookups and indexing
std::vector<NetInfo *> nets_by_udata;
@ -221,11 +223,10 @@ struct Router2
};
};
int bb_margin_x = 4, bb_margin_y = 4; // number of units outside the bounding box we may go
bool hit_test_pip(ArcBounds &bb, Loc l)
{
return l.x >= (bb.x0 - bb_margin_x) && l.x <= (bb.x1 + bb_margin_x) && l.y >= (bb.y0 - bb_margin_y) &&
l.y <= (bb.y1 + bb_margin_y);
return l.x >= (bb.x0 - cfg.bb_margin_x) && l.x <= (bb.x1 + cfg.bb_margin_x) &&
l.y >= (bb.y0 - cfg.bb_margin_y) && l.y <= (bb.y1 + cfg.bb_margin_y);
}
double curr_cong_weight, hist_cong_weight, estimate_weight;
@ -320,7 +321,7 @@ struct Router2
source_uses = wd.bound_nets.at(net->udata).first;
if (pip != PipId()) {
Loc pl = ctx->getPipLocation(pip);
bias_cost = 0.25f * (base_cost / int(net->users.size())) *
bias_cost = cfg.bias_cost_factor * (base_cost / int(net->users.size())) *
((std::abs(pl.x - nd.cx) + std::abs(pl.y - nd.cy)) / float(nd.hpwl));
}
return base_cost * hist_cost * present_cost / (1 + source_uses) + bias_cost;
@ -333,7 +334,7 @@ struct Router2
if (wd.bound_nets.count(net->udata))
source_uses = wd.bound_nets.at(net->udata).first;
// FIXME: timing/wirelength balance?
return ctx->getDelayNS(ctx->estimateDelay(wd.w, sink)) / (1 + source_uses);
return (ctx->getDelayNS(ctx->estimateDelay(wd.w, sink)) / (1 + source_uses)) + cfg.ipin_cost_adder;
}
bool check_arc_routing(NetInfo *net, size_t usr)
@ -469,7 +470,8 @@ struct Router2
// This could also be used to speed up forwards routing by a hybrid
// bidirectional approach
int backwards_iter = 0;
int backwards_limit = ctx->getBelGlobalBuf(net->driver.cell->bel) ? 20000 : 15;
int backwards_limit =
ctx->getBelGlobalBuf(net->driver.cell->bel) ? cfg.global_backwards_max_iter : cfg.backwards_max_iter;
t.backwards_queue.push(wire_to_idx.at(dst_wire));
while (!t.backwards_queue.empty() && backwards_iter < backwards_limit) {
int cursor = t.backwards_queue.front();
@ -611,7 +613,7 @@ struct Router2
next_score.cost = curr.score.cost + score_wire_for_arc(net, i, next, dh);
next_score.delay =
curr.score.delay + ctx->getPipDelay(dh).maxDelay() + ctx->getWireDelay(next).maxDelay();
next_score.togo_cost = 1.75 * get_togo_cost(net, i, next_idx, dst_wire);
next_score.togo_cost = cfg.estimate_weight * get_togo_cost(net, i, next_idx, dst_wire);
const auto &v = nwd.visit;
if (!v.visited || (v.score.total() > next_score.total())) {
++explored;
@ -669,9 +671,7 @@ struct Router2
ROUTE_LOG_DBG("Routing net '%s'...\n", ctx->nameOf(net));
#ifdef RUNTIME_PROFILE
auto rstart = std::chrono::high_resolution_clock::now();
#endif
// Nothing to do if net is undriven
if (net->driver.cell == nullptr)
@ -715,11 +715,11 @@ struct Router2
}
}
}
#ifdef RUNTIME_PROFILE
auto rend = std::chrono::high_resolution_clock::now();
nets.at(net->udata).total_route_us +=
(std::chrono::duration_cast<std::chrono::microseconds>(rend - rstart).count());
#endif
if (cfg.perf_profile) {
auto rend = std::chrono::high_resolution_clock::now();
nets.at(net->udata).total_route_us +=
(std::chrono::duration_cast<std::chrono::microseconds>(rend - rstart).count());
}
return !have_failures;
}
#undef ROUTE_LOG_DBG
@ -951,10 +951,10 @@ struct Router2
auto &nd = nets.at(n);
auto ni = nets_by_udata.at(n);
int bin = N;
int le_x = mid_x - bb_margin_x;
int rs_x = mid_x + bb_margin_x;
int le_y = mid_y - bb_margin_y;
int rs_y = mid_y + bb_margin_y;
int le_x = mid_x - cfg.bb_margin_x;
int rs_x = mid_x + cfg.bb_margin_x;
int le_y = mid_y - cfg.bb_margin_y;
int rs_y = mid_y + cfg.bb_margin_y;
// Quadrants
if (nd.bb.x0 < le_x && nd.bb.x1 < le_x && nd.bb.y0 < le_y && nd.bb.y1 < le_y)
bin = 0;
@ -1010,14 +1010,14 @@ struct Router2
route_net(tcs.at(N), fail, false);
}
void router_test()
void operator()()
{
setup_nets();
setup_wires();
find_all_reserved_wires();
partition_nets();
curr_cong_weight = 0.5;
hist_cong_weight = 1.0;
curr_cong_weight = cfg.init_curr_cong_weight;
hist_cong_weight = cfg.hist_cong_weight;
ThreadContext st;
int iter = 1;
@ -1051,32 +1051,48 @@ struct Router2
log_info("iter=%d wires=%d overused=%d overuse=%d archfail=%s\n", iter, total_wire_use, overused_wires,
total_overuse, overused_wires > 0 ? "NA" : std::to_string(arch_fail).c_str());
++iter;
curr_cong_weight *= 2;
curr_cong_weight *= cfg.curr_cong_mult;
} while (!failed_nets.empty());
#ifdef RUNTIME_PROFILE
std::vector<std::pair<int, IdString>> nets_by_runtime;
for (auto &n : nets_by_udata) {
nets_by_runtime.emplace_back(nets.at(n->udata).total_route_us, n->name);
if (cfg.perf_profile) {
std::vector<std::pair<int, IdString>> nets_by_runtime;
for (auto &n : nets_by_udata) {
nets_by_runtime.emplace_back(nets.at(n->udata).total_route_us, n->name);
}
std::sort(nets_by_runtime.begin(), nets_by_runtime.end(), std::greater<std::pair<int, IdString>>());
log_info("1000 slowest nets by runtime:\n");
for (int i = 0; i < std::min(int(nets_by_runtime.size()), 1000); i++) {
log(" %80s %6d %.1fms\n", nets_by_runtime.at(i).second.c_str(ctx),
int(ctx->nets.at(nets_by_runtime.at(i).second)->users.size()),
nets_by_runtime.at(i).first / 1000.0);
}
}
std::sort(nets_by_runtime.begin(), nets_by_runtime.end(), std::greater<std::pair<int, IdString>>());
log_info("1000 slowest nets by runtime:\n");
for (int i = 0; i < std::min(int(nets_by_runtime.size()), 1000); i++) {
log(" %80s %6d %.1fms\n", nets_by_runtime.at(i).second.c_str(ctx),
int(ctx->nets.at(nets_by_runtime.at(i).second)->users.size()), nets_by_runtime.at(i).first / 1000.0);
}
#endif
}
};
} // namespace
void router2(Context *ctx)
void router2(Context *ctx, const Router2Cfg &cfg)
{
Router2 rt;
Router2 rt(ctx, cfg);
rt.ctx = ctx;
auto rstart = std::chrono::high_resolution_clock::now();
rt.router_test();
rt();
auto rend = std::chrono::high_resolution_clock::now();
log_info("Router2 time %.02fs\n", std::chrono::duration<float>(rend - rstart).count());
}
Router2Cfg::Router2Cfg(Context *ctx)
{
backwards_max_iter = ctx->setting<int>("router2/bwdMaxIter", 20);
global_backwards_max_iter = ctx->setting<int>("router2/glbBwdMaxIter", 200);
bb_margin_x = ctx->setting<int>("router2/bbMargin/x", 3);
bb_margin_y = ctx->setting<int>("router2/bbMargin/y", 3);
ipin_cost_adder = ctx->setting<float>("router2/ipinCostAdder", 0.0f);
bias_cost_factor = ctx->setting<float>("router2/biasCostFactor", 0.25f);
init_curr_cong_weight = ctx->setting<float>("router2/initCurrCongWeight", 0.5f);
hist_cong_weight = ctx->setting<float>("router2/histCongWeight", 1.0f);
curr_cong_mult = ctx->setting<float>("router2/currCongWeightMult", 2.0f);
estimate_weight = ctx->setting<float>("router2/estimateWeight", 1.75f);
perf_profile = ctx->setting<float>("router2/perfProfile", false);
}
NEXTPNR_NAMESPACE_END

View File

@ -21,6 +21,36 @@
NEXTPNR_NAMESPACE_BEGIN
void router2(Context *ctx);
struct Router2Cfg
{
Router2Cfg(Context *ctx);
// Maximum iterations for backwards routing attempt
int backwards_max_iter;
// Maximum iterations for backwards routing attempt for global nets
int global_backwards_max_iter;
// Padding added to bounding boxes to account for imperfect routing,
// congestion, etc
int bb_margin_x, bb_margin_y;
// Cost factor added to input pin wires; effectively reduces the
// benefit of sharing interconnect
float ipin_cost_adder;
// Cost factor for "bias" towards center location of net
float bias_cost_factor;
// Starting current and historical congestion cost factor
float init_curr_cong_weight, hist_cong_weight;
// Current congestion cost multiplier
float curr_cong_mult;
// Weight given to delay estimate in A*. Higher values
// mean faster and more directed routing, at the risk
// of choosing a less congestion/delay-optimal route
float estimate_weight;
// Print additional performance profiling information
bool perf_profile = false;
};
void router2(Context *ctx, const Router2Cfg &cfg);
NEXTPNR_NAMESPACE_END

View File

@ -625,7 +625,7 @@ bool Arch::route()
route_ecp5_globals(getCtx());
assignArchInfo();
assign_budget(getCtx(), true);
router2(getCtx());
router2(getCtx(), Router2Cfg(getCtx()));
bool result = router1(getCtx(), Router1Cfg(getCtx()));
#if 0
std::vector<std::pair<WireId, int>> fanout_vector;