router2: further hackery

This commit is contained in:
Lofty 2022-09-27 14:59:47 +01:00
parent c9b3c72bff
commit dc64d32497

View File

@ -589,7 +589,7 @@ struct Router2
auto &usr = net->users.at(i);
ROUTE_LOG_DBG("Routing arc %d of net '%s' (%d, %d) -> (%d, %d)\n", i.idx(), ctx->nameOf(net), ad.bb.x0,
ad.bb.y0, ad.bb.x1, ad.bb.y1);
bool verbose = false; //strcmp(ctx->nameOf(net), "_zz_132__LUT4_A_Z") == 0;
bool verbose = false; //strcmp(ctx->nameOf(net), "reset$TRELLIS_IO_IN") == 0;
WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr, phys_pin);
if (src_wire == WireId())
ARC_LOG_ERR("No wire found for port %s on source cell %s.\n", ctx->nameOf(net->driver.port),
@ -607,9 +607,6 @@ struct Router2
if (t.processed_sinks.count(dst_wire))
return ARC_SUCCESS;
if (verbose)
log("awoo\n");
// Impl note:
// t.fwd_queue = H (i.e. the high priority nodes)
// t.bwd_queue = G (i.e. the unexpanded nodes)
@ -627,35 +624,30 @@ struct Router2
// Unvisit any previously visited wires
reset_wires(t);
auto wire_count = [](int x0, int x1) {
unsigned int priority = 0;
auto wire_count = [](int x0, int x1, int y0, int y1) {
float priority = 0;
auto x = x1 - x0;
auto y = y1 - y0;
// HACK: ECP5-specific.
// H6 wires:
priority += x / 6;
/*priority += x / 6;
x -= 6 * (x / 6);
if (x % 6 == 2 || x % 6 == 4) {
// Assume an extra H6 is used here.
priority++;
x -= x % 6;
}
}*/
// H2/H1 wires:
priority += x / 2;
if (x % 2 == 1) {
/*if (x % 2 == 1) {
// Assume an extra H2 or H1 is used here.
priority++;
}
return priority;
}*/
return unsigned(0.56626506*x + 0.55421686*y);
};
// Fast maze search.
auto fast_search = [&](QueuedWire curr){
while (curr.wire != dst_wire_idx) {
NPNR_ASSERT(curr.wire < flat_wires.size());
auto lowest_priority = [&](QueuedWire curr) {
auto &curr_data = flat_wires.at(curr.wire);
// Neighbour pass 1: find priorities.
auto lowest_priority = std::numeric_limits<unsigned int>::max();
auto priority = std::numeric_limits<unsigned int>::max();
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
// Skip pips outside of box in bounding-box mode
if (is_bb && !hit_test_pip(nd.bb, ctx->getPipLocation(dh)))
@ -681,9 +673,30 @@ struct Router2
if (!thread_test_wire(t, nwd))
continue; // thread safety issue
auto box = ctx->getRouteBoundingBox(ctx->getPipDstWire(dh), dst_wire);
unsigned int priority = wire_count(box.x0, box.x1) + wire_count(box.y0, box.y1);
lowest_priority = std::min(priority, lowest_priority);
unsigned int p = wire_count(box.x0, box.x1, box.y0, box.y1);
priority = std::min(p, priority);
}
return priority;
};
dict<PipId, unsigned int> prios;
// Fast maze search.
int nodes = 0;
auto fast_search = [&](QueuedWire curr){
if (curr.wire == dst_wire_idx) {
return true;
}
bool done = false;
while (!done) {
NPNR_ASSERT(curr.wire < flat_wires.size());
auto &curr_data = flat_wires.at(curr.wire);
nodes++;
// Neighbour pass 1: find priorities.
auto lowest = lowest_priority(curr);
// Neighbour pass 2: add high-priority nodes to the list.
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
@ -716,8 +729,9 @@ struct Router2
next_score.togo = get_togo_cost(net, i, next_idx, dst_wire, false, crit_weight);
auto qw = QueuedWire(next_idx, next_score, t.rng.rng());
auto box = ctx->getRouteBoundingBox(ctx->getPipDstWire(dh), dst_wire);
unsigned int priority = wire_count(box.x0, box.x1) + wire_count(box.y0, box.y1);
if (priority - lowest_priority == 0) {
unsigned int priority = wire_count(box.x0, box.x1, box.y0, box.y1);
prios.insert({dh, priority});
if (priority - lowest == 0) {
auto& unexplored_best = t.bwd_queue.top();
if (t.bwd_queue.empty() || next_score.total() <= unexplored_best.score.total()) {
t.fwd_queue.push(qw);
@ -727,17 +741,27 @@ struct Router2
} else {
low_prio.push_back(qw);
}
set_visited_fwd(t, next_idx, dh);
if (next_idx == dst_wire_idx) {
done = true;
break;
}
}
if (t.fwd_queue.empty()) {
return false;
break;
} else {
curr = t.fwd_queue.top();
t.fwd_queue.pop();
}
}
return true;
if (verbose)
log(" explored %d nodes\n", nodes);
return done;
};
auto backtrack = [&](){
@ -785,15 +809,78 @@ struct Router2
next_score.congest = 0.0;
next_score.delay = 0.0;
next_score.togo = get_togo_cost(net, i, src_wire_idx, dst_wire, false, crit_weight);
auto curr = QueuedWire(src_wire_idx, next_score, t.rng.rng());
auto src_qw = QueuedWire(src_wire_idx, next_score, t.rng.rng());
t.fwd_queue.push(src_qw);
t.bwd_queue.push(src_qw);
bool done = false;
while (!t.fwd_queue.empty()) {
auto curr = t.fwd_queue.top();
t.fwd_queue.pop();
auto &curr_data = flat_wires.at(curr.wire);
nodes++;
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
WireId next = ctx->getPipDstWire(dh);
int next_idx = wire_to_idx.at(next);
// Skip pips outside of box in bounding-box mode
if (is_bb && !hit_test_pip(nd.bb, ctx->getPipLocation(dh)))
continue;
if (!ctx->checkPipAvailForNet(dh, net))
continue;
if (was_visited_fwd(next_idx))
continue;
auto &nwd = flat_wires.at(next_idx);
if (nwd.unavailable)
continue;
// Reserved for another net
if (nwd.reserved_net != -1 && nwd.reserved_net != net->udata)
continue;
// Don't allow the same wire to be bound to the same net with a different driving pip
auto fnd_wire = nd.wires.find(next);
if (fnd_wire != nd.wires.end() && fnd_wire->second.first != dh)
continue;
if (!thread_test_wire(t, nwd))
continue; // thread safety issue
WireScore next_score;
next_score.criticality = crit;
next_score.congest = curr.score.congest + score_wire_for_arc_congest(net, i, phys_pin, next, dh, crit_weight);
next_score.delay = curr.score.delay + score_wire_for_arc_delay(net, i, phys_pin, next, dh, crit_weight);
next_score.togo = get_togo_cost(net, i, next_idx, dst_wire, false, crit_weight);
auto qw = QueuedWire(next_idx, next_score, t.rng.rng());
if (net->wires.find(next) != net->wires.end()) {
log("Discovered existing routing wire %s\n", ctx->nameOfWire(next));
t.fwd_queue.push(qw);
t.bwd_queue.push(qw);
} else {
t.bwd_queue.push(qw);
}
set_visited_fwd(t, next_idx, dh);
if (next_idx == dst_wire_idx)
done = true;
}
}
int fs_calls = 0;
int bt_calls = 0;
if (!done) {
NPNR_ASSERT(!t.bwd_queue.empty());
auto curr = t.bwd_queue.top();
t.bwd_queue.pop();
NPNR_ASSERT(curr.wire < flat_wires.size());
bool done = false;
int fs_calls = 0;
int bt_calls = 0;
while (!done) {
fs_calls++;
if (verbose)
log("fast_search from %s to %s\n", ctx->nameOfWire(flat_wires.at(curr.wire).w), ctx->nameOfWire(dst_wire));
done = fast_search(curr);
if (!done) {
if (t.bwd_queue.empty() && low_prio.empty()) {
@ -801,15 +888,22 @@ struct Router2
//log("fail; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
return ARC_RETRY_WITHOUT_BB;
} else {
if (verbose)
log(" failed; backtracking\n");
curr = backtrack();
bt_calls++;
}
}
}
}
int cursor_bwd = dst_wire_idx;
int path_prio = 0, path_len = 0;
while (was_visited_fwd(cursor_bwd)) {
PipId pip = flat_wires.at(cursor_bwd).pip_fwd;
if (prios.find(pip) != prios.end())
path_prio += prios.at(pip);
path_len++;
if (pip == PipId() && cursor_bwd != src_wire_idx)
break;
bind_pip_internal(nd, i, cursor_bwd, pip);
@ -826,8 +920,20 @@ struct Router2
cursor_bwd = wire_to_idx.at(ctx->getPipSrcWire(pip));
}
update_wire_by_loc(t, net, i, phys_pin, is_mt);
t.processed_sinks.insert(dst_wire);
ad.routed = true;
reset_wires(t);
//log("done; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
if (verbose)
log("done; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
auto arc_end = std::chrono::high_resolution_clock::now();
auto box = ctx->getRouteBoundingBox(src_wire, dst_wire);
//printf("%d,%d,%f,%d\n", box.x1 - box.x0, box.y1 - box.y0, crit, path_len);
if (verbose)
log("Routing arc %d of net '%s' (is_bb = %d) took %02fs; path: %.03f/%d/%d/%d nodes\n", i.idx(), ctx->nameOf(net), is_bb,
std::chrono::duration<float>(arc_end - arc_start).count(), float(path_prio)/float(path_len), lowest_priority(src_qw), path_len, nodes);
return ARC_SUCCESS;
}
@ -1703,6 +1809,23 @@ struct Router2
++iter;
if (curr_cong_weight < 1e9)
curr_cong_weight += cfg.curr_cong_mult;
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("100 slowest nets by runtime:\n");
for (int i = 0; i < std::min(int(nets_by_runtime.size()), 100); i++) {
if (nets_by_runtime.at(i).first < 1000000.0)
break;
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.entries()),
nets_by_runtime.at(i).first / 1000.0);
}
}
tmg.print_fmax();
} while (!failed_nets.empty());
if (cfg.perf_profile) {
@ -1749,7 +1872,7 @@ Router2Cfg::Router2Cfg(Context *ctx)
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.25f);
perf_profile = ctx->setting<bool>("router2/perfProfile", false);
perf_profile = ctx->setting<bool>("router2/perfProfile", true);
if (ctx->settings.count(ctx->id("router2/heatmap")))
heatmap = ctx->settings.at(ctx->id("router2/heatmap")).as_string();
else