Skip to content

Faster check_non_configurable_edges #2839

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 7 commits into from
Jan 28, 2025
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
20 changes: 14 additions & 6 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1637,7 +1637,7 @@ typedef t_routing_status<AtomNetId> t_atom_net_routing_status;

/** Edge between two RRNodes */
struct t_node_edge {
t_node_edge(RRNodeId fnode, RRNodeId tnode)
t_node_edge(RRNodeId fnode, RRNodeId tnode) noexcept
: from_node(fnode)
, to_node(tnode) {}

Expand All @@ -1650,10 +1650,18 @@ struct t_node_edge {
}
};

///@brief Non-configurably connected nodes and edges in the RR graph
/**
* @brief Groups of non-configurably connected nodes and edges in the RR graph.
* @note Each group is represented by a node set and an edge set, stored at the same index.
*
* For example, in an architecture with L-shaped wires formed by an x- and y-directed segment
* connected by an electrical short, each L-shaped wire corresponds to a new group. The group's
* index provides access to its node set (containing two RRNodeIds) and edge set (containing two
* directed edge in opposite directions).
*/
struct t_non_configurable_rr_sets {
std::set<std::set<RRNodeId>> node_sets;
std::set<std::set<t_node_edge>> edge_sets;
std::vector<std::set<RRNodeId>> node_sets;
std::vector<std::set<t_node_edge>> edge_sets;
};

///@brief Power estimation options
Expand All @@ -1665,11 +1673,11 @@ struct t_power_opts {
* @param max= Maximum channel width between x_max and y_max.
* @param x_min= Minimum channel width of horizontal channels. Initialized when init_chan() is invoked in rr_graph2.cpp
* @param y_min= Same as above but for vertical channels.
* @param x_max= Maximum channel width of horiozntal channels. Initialized when init_chan() is invoked in rr_graph2.cpp
* @param x_max= Maximum channel width of horizontal channels. Initialized when init_chan() is invoked in rr_graph2.cpp
* @param y_max= Same as above but for vertical channels.
* @param x_list= Stores the channel width of all horizontal channels and thus goes from [0..grid.height()]
* (imagine a 2D Cartesian grid with horizontal lines starting at every grid point on a line parallel to the y-axis)
* @param y_list= Stores the channel width of all verical channels and thus goes from [0..grid.width()]
* @param y_list= Stores the channel width of all vertical channels and thus goes from [0..grid.width()]
* (imagine a 2D Cartesian grid with vertical lines starting at every grid point on a line parallel to the x-axis)
*/

Expand Down
108 changes: 77 additions & 31 deletions vpr/src/route/check_route.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <cstdio>

#include "check_route.h"

#include "route_common.h"
#include "vtr_assert.h"
Expand All @@ -11,7 +12,7 @@

#include "globals.h"
#include "route_export.h"
#include "check_route.h"

#include "rr_graph.h"
#include "check_rr_graph.h"
#include "read_xml_arch_file.h"
Expand Down Expand Up @@ -39,11 +40,32 @@ static void check_locally_used_clb_opins(const t_clb_opins_used& clb_opins_used_
enum e_route_type route_type,
bool is_flat);

/**
* Checks that all non-configurable edges are in a legal configuration.
* @param net_list The netlist whose routing is to be checked.
* @param is_flat True if flat routing is enabled; otherwise false.
*/
static void check_all_non_configurable_edges(const Netlist<>& net_list, bool is_flat);

/**
* @brief Checks that the specified routing is legal with respect to non-configurable edges.
* For routing to be valid, if any non-configurable edge is used, all nodes in the same set
* and the required connecting edges in the set must also be used.
*
* @param net_list A reference to the netlist.
* @param net The net id for which the check is done.
* @param non_configurable_rr_sets Node and edge sets that constitute non-configurable RR sets.
* @param rrnode_set_id Specifies which RR sets each RR node is part of. These indices can be used to
* access elements of node_sets and edge_sets in non_configurable_rr_sets.
* @param is_flat Indicates whether flat routing is enabled.
* @return True if check is done successfully; otherwise false.
*/
static bool check_non_configurable_edges(const Netlist<>& net_list,
ParentNetId net,
const t_non_configurable_rr_sets& non_configurable_rr_sets,
const vtr::vector<RRNodeId, int>& rrnode_set_id,
bool is_flat);

static void check_net_for_stubs(const Netlist<>& net_list,
ParentNetId net,
bool is_flat);
Expand All @@ -65,13 +87,9 @@ void check_route(const Netlist<>& net_list,
return;
}

int max_pins;
unsigned int ipin;
bool valid, connects;

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

const size_t num_switches = rr_graph.num_rr_switches();

Expand All @@ -83,7 +101,7 @@ void check_route(const Netlist<>& net_list,
* is a successful routing, but I want to double check it here. */

recompute_occupancy_from_scratch(net_list, is_flat);
valid = feasible_routing();
const bool valid = feasible_routing();
if (valid == false) {
VPR_ERROR(VPR_ERROR_ROUTE,
"Error in check_route -- routing resources are overused.\n");
Expand All @@ -95,7 +113,7 @@ void check_route(const Netlist<>& net_list,
is_flat);
}

max_pins = 0;
int max_pins = 0;
for (auto net_id : net_list.nets())
max_pins = std::max(max_pins, (int)net_list.net_pins(net_id).size());

Expand Down Expand Up @@ -129,7 +147,7 @@ void check_route(const Netlist<>& net_list,
check_switch(rt_node, num_switches);

if (rt_node.parent()) {
connects = check_adjacent(rt_node.parent()->inode, rt_node.inode, is_flat);
bool connects = check_adjacent(rt_node.parent()->inode, rt_node.inode, is_flat);
if (!connects) {
VPR_ERROR(VPR_ERROR_ROUTE,
"in check_route: found non-adjacent segments in traceback while checking net %d:\n"
Expand All @@ -154,7 +172,7 @@ void check_route(const Netlist<>& net_list,
num_sinks, net_list.net_sinks(net_id).size());
}

for (ipin = 0; ipin < net_list.net_pins(net_id).size(); ipin++) {
for (size_t ipin = 0; ipin < net_list.net_pins(net_id).size(); ipin++) {
if (pin_done[ipin] == false) {
VPR_FATAL_ERROR(VPR_ERROR_ROUTE,
"in check_route: net %zu does not connect to pin %d.\n", size_t(net_id), ipin);
Expand Down Expand Up @@ -194,7 +212,7 @@ static void check_sink(const Netlist<>& net_list,
inode, net_list.net_name(net_id).c_str(), size_t(net_id));
}

VTR_ASSERT(!pin_done[net_pin_index]); /* Should not have found a routed cnnection to it before */
VTR_ASSERT(!pin_done[net_pin_index]); /* Should not have found a routed connection to it before */
pin_done[net_pin_index] = true;
}

Expand Down Expand Up @@ -595,43 +613,71 @@ static void check_node_and_range(RRNodeId inode,
is_flat);
}

//Checks that all non-configurable edges are in a legal configuration
//This check is slow, so it has been moved out of check_route()
static void check_all_non_configurable_edges(const Netlist<>& net_list, bool is_flat) {
const auto& rr_graph = g_vpr_ctx.device().rr_graph;

vtr::ScopedStartFinishTimer timer("Checking to ensure non-configurable edges are legal");
auto non_configurable_rr_sets = identify_non_configurable_rr_sets();
const t_non_configurable_rr_sets non_configurable_rr_sets = identify_non_configurable_rr_sets();

// Specifies which RR set each node is part of.
vtr::vector<RRNodeId, int> rrnode_set_ids(rr_graph.num_nodes(), -1);

const size_t num_non_cfg_rr_sets = non_configurable_rr_sets.node_sets.size();

// Populate rrnode_set_ids
for (size_t non_cfg_rr_set_id = 0; non_cfg_rr_set_id < num_non_cfg_rr_sets; non_cfg_rr_set_id++) {
const std::set<RRNodeId>& node_set = non_configurable_rr_sets.node_sets[non_cfg_rr_set_id];
for (const RRNodeId node_id : node_set) {
VTR_ASSERT_SAFE(rrnode_set_ids[node_id] == -1);
rrnode_set_ids[node_id] = (int)non_cfg_rr_set_id;
}
}

for (auto net_id : net_list.nets()) {
check_non_configurable_edges(net_list,
net_id,
non_configurable_rr_sets,
rrnode_set_ids,
is_flat);
}
}

// Checks that the specified routing is legal with respect to non-configurable edges
//
//For routing to be legal if *any* non-configurable edge is used, so must *all*
//other non-configurable edges in the same set
static bool check_non_configurable_edges(const Netlist<>& net_list,
ParentNetId net,
const t_non_configurable_rr_sets& non_configurable_rr_sets,
const vtr::vector<RRNodeId, int>& rrnode_set_id,
bool is_flat) {
const auto& device_ctx = g_vpr_ctx.device();
auto& route_ctx = g_vpr_ctx.mutable_routing();
const auto& route_ctx = g_vpr_ctx.routing();

if (!route_ctx.route_trees[net]) // no routing
return true;

// Collect all the edges used by this net's routing
// Collect all the nodes, edges, and non-configurable RR set ids used by this net's routing
std::set<t_node_edge> routing_edges;
std::set<RRNodeId> routing_nodes;
for (auto& rt_node : route_ctx.route_trees[net].value().all_nodes()) {
std::set<int> routing_non_configurable_rr_set_ids;
for (const RouteTreeNode& rt_node : route_ctx.route_trees[net].value().all_nodes()) {
routing_nodes.insert(rt_node.inode);
if (!rt_node.parent())
continue;
t_node_edge edge = {rt_node.parent()->inode, rt_node.inode};
routing_edges.insert(edge);

if (rrnode_set_id[rt_node.inode] >= 0) { // The node belongs to a non-configurable RR set
routing_non_configurable_rr_set_ids.insert(rrnode_set_id[rt_node.inode]);
}
}

// Copy used non-configurable RR sets
// This is done to check legality only for used non-configurable RR sets. If a non-configurable RR set
// is not used by a net's routing, it cannot violate the requirements of using that non-configurable RR set.
t_non_configurable_rr_sets used_non_configurable_rr_sets;
used_non_configurable_rr_sets.node_sets.reserve(routing_non_configurable_rr_set_ids.size());
used_non_configurable_rr_sets.edge_sets.reserve(routing_non_configurable_rr_set_ids.size());
for (const int set_idx : routing_non_configurable_rr_set_ids) {
used_non_configurable_rr_sets.node_sets.emplace_back(non_configurable_rr_sets.node_sets[set_idx]);
used_non_configurable_rr_sets.edge_sets.emplace_back(non_configurable_rr_sets.edge_sets[set_idx]);
}

//We need to perform two types of checks:
Expand All @@ -640,13 +686,13 @@ static bool check_non_configurable_edges(const Netlist<>& net_list,
// 2) That all (required) non-configurable edges are used
//
//We need to check (2) in addition to (1) to ensure that (1) did not pass
//because the nodes 'happend' to be connected together by configurable
//because the nodes 'happened' to be connected together by configurable
//routing (to be legal, by definition, they must be connected by
//non-configurable routing).

//Check that all nodes in each non-configurable set are full included if any element
//Check that all nodes in each non-configurable set are fully included if any element
//within a set is used by the routing
for (const auto& rr_nodes : non_configurable_rr_sets.node_sets) {
for (const auto& rr_nodes : used_non_configurable_rr_sets.node_sets) {
//Compute the intersection of the routing and current non-configurable nodes set
std::vector<RRNodeId> intersection;
std::set_intersection(routing_nodes.begin(), routing_nodes.end(),
Expand All @@ -668,7 +714,7 @@ static bool check_non_configurable_edges(const Netlist<>& net_list,
routing_nodes.begin(), routing_nodes.end(),
std::back_inserter(difference));

VTR_ASSERT(difference.size() > 0);
VTR_ASSERT(!difference.empty());
std::string msg = vtr::string_fmt(
"Illegal routing for net '%s' (#%zu) some "
"required non-configurably connected nodes are missing:\n",
Expand All @@ -685,7 +731,7 @@ static bool check_non_configurable_edges(const Netlist<>& net_list,

//Check that any sets of non-configurable RR graph edges are fully included
//in the routing, if any of a set's edges are used
for (const auto& rr_edges : non_configurable_rr_sets.edge_sets) {
for (const auto& rr_edges : used_non_configurable_rr_sets.edge_sets) {
//Compute the intersection of the routing and current non-configurable edge set
std::vector<t_node_edge> intersection;
std::set_intersection(routing_edges.begin(), routing_edges.end(),
Expand All @@ -698,7 +744,7 @@ static bool check_non_configurable_edges(const Netlist<>& net_list,
//Since at least one non-configurable edge is used, to be legal
//the full set of non-configurably connected edges must be used.
//
//This is somewhat complicted by the fact that non-configurable edges
//This is somewhat complicated by the fact that non-configurable edges
//are sometimes bi-directional (e.g. electrical shorts) and so appear
//in rr_edges twice (once forward, once backward). Only one of the
//paired edges need appear to be correct.
Expand Down Expand Up @@ -791,9 +837,9 @@ class StubFinder {
std::set<int> stub_nodes_;
};

//Cheks for stubs in a net's routing.
//Checks for stubs in a net's routing.
//
//Stubs (routing branches which don't connect to SINKs) serve no purpose, and only chew up wiring unecessarily.
//Stubs (routing branches which don't connect to SINKs) serve no purpose, and only chew up wiring unnecessarily.
//The only exception are stubs required by non-configurable switches (e.g. shorts).
//
//We treat any configurable stubs as an error.
Expand Down
10 changes: 5 additions & 5 deletions vpr/src/route/edge_groups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ t_non_configurable_rr_sets EdgeGroups::output_sets() {
std::set<t_node_edge> edge_set;
std::set<RRNodeId> node_set(nodes.begin(), nodes.end());

for (const auto& src : node_set) {
for (const auto& dest : graph_[src].edges) {
edge_set.emplace(t_node_edge(src, dest));
for (const RRNodeId src : node_set) {
for (const RRNodeId dest : graph_[src].edges) {
edge_set.emplace(src, dest);
}
}

sets.node_sets.emplace(std::move(node_set));
sets.edge_sets.emplace(std::move(edge_set));
sets.node_sets.emplace_back(std::move(node_set));
sets.edge_sets.emplace_back(std::move(edge_set));
}

return sets;
Expand Down
10 changes: 5 additions & 5 deletions vpr/test/test_edge_groups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ TEST_CASE("edge_groups_create_sets", "[vpr]") {
// Build chains from the given connected sets
int max_node_id = 0;
std::vector<std::pair<int, int>> edges;
for (auto set : connected_sets) {
for (const auto& set : connected_sets) {
int last = *set.cbegin();
std::for_each(std::next(set.cbegin()),
set.cend(),
[&](int node) {
edges.push_back(std::make_pair(last, node));
edges.emplace_back(last, node);
last = node;
max_node_id = std::max(max_node_id, node);
});
Expand All @@ -36,7 +36,7 @@ TEST_CASE("edge_groups_create_sets", "[vpr]") {
// Initialize nodes to [0, 1, ..., max_node_id]
std::iota(nodes.begin(), nodes.end(), 0);

// Create a Mersenne Twister psuedo-random number generator with seed 1
// Create a Mersenne Twister pseudo-random number generator with seed 1
std::mt19937 g(1);

// Run the test many times, the PRNG will give differently shuffled inputs
Expand Down Expand Up @@ -66,12 +66,12 @@ TEST_CASE("edge_groups_create_sets", "[vpr]") {
t_non_configurable_rr_sets sets = groups.output_sets();

// Check for the expected sets
for (auto set : connected_sets) {
for (const auto& set : connected_sets) {
std::set<RRNodeId> random_set;
for (auto elem : set) {
random_set.insert(RRNodeId(random_nodes[elem]));
}
REQUIRE(sets.node_sets.find(random_set) != sets.node_sets.end());
REQUIRE(std::find(sets.node_sets.begin(), sets.node_sets.end(), random_set) != sets.node_sets.end());
}
}
}
Expand Down