Skip to content

RRGraphView::node_capacity() Implementation #1780

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion utils/route_diag/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ static void do_one_route(int source_node, int sink_node,
* to route this net, even ignoring congestion, it returns false. In this *
* case the rr_graph is disconnected and you can give up. */
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

t_rt_node* rt_root = init_route_tree_to_source_no_net(source_node);
Expand Down Expand Up @@ -123,7 +124,7 @@ static void do_one_route(int source_node, int sink_node,
print_route_tree(rt_root);
VTR_LOG("\n");

VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= device_ctx.rr_nodes[rt_root->inode].capacity(), "SOURCE should never be congested");
VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= rr_graph.node_capacity(RRNodeId(rt_root->inode)), "SOURCE should never be congested");
free_route_tree(rt_root);
} else {
VTR_LOG("Routed failed");
Expand Down
5 changes: 5 additions & 0 deletions vpr/src/device/rr_graph_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ class RRGraphView {
return node_storage_.node_type(node);
}

/* Get the capacity of a routing resource node. This function is inlined for runtime optimization. */
inline short node_capacity(RRNodeId node) const {
return node_storage_.node_capacity(node);
}

/* Return the fast look-up data structure for queries from client functions */
const RRSpatialLookup& node_lookup() const {
return node_lookup_;
Expand Down
8 changes: 4 additions & 4 deletions vpr/src/draw/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ static void draw_congestion(ezgl::renderer* g) {
std::vector<int> congested_rr_nodes = collect_congested_rr_nodes();
for (int inode : congested_rr_nodes) {
short occ = route_ctx.rr_node_route_inf[inode].occ();
short capacity = device_ctx.rr_nodes[inode].capacity();
short capacity = rr_graph.node_capacity(RRNodeId(inode));

float congestion_ratio = float(occ) / capacity;

Expand All @@ -1133,10 +1133,10 @@ static void draw_congestion(ezgl::renderer* g) {
//valued nodes are not overdrawn by lower value ones (e.g-> when zoomed-out far)
auto cmp_ascending_acc_cost = [&](int lhs_node, int rhs_node) {
short lhs_occ = route_ctx.rr_node_route_inf[lhs_node].occ();
short lhs_capacity = device_ctx.rr_nodes[lhs_node].capacity();
short lhs_capacity = rr_graph.node_capacity(RRNodeId(lhs_node));

short rhs_occ = route_ctx.rr_node_route_inf[rhs_node].occ();
short rhs_capacity = device_ctx.rr_nodes[rhs_node].capacity();
short rhs_capacity = rr_graph.node_capacity(RRNodeId(rhs_node));

float lhs_cong_ratio = float(lhs_occ) / lhs_capacity;
float rhs_cong_ratio = float(rhs_occ) / rhs_capacity;
Expand Down Expand Up @@ -1170,7 +1170,7 @@ static void draw_congestion(ezgl::renderer* g) {
//Draw each congested node
for (int inode : congested_rr_nodes) {
short occ = route_ctx.rr_node_route_inf[inode].occ();
short capacity = device_ctx.rr_nodes[inode].capacity();
short capacity = rr_graph.node_capacity(RRNodeId(inode));

float congestion_ratio = float(occ) / capacity;

Expand Down
2 changes: 1 addition & 1 deletion vpr/src/route/check_rr_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ void check_rr_node(int inode, enum e_route_type route_type, const DeviceContext&
ylow = device_ctx.rr_nodes[inode].ylow();
yhigh = device_ctx.rr_nodes[inode].yhigh();
ptc_num = device_ctx.rr_nodes[inode].ptc_num();
capacity = device_ctx.rr_nodes[inode].capacity();
capacity = rr_graph.node_capacity(RRNodeId(inode));
cost_index = device_ctx.rr_nodes[inode].cost_index();
type = nullptr;

Expand Down
6 changes: 4 additions & 2 deletions vpr/src/route/overuse_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static void log_single_overused_node_status(int overuse_index, RRNodeId inode);
*/
void log_overused_nodes_status(int max_logged_overused_rr_nodes) {
const auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
const auto& route_ctx = g_vpr_ctx.routing();

//Print overuse info header
Expand All @@ -36,7 +37,7 @@ void log_overused_nodes_status(int max_logged_overused_rr_nodes) {
//Print overuse info body
int overuse_index = 0;
for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) {
int overuse = route_ctx.rr_node_route_inf[inode].occ() - device_ctx.rr_nodes[inode].capacity();
int overuse = route_ctx.rr_node_route_inf[inode].occ() - rr_graph.node_capacity(RRNodeId(inode));

if (overuse > 0) {
log_single_overused_node_status(overuse_index, RRNodeId(inode));
Expand Down Expand Up @@ -130,6 +131,7 @@ void report_overused_nodes() {
*/
void generate_overused_nodes_to_congested_net_lookup(std::map<RRNodeId, std::set<ClusterNetId>>& nodes_to_nets_lookup) {
const auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
const auto& route_ctx = g_vpr_ctx.routing();
const auto& cluster_ctx = g_vpr_ctx.clustering();

Expand All @@ -139,7 +141,7 @@ void generate_overused_nodes_to_congested_net_lookup(std::map<RRNodeId, std::set
for (t_trace* tptr = route_ctx.trace[net_id].head; tptr != nullptr; tptr = tptr->next) {
int inode = tptr->index;

int overuse = route_ctx.rr_node_route_inf[inode].occ() - device_ctx.rr_nodes[inode].capacity();
int overuse = route_ctx.rr_node_route_inf[inode].occ() - rr_graph.node_capacity(RRNodeId(inode));
if (overuse > 0) {
nodes_to_nets_lookup[RRNodeId(inode)].insert(net_id);
}
Expand Down
20 changes: 13 additions & 7 deletions vpr/src/route/route_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,11 @@ bool feasible_routing() {
* that the occupancy arrays are up to date when it is called. */

auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) {
if (route_ctx.rr_node_route_inf[inode].occ() > device_ctx.rr_nodes[inode].capacity()) {
if (route_ctx.rr_node_route_inf[inode].occ() > rr_graph.node_capacity(RRNodeId(inode))) {
return (false);
}
}
Expand All @@ -339,12 +340,13 @@ bool feasible_routing() {
//Returns all RR nodes in the current routing which are congested
std::vector<int> collect_congested_rr_nodes() {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

std::vector<int> congested_rr_nodes;
for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) {
short occ = route_ctx.rr_node_route_inf[inode].occ();
short capacity = device_ctx.rr_nodes[inode].capacity();
short capacity = rr_graph.node_capacity(RRNodeId(inode));

if (occ > capacity) {
congested_rr_nodes.push_back(inode);
Expand Down Expand Up @@ -424,11 +426,12 @@ void pathfinder_update_acc_cost_and_overuse_info(float acc_fac, OveruseInfo& ove
* This routine also creates a new overuse info for the current routing iteration. */

auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.mutable_routing();
size_t overused_nodes = 0, total_overuse = 0, worst_overuse = 0;

for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) {
int overuse = route_ctx.rr_node_route_inf[inode].occ() - device_ctx.rr_nodes[inode].capacity();
int overuse = route_ctx.rr_node_route_inf[inode].occ() - rr_graph.node_capacity(RRNodeId(inode));

// If overused, update the acc_cost and add this node to the overuse info
// If not, do nothing
Expand Down Expand Up @@ -1453,9 +1456,10 @@ static void adjust_one_rr_occ_and_acc_cost(int inode, int add_or_sub, float acc_

auto& route_ctx = g_vpr_ctx.mutable_routing();
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

int new_occ = route_ctx.rr_node_route_inf[inode].occ() + add_or_sub;
int capacity = device_ctx.rr_nodes[inode].capacity();
int capacity = rr_graph.node_capacity(RRNodeId(inode));
route_ctx.rr_node_route_inf[inode].set_occ(new_occ);

if (new_occ < capacity) {
Expand Down Expand Up @@ -1512,7 +1516,7 @@ void print_traceback(const t_trace* trace) {
VTR_LOG("*"); //Reached non-configurably
}

if (route_ctx.rr_node_route_inf[inode].occ() > device_ctx.rr_nodes[inode].capacity()) {
if (route_ctx.rr_node_route_inf[inode].occ() > rr_graph.node_capacity(RRNodeId(inode))) {
VTR_LOG(" x"); //Overused
}
VTR_LOG("\n");
Expand Down Expand Up @@ -1587,6 +1591,7 @@ bool validate_traceback_recurr(t_trace* trace, std::set<int>& seen_rr_nodes) {
//Print information about an invalid routing, caused by overused routing resources
void print_invalid_routing_info() {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& route_ctx = g_vpr_ctx.routing();

Expand All @@ -1604,7 +1609,7 @@ void print_invalid_routing_info() {

for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) {
int occ = route_ctx.rr_node_route_inf[inode].occ();
int cap = device_ctx.rr_nodes[inode].capacity();
int cap = rr_graph.node_capacity(RRNodeId(inode));
if (occ > cap) {
VTR_LOG(" %s is overused (occ=%d capacity=%d)\n", describe_rr_node(inode).c_str(), occ, cap);

Expand Down Expand Up @@ -1641,13 +1646,14 @@ void print_rr_node_route_inf() {
void print_rr_node_route_inf_dot() {
auto& route_ctx = g_vpr_ctx.routing();
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

VTR_LOG("digraph G {\n");
VTR_LOG("\tnode[shape=record]\n");
for (size_t inode = 0; inode < route_ctx.rr_node_route_inf.size(); ++inode) {
if (!std::isinf(route_ctx.rr_node_route_inf[inode].path_cost)) {
VTR_LOG("\tnode%zu[label=\"{%zu (%s)", inode, inode, device_ctx.rr_nodes[inode].type_string());
if (route_ctx.rr_node_route_inf[inode].occ() > device_ctx.rr_nodes[inode].capacity()) {
if (route_ctx.rr_node_route_inf[inode].occ() > rr_graph.node_capacity(RRNodeId(inode))) {
VTR_LOG(" x");
}
VTR_LOG("}\"]\n");
Expand Down
6 changes: 4 additions & 2 deletions vpr/src/route/route_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ inline float get_single_rr_cong_acc_cost(int inode) {
/* Returns the present congestion cost of using this rr_node */
inline float get_single_rr_cong_pres_cost(int inode, float pres_fac) {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

int occ = route_ctx.rr_node_route_inf[inode].occ();
int capacity = device_ctx.rr_nodes[inode].capacity();
int capacity = rr_graph.node_capacity(RRNodeId(inode));

if (occ >= capacity) {
return (1. + pres_fac * (occ + 1 - capacity));
Expand All @@ -65,10 +66,11 @@ inline float get_single_rr_cong_pres_cost(int inode, float pres_fac) {
* *ignoring* non-configurable edges */
inline float get_single_rr_cong_cost(int inode, float pres_fac) {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

float pres_cost;
int overuse = route_ctx.rr_node_route_inf[inode].occ() - device_ctx.rr_nodes[inode].capacity();
int overuse = route_ctx.rr_node_route_inf[inode].occ() - rr_graph.node_capacity(RRNodeId(inode));

if (overuse >= 0) {
pres_cost = (1. + pres_fac * (overuse + 1));
Expand Down
7 changes: 4 additions & 3 deletions vpr/src/route/route_timing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,7 @@ bool timing_driven_route_net(ConnectionRouter& router,
}
}
}
VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= device_ctx.rr_nodes[rt_root->inode].capacity(), "SOURCE should never be congested");
VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= rr_graph.node_capacity(RRNodeId(rt_root->inode)), "SOURCE should never be congested");

// route tree is not kept persistent since building it from the traceback the next iteration takes almost 0 time
VTR_LOGV_DEBUG(f_router_debug, "Routed Net %zu (%zu sinks)\n", size_t(net_id), num_sinks);
Expand Down Expand Up @@ -1597,6 +1597,7 @@ static bool timing_driven_check_net_delays(ClbNetPinsMatrix<float>& net_delay) {
static bool should_route_net(ClusterNetId net_id, CBRR& connections_inf, bool if_force_reroute) {
auto& route_ctx = g_vpr_ctx.routing();
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

t_trace* tptr = route_ctx.trace[net_id].head;

Expand All @@ -1608,7 +1609,7 @@ static bool should_route_net(ClusterNetId net_id, CBRR& connections_inf, bool if
for (;;) {
int inode = tptr->index;
int occ = route_ctx.rr_node_route_inf[inode].occ();
int capacity = device_ctx.rr_nodes[inode].capacity();
int capacity = rr_graph.node_capacity(RRNodeId(inode));

if (occ > capacity) {
return true; /* overuse detected */
Expand Down Expand Up @@ -1672,7 +1673,7 @@ static size_t calculate_wirelength_available() {
size_t length_x = device_ctx.rr_nodes[i].xhigh() - device_ctx.rr_nodes[i].xlow();
size_t length_y = device_ctx.rr_nodes[i].yhigh() - device_ctx.rr_nodes[i].ylow();

available_wirelength += device_ctx.rr_nodes[i].capacity() * (length_x + length_y + 1);
available_wirelength += rr_graph.node_capacity(RRNodeId(i)) * (length_x + length_y + 1);
}
}
return available_wirelength;
Expand Down
18 changes: 11 additions & 7 deletions vpr/src/route/route_tree_timing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ void print_route_tree(const t_rt_node* rt_node, int depth) {
}

auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
VTR_LOG("%srt_node: %d (%s) \t ipin: %d \t R: %g \t C: %g \t delay: %g",
indent.c_str(), rt_node->inode, device_ctx.rr_nodes[rt_node->inode].type_string(), rt_node->net_pin_index, rt_node->R_upstream, rt_node->C_downstream, rt_node->Tdel);

Expand All @@ -697,7 +698,7 @@ void print_route_tree(const t_rt_node* rt_node, int depth) {
}

auto& route_ctx = g_vpr_ctx.routing();
if (route_ctx.rr_node_route_inf[rt_node->inode].occ() > device_ctx.rr_nodes[rt_node->inode].capacity()) {
if (route_ctx.rr_node_route_inf[rt_node->inode].occ() > rr_graph.node_capacity(RRNodeId(rt_node->inode))) {
VTR_LOG(" x");
}

Expand Down Expand Up @@ -978,7 +979,7 @@ static t_rt_node* prune_route_tree_recurr(t_rt_node* node, CBRR& connections_inf
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();
bool congested = (route_ctx.rr_node_route_inf[node->inode].occ() > device_ctx.rr_nodes[node->inode].capacity());
bool congested = (route_ctx.rr_node_route_inf[node->inode].occ() > rr_graph.node_capacity(RRNodeId(node->inode)));
int node_set = -1;
auto itr = device_ctx.rr_node_to_non_config_node_set.find(node->inode);
if (itr != device_ctx.rr_node_to_non_config_node_set.end()) {
Expand Down Expand Up @@ -1175,7 +1176,7 @@ t_rt_node* prune_route_tree(t_rt_node* rt_root, CBRR& connections_inf, std::vect

VTR_ASSERT_MSG(rr_graph.node_type(RRNodeId(rt_root->inode)) == SOURCE, "Root of route tree must be SOURCE");

VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= device_ctx.rr_nodes[rt_root->inode].capacity(),
VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= rr_graph.node_capacity(RRNodeId(rt_root->inode)),
"Route tree root/SOURCE should never be congested");

return prune_route_tree_recurr(rt_root, connections_inf, false, non_config_node_set_usage);
Expand Down Expand Up @@ -1275,13 +1276,14 @@ static void print_node_inf(const t_rt_node* rt_node) {

static void print_node_congestion(const t_rt_node* rt_node) {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

int inode = rt_node->inode;
const auto& node_inf = route_ctx.rr_node_route_inf[inode];
const auto& node = device_ctx.rr_nodes[inode];
const short& node_capacity = rr_graph.node_capacity(RRNodeId(inode));
VTR_LOG("%2d %2d|%-6d-> ", node_inf.acc_cost, rt_node->Tdel,
node_inf.occ(), node.capacity(), inode);
node_inf.occ(), node_capacity, inode);
}

void print_route_tree_inf(const t_rt_node* rt_root) {
Expand Down Expand Up @@ -1359,6 +1361,7 @@ bool is_valid_skeleton_tree(const t_rt_node* root) {
bool is_valid_route_tree(const t_rt_node* root) {
// check upstream resistance
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

constexpr float CAP_REL_TOL = 1e-6;
Expand Down Expand Up @@ -1393,7 +1396,7 @@ bool is_valid_route_tree(const t_rt_node* root) {
// sink, must not be congested
if (!edge) {
int occ = route_ctx.rr_node_route_inf[inode].occ();
int capacity = device_ctx.rr_nodes[inode].capacity();
int capacity = rr_graph.node_capacity(RRNodeId(inode));
if (occ > capacity) {
VTR_LOG("SINK %d occ %d > cap %d\n", inode, occ, capacity);
return false;
Expand Down Expand Up @@ -1437,9 +1440,10 @@ bool is_valid_route_tree(const t_rt_node* root) {
bool is_uncongested_route_tree(const t_rt_node* root) {
auto& route_ctx = g_vpr_ctx.routing();
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

int inode = root->inode;
if (route_ctx.rr_node_route_inf[inode].occ() > device_ctx.rr_nodes[inode].capacity()) {
if (route_ctx.rr_node_route_inf[inode].occ() > rr_graph.node_capacity(RRNodeId(inode))) {
//This node is congested
return false;
}
Expand Down
5 changes: 3 additions & 2 deletions vpr/src/route/route_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,23 @@ vtr::Matrix<float> calculate_routing_avail(t_rr_type rr_type) {
vtr::Matrix<float> avail({{device_ctx.grid.width(), device_ctx.grid.height()}}, 0.);
for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) {
auto& rr_node = device_ctx.rr_nodes[inode];
const short& rr_node_capacity = rr_graph.node_capacity(RRNodeId(inode));

if (rr_graph.node_type(RRNodeId(inode)) == CHANX && rr_type == CHANX) {
VTR_ASSERT(rr_graph.node_type(RRNodeId(inode)) == CHANX);
VTR_ASSERT(rr_node.ylow() == rr_node.yhigh());

int y = rr_node.ylow();
for (int x = rr_node.xlow(); x <= rr_node.xhigh(); ++x) {
avail[x][y] += rr_node.capacity();
avail[x][y] += rr_node_capacity;
}
} else if (rr_graph.node_type(RRNodeId(inode)) == CHANY && rr_type == CHANY) {
VTR_ASSERT(rr_graph.node_type(RRNodeId(inode)) == CHANY);
VTR_ASSERT(rr_node.xlow() == rr_node.xhigh());

int x = rr_node.xlow();
for (int y = rr_node.ylow(); y <= rr_node.yhigh(); ++y) {
avail[x][y] += rr_node.capacity();
avail[x][y] += rr_node_capacity;
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion vpr/src/route/router_delay_profiling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ bool RouterDelayProfiler::calculate_delay(int source_node, int sink_node, const
* to route this net, even ignoring congestion, it returns false. In this *
* case the rr_graph is disconnected and you can give up. */
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

//vtr::ScopedStartFinishTimer t(vtr::string_fmt("Profiling Delay from %s at %d,%d (%s) to %s at %d,%d (%s)",
Expand Down Expand Up @@ -79,7 +80,7 @@ bool RouterDelayProfiler::calculate_delay(int source_node, int sink_node, const
//find delay
*net_delay = rt_node_of_sink->Tdel;

VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= device_ctx.rr_nodes[rt_root->inode].capacity(), "SOURCE should never be congested");
VTR_ASSERT_MSG(route_ctx.rr_node_route_inf[rt_root->inode].occ() <= rr_graph.node_capacity(RRNodeId(rt_root->inode)), "SOURCE should never be congested");
free_route_tree(rt_root);
}

Expand Down
Loading