Skip to content

Commit 311c460

Browse files
authored
Merge pull request #1939 from RapidSilicon/reorder_rr_graph_nodes_function_position_change
API reorder_rr_graph_node() created in rr_graph_util.cpp
2 parents 3b7cae7 + 16e3a13 commit 311c460

File tree

6 files changed

+128
-95
lines changed

6 files changed

+128
-95
lines changed

vpr/src/base/vpr_context.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ struct DeviceContext : public Context {
163163
/* A writeable view of routing resource graph to be the ONLY database
164164
* for routing resource graph builder functions.
165165
*/
166-
RRGraphBuilder rr_graph_builder{&rr_nodes};
166+
RRGraphBuilder rr_graph_builder{&rr_nodes, &rr_node_metadata, &rr_edge_metadata};
167167

168168
/* A read-only view of routing resource graph to be the ONLY database
169169
* for client functions: GUI, placer, router, timing analyzer etc.

vpr/src/device/rr_graph_builder.cpp

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
#include "vtr_log.h"
22
#include "rr_graph_builder.h"
3+
#include "vtr_time.h"
4+
#include <queue>
5+
#include <random>
6+
//#include <algorithm>
37

4-
RRGraphBuilder::RRGraphBuilder(t_rr_graph_storage* node_storage)
5-
: node_storage_(*node_storage) {
8+
//#include "globals.h"
9+
10+
RRGraphBuilder::RRGraphBuilder(t_rr_graph_storage* node_storage,
11+
MetadataStorage<int>* rr_node_metadata,
12+
MetadataStorage<std::tuple<int, int, short>>* rr_edge_metadata)
13+
: node_storage_(*node_storage)
14+
, rr_node_metadata_(*rr_node_metadata)
15+
, rr_edge_metadata_(*rr_edge_metadata) {
616
}
717

818
t_rr_graph_storage& RRGraphBuilder::node_storage() {
@@ -50,3 +60,71 @@ void RRGraphBuilder::add_node_to_all_locs(RRNodeId node) {
5060
void RRGraphBuilder::clear() {
5161
node_lookup_.clear();
5262
}
63+
64+
void RRGraphBuilder::reorder_nodes(e_rr_node_reorder_algorithm reorder_rr_graph_nodes_algorithm,
65+
int reorder_rr_graph_nodes_threshold,
66+
int reorder_rr_graph_nodes_seed) {
67+
size_t v_num = node_storage_.size();
68+
if (reorder_rr_graph_nodes_threshold < 0 || v_num < (size_t)reorder_rr_graph_nodes_threshold) return;
69+
vtr::ScopedStartFinishTimer timer("Reordering rr_graph nodes");
70+
vtr::vector<RRNodeId, RRNodeId> src_order(v_num); // new id -> old id
71+
size_t cur_idx = 0;
72+
for (RRNodeId& n : src_order) { // Initialize to [0, 1, 2 ...]
73+
n = RRNodeId(cur_idx++);
74+
}
75+
76+
// This method works well. The intution is that highly connected nodes are enumerated first (together),
77+
// and since there will be a lot of nodes with the same degree, they are then ordered based on some
78+
// distance from the starting node.
79+
if (reorder_rr_graph_nodes_algorithm == DEGREE_BFS) {
80+
vtr::vector<RRNodeId, size_t> bfs_idx(v_num);
81+
vtr::vector<RRNodeId, size_t> degree(v_num);
82+
std::queue<RRNodeId> que;
83+
84+
// Compute both degree (in + out) and an index based on the BFS traversal
85+
cur_idx = 0;
86+
for (size_t i = 0; i < v_num; ++i) {
87+
if (bfs_idx[RRNodeId(i)]) continue;
88+
que.push(RRNodeId(i));
89+
bfs_idx[RRNodeId(i)] = cur_idx++;
90+
while (!que.empty()) {
91+
RRNodeId u = que.front();
92+
que.pop();
93+
degree[u] += node_storage_.num_edges(u);
94+
for (RREdgeId edge = node_storage_.first_edge(u); edge < node_storage_.last_edge(u); edge = RREdgeId(size_t(edge) + 1)) {
95+
RRNodeId v = node_storage_.edge_sink_node(edge);
96+
degree[v]++;
97+
if (bfs_idx[v]) continue;
98+
bfs_idx[v] = cur_idx++;
99+
que.push(v);
100+
}
101+
}
102+
}
103+
104+
// Sort by degree primarily, and BFS order secondarily
105+
sort(src_order.begin(), src_order.end(),
106+
[&](auto a, auto b) -> bool {
107+
auto deg_a = degree[a];
108+
auto deg_b = degree[b];
109+
return deg_a > deg_b || (deg_a == deg_b && bfs_idx[a] < bfs_idx[b]);
110+
});
111+
} else if (reorder_rr_graph_nodes_algorithm == RANDOM_SHUFFLE) {
112+
std::mt19937 g(reorder_rr_graph_nodes_seed);
113+
std::shuffle(src_order.begin(), src_order.end(), g);
114+
}
115+
vtr::vector<RRNodeId, RRNodeId> dest_order(v_num);
116+
cur_idx = 0;
117+
for (auto u : src_order)
118+
dest_order[u] = RRNodeId(cur_idx++);
119+
120+
node_storage_.reorder(dest_order, src_order);
121+
122+
node_lookup().reorder(dest_order);
123+
124+
rr_node_metadata_.remap_keys([&](int node) { return size_t(dest_order[RRNodeId(node)]); });
125+
rr_edge_metadata_.remap_keys([&](std::tuple<int, int, short> edge) {
126+
return std::make_tuple(size_t(dest_order[RRNodeId(std::get<0>(edge))]),
127+
size_t(dest_order[RRNodeId(std::get<1>(edge))]),
128+
std::get<2>(edge));
129+
});
130+
}

vpr/src/device/rr_graph_builder.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@
1515
*/
1616
#include "rr_graph_storage.h"
1717
#include "rr_spatial_lookup.h"
18+
#include "metadata_storage.h"
1819

1920
class RRGraphBuilder {
2021
/* -- Constructors -- */
2122
public:
2223
/* See detailed comments about the data structures in the internal data storage section of this file */
23-
RRGraphBuilder(t_rr_graph_storage* node_storage);
24+
RRGraphBuilder(t_rr_graph_storage* node_storage,
25+
MetadataStorage<int>* rr_node_metadata,
26+
MetadataStorage<std::tuple<int, int, short>>* rr_edge_metadata);
2427

2528
/* Disable copy constructors and copy assignment operator
2629
* This is to avoid accidental copy because it could be an expensive operation considering that the
@@ -58,6 +61,29 @@ class RRGraphBuilder {
5861

5962
/** @brief Clear all the underlying data storage */
6063
void clear();
64+
/** @brief reorder all the nodes
65+
* Reordering the rr-graph nodes may be helpful in
66+
* - Increasing cache locality during routing
67+
* - Improving compile time
68+
* Reorder RRNodeId's using one of these algorithms:
69+
* - DEGREE_BFS: Order by degree primarily, and BFS traversal order secondarily.
70+
* - RANDOM_SHUFFLE: Shuffle using the specified seed. Great for testing.
71+
* The DEGREE_BFS algorithm was selected because it had the best performance of seven
72+
* existing algorithms here: https://github.com/SymbiFlow/vtr-rrgraph-reordering-tool
73+
* It might be worth further research, as the DEGREE_BFS algorithm is simple and
74+
* makes some arbitrary choices, such as the starting node.
75+
* The re-ordering algorithm (DEGREE_BFS) does not speed up the router on most architectures
76+
* vs. using the node ordering created by the rr-graph builder in VPR, so it is off by default.
77+
* The other use of this algorithm is for some unit tests; by changing the order of the nodes
78+
* in the rr-graph before routing we check that no code depends on the rr-graph node order
79+
* Nonetheless, it does improve performance ~7% for the SymbiFlow Xilinx Artix 7 graph.
80+
*
81+
* NOTE: Re-ordering will invalidate any references to rr_graph nodes, so this
82+
* should generally be called before creating such references.
83+
*/
84+
void reorder_nodes(e_rr_node_reorder_algorithm reorder_rr_graph_nodes_algorithm,
85+
int reorder_rr_graph_nodes_threshold,
86+
int reorder_rr_graph_nodes_seed);
6187

6288
/** @brief Set capacity of this node (number of routes that can use it). */
6389
inline void set_node_capacity(RRNodeId id, short new_capacity) {
@@ -208,6 +234,14 @@ class RRGraphBuilder {
208234
t_rr_graph_storage& node_storage_;
209235
/* Fast look-up for rr nodes */
210236
RRSpatialLookup node_lookup_;
237+
238+
/* Metadata is an extra data on rr-nodes and edges, respectively, that is not used by vpr
239+
* but simply passed through the flow so that it can be used by downstream tools.
240+
* The main (perhaps only) current use of this metadata is the fasm tool of symbiflow,
241+
* which needs extra metadata on which programming bits control which switch in order to produce a bitstream.*/
242+
243+
MetadataStorage<int>& rr_node_metadata_;
244+
MetadataStorage<std::tuple<int, int, short>>& rr_edge_metadata_;
211245
};
212246

213247
#endif

vpr/src/route/rr_graph.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "router_lookahead_map.h"
3535
#include "rr_graph_clock.h"
3636
#include "edge_groups.h"
37+
#include "rr_graph_builder.h"
3738

3839
#include "rr_types.h"
3940

@@ -313,7 +314,7 @@ void create_rr_graph(const t_graph_type graph_type,
313314
const int num_directs,
314315
int* Warnings) {
315316
const auto& device_ctx = g_vpr_ctx.device();
316-
317+
auto& mutable_device_ctx = g_vpr_ctx.mutable_device();
317318
if (!det_routing_arch->read_rr_graph_filename.empty()) {
318319
if (device_ctx.read_rr_graph_filename != det_routing_arch->read_rr_graph_filename) {
319320
free_rr_graph();
@@ -326,8 +327,11 @@ void create_rr_graph(const t_graph_type graph_type,
326327
det_routing_arch->read_rr_graph_filename.c_str(),
327328
router_opts.read_rr_edge_metadata,
328329
router_opts.do_check_rr_graph);
329-
330-
reorder_rr_graph_nodes(router_opts);
330+
if (router_opts.reorder_rr_graph_nodes_algorithm != DONT_REORDER) {
331+
mutable_device_ctx.rr_graph_builder.reorder_nodes(router_opts.reorder_rr_graph_nodes_algorithm,
332+
router_opts.reorder_rr_graph_nodes_threshold,
333+
router_opts.reorder_rr_graph_nodes_seed);
334+
}
331335
}
332336
} else {
333337
if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) {
@@ -357,7 +361,11 @@ void create_rr_graph(const t_graph_type graph_type,
357361
directs, num_directs,
358362
&det_routing_arch->wire_to_rr_ipin_switch,
359363
Warnings);
360-
reorder_rr_graph_nodes(router_opts);
364+
if (router_opts.reorder_rr_graph_nodes_algorithm != DONT_REORDER) {
365+
mutable_device_ctx.rr_graph_builder.reorder_nodes(router_opts.reorder_rr_graph_nodes_algorithm,
366+
router_opts.reorder_rr_graph_nodes_threshold,
367+
router_opts.reorder_rr_graph_nodes_seed);
368+
}
361369
}
362370

363371
process_non_config_sets();

vpr/src/route/rr_graph_util.cpp

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -83,91 +83,6 @@ int seg_index_of_sblock(int from_node, int to_node) {
8383
}
8484
}
8585

86-
// Reorder RRNodeId's using one of these algorithms:
87-
// - DONT_REORDER: The identity reordering (does nothing.)
88-
// - DEGREE_BFS: Order by degree primarily, and BFS traversal order secondarily.
89-
// - RANDOM_SHUFFLE: Shuffle using the specified seed. Great for testing.
90-
// The DEGREE_BFS algorithm was selected because it had the best performance of seven
91-
// existing algorithms here: https://github.com/SymbiFlow/vtr-rrgraph-reordering-tool
92-
// It might be worth further research, as the DEGREE_BFS algorithm is simple and
93-
// makes some arbitrary choices, such as the starting node.
94-
// Nonetheless, it does improve performance ~7% for the SymbiFlow Xilinx Artix 7 graph.
95-
//
96-
// NOTE: Re-ordering will invalidate any references to rr_graph nodes, so this
97-
// should generally be called before creating such references.
98-
void reorder_rr_graph_nodes(const t_router_opts& router_opts) {
99-
auto& device_ctx = g_vpr_ctx.mutable_device();
100-
auto& graph = device_ctx.rr_nodes;
101-
auto& rr_graph = device_ctx.rr_graph;
102-
size_t v_num = graph.size();
103-
104-
if (router_opts.reorder_rr_graph_nodes_algorithm == DONT_REORDER) return;
105-
if (router_opts.reorder_rr_graph_nodes_threshold < 0 || v_num < (size_t)router_opts.reorder_rr_graph_nodes_threshold) return;
106-
107-
vtr::ScopedStartFinishTimer timer("Reordering rr_graph nodes");
108-
109-
vtr::vector<RRNodeId, RRNodeId> src_order(v_num); // new id -> old id
110-
size_t cur_idx = 0;
111-
for (RRNodeId& n : src_order) { // Initialize to [0, 1, 2 ...]
112-
n = RRNodeId(cur_idx++);
113-
}
114-
115-
// This method works well. The intution is that highly connected nodes are enumerated first (together),
116-
// and since there will be a lot of nodes with the same degree, they are then ordered based on some
117-
// distance from the starting node.
118-
if (router_opts.reorder_rr_graph_nodes_algorithm == DEGREE_BFS) {
119-
vtr::vector<RRNodeId, size_t> bfs_idx(v_num);
120-
vtr::vector<RRNodeId, size_t> degree(v_num);
121-
std::queue<RRNodeId> que;
122-
123-
// Compute both degree (in + out) and an index based on the BFS traversal
124-
cur_idx = 0;
125-
for (size_t i = 0; i < v_num; ++i) {
126-
if (bfs_idx[RRNodeId(i)]) continue;
127-
que.push(RRNodeId(i));
128-
bfs_idx[RRNodeId(i)] = cur_idx++;
129-
while (!que.empty()) {
130-
RRNodeId u = que.front();
131-
que.pop();
132-
degree[u] += graph.num_edges(u);
133-
for (RREdgeId edge = rr_graph.node_first_edge(u); edge < rr_graph.node_last_edge(u); edge = RREdgeId(size_t(edge) + 1)) {
134-
RRNodeId v = graph.edge_sink_node(edge);
135-
degree[v]++;
136-
if (bfs_idx[v]) continue;
137-
bfs_idx[v] = cur_idx++;
138-
que.push(v);
139-
}
140-
}
141-
}
142-
143-
// Sort by degree primarily, and BFS order secondarily
144-
sort(src_order.begin(), src_order.end(),
145-
[&](auto a, auto b) -> bool {
146-
auto deg_a = degree[a];
147-
auto deg_b = degree[b];
148-
return deg_a > deg_b || (deg_a == deg_b && bfs_idx[a] < bfs_idx[b]);
149-
});
150-
} else if (router_opts.reorder_rr_graph_nodes_algorithm == RANDOM_SHUFFLE) {
151-
std::mt19937 g(router_opts.reorder_rr_graph_nodes_seed);
152-
std::shuffle(src_order.begin(), src_order.end(), g);
153-
}
154-
vtr::vector<RRNodeId, RRNodeId> dest_order(v_num);
155-
cur_idx = 0;
156-
for (auto u : src_order)
157-
dest_order[u] = RRNodeId(cur_idx++);
158-
159-
graph.reorder(dest_order, src_order);
160-
161-
device_ctx.rr_graph_builder.node_lookup().reorder(dest_order);
162-
163-
device_ctx.rr_node_metadata.remap_keys([&](int node) { return size_t(dest_order[RRNodeId(node)]); });
164-
device_ctx.rr_edge_metadata.remap_keys([&](std::tuple<int, int, short> edge) {
165-
return std::make_tuple(size_t(dest_order[RRNodeId(std::get<0>(edge))]),
166-
size_t(dest_order[RRNodeId(std::get<1>(edge))]),
167-
std::get<2>(edge));
168-
});
169-
}
170-
17186
vtr::vector<RRNodeId, std::vector<RREdgeId>> get_fan_in_list() {
17287
auto& rr_nodes = g_vpr_ctx.device().rr_nodes;
17388

vpr/src/route/rr_graph_util.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ int seg_index_of_cblock(t_rr_type from_rr_type, int to_node);
77

88
int seg_index_of_sblock(int from_node, int to_node);
99

10-
void reorder_rr_graph_nodes(const t_router_opts& router_opts);
11-
1210
// This function generates and returns a vector indexed by RRNodeId
1311
// containing a list of fan-in edges for each node.
1412
vtr::vector<RRNodeId, std::vector<RREdgeId>> get_fan_in_list();

0 commit comments

Comments
 (0)