Skip to content

Commit

Permalink
Merge pull request #2839 from verilog-to-routing/temp_faster_check_no…
Browse files Browse the repository at this point in the history
…n_configurable_edges

Faster check_non_configurable_edges
  • Loading branch information
AlexandreSinger authored Jan 28, 2025
2 parents b4f358a + 0e464f7 commit 7829f79
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 47 deletions.
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

0 comments on commit 7829f79

Please sign in to comment.