-
Notifications
You must be signed in to change notification settings - Fork 416
API reorder_rr_graph_node() created in rr_graph_util.cpp #1939
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
Changes from 2 commits
0cfed30
17f164c
0d9b9dd
96f351b
d2a3d1a
72a35cb
8229337
16e3a13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
#include "vtr_log.h" | ||
#include "rr_graph_builder.h" | ||
#include "vtr_time.h" | ||
#include <queue> | ||
#include "globals.h" | ||
|
||
RRGraphBuilder::RRGraphBuilder(t_rr_graph_storage* node_storage) | ||
: node_storage_(*node_storage) { | ||
|
@@ -50,3 +53,75 @@ void RRGraphBuilder::add_node_to_all_locs(RRNodeId node) { | |
void RRGraphBuilder::clear() { | ||
node_lookup_.clear(); | ||
} | ||
|
||
void RRGraphBuilder::reorder_rr_graph_nodes(const t_router_opts& router_opts) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
auto& device_ctx = g_vpr_ctx.mutable_device(); | ||
auto& rr_graph = device_ctx.rr_graph; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now |
||
size_t v_num = node_storage_.size(); | ||
|
||
if (router_opts.reorder_rr_graph_nodes_algorithm == DONT_REORDER) return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This if-condition can be done outside this API. In client functions, we can call the API in this way:
|
||
if (router_opts.reorder_rr_graph_nodes_threshold < 0 || v_num < (size_t)router_opts.reorder_rr_graph_nodes_threshold) return; | ||
|
||
vtr::ScopedStartFinishTimer timer("Reordering rr_graph nodes"); | ||
|
||
vtr::vector<RRNodeId, RRNodeId> src_order(v_num); // new id -> old id | ||
size_t cur_idx = 0; | ||
for (RRNodeId& n : src_order) { // Initialize to [0, 1, 2 ...] | ||
n = RRNodeId(cur_idx++); | ||
} | ||
|
||
// This method works well. The intution is that highly connected nodes are enumerated first (together), | ||
// and since there will be a lot of nodes with the same degree, they are then ordered based on some | ||
// distance from the starting node. | ||
if (router_opts.reorder_rr_graph_nodes_algorithm == DEGREE_BFS) { | ||
vtr::vector<RRNodeId, size_t> bfs_idx(v_num); | ||
vtr::vector<RRNodeId, size_t> degree(v_num); | ||
std::queue<RRNodeId> que; | ||
|
||
// Compute both degree (in + out) and an index based on the BFS traversal | ||
cur_idx = 0; | ||
for (size_t i = 0; i < v_num; ++i) { | ||
if (bfs_idx[RRNodeId(i)]) continue; | ||
que.push(RRNodeId(i)); | ||
bfs_idx[RRNodeId(i)] = cur_idx++; | ||
while (!que.empty()) { | ||
RRNodeId u = que.front(); | ||
que.pop(); | ||
degree[u] += node_storage_.num_edges(u); | ||
for (RREdgeId edge = rr_graph.node_first_edge(u); edge < rr_graph.node_last_edge(u); edge = RREdgeId(size_t(edge) + 1)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
RRNodeId v = node_storage_.edge_sink_node(edge); | ||
degree[v]++; | ||
if (bfs_idx[v]) continue; | ||
bfs_idx[v] = cur_idx++; | ||
que.push(v); | ||
} | ||
} | ||
} | ||
|
||
// Sort by degree primarily, and BFS order secondarily | ||
sort(src_order.begin(), src_order.end(), | ||
[&](auto a, auto b) -> bool { | ||
auto deg_a = degree[a]; | ||
auto deg_b = degree[b]; | ||
return deg_a > deg_b || (deg_a == deg_b && bfs_idx[a] < bfs_idx[b]); | ||
}); | ||
} else if (router_opts.reorder_rr_graph_nodes_algorithm == RANDOM_SHUFFLE) { | ||
std::mt19937 g(router_opts.reorder_rr_graph_nodes_seed); | ||
std::shuffle(src_order.begin(), src_order.end(), g); | ||
} | ||
vtr::vector<RRNodeId, RRNodeId> dest_order(v_num); | ||
cur_idx = 0; | ||
for (auto u : src_order) | ||
dest_order[u] = RRNodeId(cur_idx++); | ||
|
||
node_storage_.reorder(dest_order, src_order); | ||
|
||
node_lookup().reorder(dest_order); | ||
|
||
device_ctx.rr_node_metadata.remap_keys([&](int node) { return size_t(dest_order[RRNodeId(node)]); }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can do the reordering node/edge metadata outside the |
||
device_ctx.rr_edge_metadata.remap_keys([&](std::tuple<int, int, short> edge) { | ||
return std::make_tuple(size_t(dest_order[RRNodeId(std::get<0>(edge))]), | ||
size_t(dest_order[RRNodeId(std::get<1>(edge))]), | ||
std::get<2>(edge)); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,20 @@ class RRGraphBuilder { | |
/** @brief Clear all the underlying data storage */ | ||
void clear(); | ||
|
||
// Reorder RRNodeId's using one of these algorithms: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please follow the comment style of other APIs, which are compatible with Doxygen. |
||
// - DONT_REORDER: The identity reordering (does nothing.) | ||
// - DEGREE_BFS: Order by degree primarily, and BFS traversal order secondarily. | ||
// - RANDOM_SHUFFLE: Shuffle using the specified seed. Great for testing. | ||
// The DEGREE_BFS algorithm was selected because it had the best performance of seven | ||
// existing algorithms here: https://github.com/SymbiFlow/vtr-rrgraph-reordering-tool | ||
// It might be worth further research, as the DEGREE_BFS algorithm is simple and | ||
// makes some arbitrary choices, such as the starting node. | ||
// Nonetheless, it does improve performance ~7% for the SymbiFlow Xilinx Artix 7 graph. | ||
// | ||
// NOTE: Re-ordering will invalidate any references to rr_graph nodes, so this | ||
// should generally be called before creating such references. | ||
void reorder_rr_graph_nodes(const t_router_opts& router_opts); | ||
|
||
/** @brief Set capacity of this node (number of routes that can use it). */ | ||
inline void set_node_capacity(RRNodeId id, short new_capacity) { | ||
node_storage_.set_node_capacity(id, new_capacity); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No globals in the rr_graph_builder. The data structure should be self-contained.