Skip to content

Commit 0ce9b46

Browse files
committed
Add MixedNetlistRouter
1 parent 6acbdc9 commit 0ce9b46

8 files changed

+306
-30
lines changed

vpr/src/base/ShowSetup.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ static void ShowRouterOpts(const t_router_opts& RouterOpts) {
254254

255255
VTR_LOG("RouterOpts.router_algorithm: ");
256256
switch (RouterOpts.router_algorithm) {
257+
case MIXED:
258+
VTR_LOG("MIXED\n");
259+
break;
257260
case PARALLEL:
258261
VTR_LOG("PARALLEL\n");
259262
break;

vpr/src/base/read_options.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ struct ParseRoutePredictor {
171171
struct ParseRouterAlgorithm {
172172
ConvertedValue<e_router_algorithm> from_str(const std::string& str) {
173173
ConvertedValue<e_router_algorithm> conv_value;
174-
if (str == "parallel")
174+
if (str == "mixed")
175+
conv_value.set_value(MIXED);
176+
else if (str == "parallel")
175177
conv_value.set_value(PARALLEL);
176178
else if (str == "parallel_decomp")
177179
conv_value.set_value(PARALLEL_DECOMP);
@@ -187,8 +189,12 @@ struct ParseRouterAlgorithm {
187189

188190
ConvertedValue<std::string> to_str(e_router_algorithm val) {
189191
ConvertedValue<std::string> conv_value;
190-
if (val == PARALLEL)
192+
if (val == MIXED)
193+
conv_value.set_value("mixed");
194+
else if (val == PARALLEL)
191195
conv_value.set_value("parallel");
196+
else if (val == PARALLEL_DECOMP)
197+
conv_value.set_value("parallel_decomp");
192198
else {
193199
VTR_ASSERT(val == TIMING_DRIVEN);
194200
conv_value.set_value("timing_driven");
@@ -2405,7 +2411,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
24052411
" * parallel: timing_driven with nets in different regions of the chip routed in parallel\n"
24062412
" * parallel_decomp: timing_driven with additional parallelism obtained by decomposing high-fanout nets, possibly reducing quality\n")
24072413
.default_value("timing_driven")
2408-
.choices({"parallel", "parallel_decomp", "timing_driven"})
2414+
.choices({"mixed","parallel", "parallel_decomp", "timing_driven"})
24092415
.show_in(argparse::ShowIn::HELP_ONLY);
24102416

24112417
route_grp.add_argument(args.min_incremental_reroute_fanout, "--min_incremental_reroute_fanout")

vpr/src/base/vpr_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,7 @@ struct t_ap_opts {
11861186
* read_rr_graph_name: stores the file name of the rr graph to be read by vpr */
11871187

11881188
enum e_router_algorithm {
1189+
MIXED,
11891190
PARALLEL,
11901191
PARALLEL_DECOMP,
11911192
TIMING_DRIVEN,

vpr/src/route/MixedNetlistRouter.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#pragma once
2+
3+
/** @file Mixed case for NetlistRouter */
4+
#include "netlist_routers.h"
5+
#include "vtr_optional.h"
6+
#include "vtr_thread_pool.h"
7+
#include <unordered_map>
8+
9+
/* Add cmd line option for this later */
10+
constexpr int MAX_THREADS = 4;
11+
12+
/** Mixed impl for NetlistRouter.
13+
* Holds enough context members to glue together ConnectionRouter and net routing functions,
14+
* such as \ref route_net. Keeps the members in thread-local storage where needed,
15+
* i.e. ConnectionRouters and RouteIterResults-es.
16+
* See \ref route_net. */
17+
template<typename HeapType>
18+
class MixedNetlistRouter : public NetlistRouter {
19+
public:
20+
MixedNetlistRouter(
21+
const Netlist<>& net_list,
22+
const RouterLookahead* router_lookahead,
23+
const t_router_opts& router_opts,
24+
CBRR& connections_inf,
25+
NetPinsMatrix<float>& net_delay,
26+
const ClusteredPinAtomPinsLookup& netlist_pin_lookup,
27+
std::shared_ptr<SetupHoldTimingInfo> timing_info,
28+
NetPinTimingInvalidator* pin_timing_invalidator,
29+
route_budgets& budgeting_inf,
30+
const RoutingPredictor& routing_predictor,
31+
const vtr::vector<ParentNetId, std::vector<std::unordered_map<RRNodeId, int>>>& choking_spots,
32+
bool is_flat)
33+
: _net_list(net_list)
34+
, _router_lookahead(router_lookahead)
35+
, _router_opts(router_opts)
36+
, _connections_inf(connections_inf)
37+
, _net_delay(net_delay)
38+
, _netlist_pin_lookup(netlist_pin_lookup)
39+
, _timing_info(timing_info)
40+
, _pin_timing_invalidator(pin_timing_invalidator)
41+
, _budgeting_inf(budgeting_inf)
42+
, _routing_predictor(routing_predictor)
43+
, _choking_spots(choking_spots)
44+
, _is_flat(is_flat)
45+
, _thread_pool(MAX_THREADS) {}
46+
~MixedNetlistRouter() {}
47+
48+
/** Run a single iteration of netlist routing for this->_net_list. This usually means calling
49+
* \ref route_net for each net, which will handle other global updates.
50+
* \return RouteIterResults for this iteration. */
51+
RouteIterResults route_netlist(int itry, float pres_fac, float worst_neg_slack);
52+
/** Inform the PartitionTree of the nets with updated bounding boxes */
53+
void handle_bb_updated_nets(const std::vector<ParentNetId>& nets);
54+
void set_rcv_enabled(bool x);
55+
void set_timing_info(std::shared_ptr<SetupHoldTimingInfo> timing_info);
56+
57+
private:
58+
/** Route all nets in a PartitionTree node and add its children to the task queue. */
59+
void route_partition_tree_node(PartitionTreeNode& node);
60+
61+
ConnectionRouter<HeapType> _make_router(const RouterLookahead* router_lookahead, bool is_flat) {
62+
auto& device_ctx = g_vpr_ctx.device();
63+
auto& route_ctx = g_vpr_ctx.mutable_routing();
64+
65+
return ConnectionRouter<HeapType>(
66+
device_ctx.grid,
67+
*router_lookahead,
68+
device_ctx.rr_graph.rr_nodes(),
69+
&device_ctx.rr_graph,
70+
device_ctx.rr_rc_data,
71+
device_ctx.rr_graph.rr_switch(),
72+
route_ctx.rr_node_route_inf,
73+
is_flat);
74+
}
75+
76+
/* Context fields. Most of them will be forwarded to route_net (see route_net.tpp) */
77+
const Netlist<>& _net_list;
78+
const RouterLookahead* _router_lookahead;
79+
const t_router_opts& _router_opts;
80+
CBRR& _connections_inf;
81+
NetPinsMatrix<float>& _net_delay;
82+
const ClusteredPinAtomPinsLookup& _netlist_pin_lookup;
83+
std::shared_ptr<SetupHoldTimingInfo> _timing_info;
84+
NetPinTimingInvalidator* _pin_timing_invalidator;
85+
route_budgets& _budgeting_inf;
86+
const RoutingPredictor& _routing_predictor;
87+
const vtr::vector<ParentNetId, std::vector<std::unordered_map<RRNodeId, int>>>& _choking_spots;
88+
bool _is_flat;
89+
90+
/** Cached routing parameters for current iteration (inputs to \see route_netlist()) */
91+
int _itry;
92+
float _pres_fac;
93+
float _worst_neg_slack;
94+
95+
/** The partition tree. Holds the groups of nets for each partition */
96+
vtr::optional<PartitionTree> _tree;
97+
98+
vtr::thread_pool _thread_pool;
99+
100+
/* Thread-local storage */
101+
std::unordered_map<std::thread::id, ConnectionRouter<HeapType>> _routers_th;
102+
std::unordered_map<std::thread::id, RouteIterResults> _results_th;
103+
std::mutex _storage_mutex;
104+
105+
ConnectionRouter<HeapType>& get_thread_router() {
106+
auto id = std::this_thread::get_id();
107+
std::lock_guard<std::mutex> lock(_storage_mutex);
108+
if (!_routers_th.count(id)) {
109+
_routers_th.emplace(id, _make_router(_router_lookahead, _is_flat));
110+
}
111+
return _routers_th.at(id);
112+
}
113+
114+
RouteIterResults& get_thread_results() {
115+
auto id = std::this_thread::get_id();
116+
std::lock_guard<std::mutex> lock(_storage_mutex);
117+
return _results_th[id];
118+
}
119+
};
120+
121+
#include "MixedNetlistRouter.tpp"

vpr/src/route/MixedNetlistRouter.tpp

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#pragma once
2+
3+
/** @file Impls for ParallelNetlistRouter */
4+
5+
#include <string>
6+
#include "netlist_routers.h"
7+
#include "route_net.h"
8+
#include "vtr_time.h"
9+
10+
template<typename HeapType>
11+
inline RouteIterResults MixedNetlistRouter<HeapType>::route_netlist(int itry, float pres_fac, float worst_neg_slack) {
12+
/* Reset results for each thread */
13+
for (auto& [_, results] : _results_th) {
14+
results = RouteIterResults();
15+
}
16+
17+
/* Set the routing parameters: they won't change until the next call and that saves us the trouble of passing them around */
18+
_itry = itry;
19+
_pres_fac = pres_fac;
20+
_worst_neg_slack = worst_neg_slack;
21+
22+
/* Organize netlist into a PartitionTree.
23+
* Nets in a given level of nodes are guaranteed to not have any overlapping bounding boxes, so they can be routed in parallel. */
24+
vtr::Timer timer;
25+
if(!_tree){
26+
_tree = PartitionTree(_net_list);
27+
PartitionTreeDebug::log("Iteration " + std::to_string(itry) + ": built partition tree in " + std::to_string(timer.elapsed_sec()) + " s");
28+
}
29+
30+
/* Push a single route_partition_tree_node task to the thread pool,
31+
* which will recursively schedule the rest of the tree */
32+
_thread_pool.schedule_work([this]() {
33+
route_partition_tree_node(_tree->root());
34+
});
35+
36+
/* Wait for all tasks in the thread pool to complete */
37+
_thread_pool.wait_for_all();
38+
39+
PartitionTreeDebug::log("Routing all nets took " + std::to_string(timer.elapsed_sec()) + " s");
40+
41+
/* Combine results from threads */
42+
RouteIterResults out;
43+
for (auto& [_, results] : _results_th) {
44+
out.stats.combine(results.stats);
45+
out.rerouted_nets.insert(out.rerouted_nets.end(), results.rerouted_nets.begin(), results.rerouted_nets.end());
46+
out.bb_updated_nets.insert(out.bb_updated_nets.end(), results.bb_updated_nets.begin(), results.bb_updated_nets.end());
47+
out.is_routable &= results.is_routable;
48+
}
49+
return out;
50+
}
51+
52+
template<typename HeapType>
53+
void MixedNetlistRouter<HeapType>::route_partition_tree_node(PartitionTreeNode& node) {
54+
auto& route_ctx = g_vpr_ctx.mutable_routing();
55+
56+
/* node.nets is an unordered set, copy into vector to sort */
57+
std::vector<ParentNetId> nets(node.nets.begin(), node.nets.end());
58+
59+
/* Sort so net with most sinks is routed first. */
60+
std::stable_sort(nets.begin(), nets.end(), [&](ParentNetId id1, ParentNetId id2) -> bool {
61+
return _net_list.net_sinks(id1).size() > _net_list.net_sinks(id2).size();
62+
});
63+
64+
vtr::Timer timer;
65+
66+
/* Route all nets in this node serially */
67+
for (auto net_id : nets) {
68+
auto& results = get_thread_results();
69+
auto& router = get_thread_router();
70+
71+
auto flags = route_net(
72+
router,
73+
_net_list,
74+
net_id,
75+
_itry,
76+
_pres_fac,
77+
_router_opts,
78+
_connections_inf,
79+
results.stats,
80+
_net_delay,
81+
_netlist_pin_lookup,
82+
_timing_info.get(),
83+
_pin_timing_invalidator,
84+
_budgeting_inf,
85+
_worst_neg_slack,
86+
_routing_predictor,
87+
_choking_spots[net_id],
88+
_is_flat,
89+
route_ctx.route_bb[net_id]);
90+
91+
if (!flags.success && !flags.retry_with_full_bb) {
92+
/* Disconnected RRG and ConnectionRouter doesn't think growing the BB will work */
93+
results.is_routable = false;
94+
return;
95+
}
96+
if (flags.retry_with_full_bb) {
97+
/* ConnectionRouter thinks we should grow the BB. Do that and leave this net unrouted for now */
98+
route_ctx.route_bb[net_id] = full_device_bb();
99+
results.bb_updated_nets.push_back(net_id);
100+
continue;
101+
}
102+
if (flags.was_rerouted) {
103+
results.rerouted_nets.push_back(net_id);
104+
}
105+
}
106+
107+
PartitionTreeDebug::log("Node with " + std::to_string(node.nets.size())
108+
+ " nets and " + std::to_string(node.vnets.size())
109+
+ " virtual nets routed in " + std::to_string(timer.elapsed_sec())
110+
+ " s");
111+
112+
/* Schedule child nodes as new tasks */
113+
if (node.left && node.right) {
114+
_thread_pool.schedule_work([this, left = node.left.get()]() {
115+
route_partition_tree_node(*left);
116+
});
117+
_thread_pool.schedule_work([this, right = node.right.get()]() {
118+
route_partition_tree_node(*right);
119+
});
120+
} else {
121+
VTR_ASSERT(!node.left && !node.right); // there shouldn't be a node with a single branch
122+
}
123+
}
124+
125+
template<typename HeapType>
126+
void MixedNetlistRouter<HeapType>::handle_bb_updated_nets(const std::vector<ParentNetId>& nets) {
127+
VTR_ASSERT(_tree);
128+
_tree->update_nets(nets);
129+
}
130+
131+
template<typename HeapType>
132+
void MixedNetlistRouter<HeapType>::set_rcv_enabled(bool x) {
133+
for (auto& [_, router] : _routers_th) {
134+
router.set_rcv_enabled(x);
135+
}
136+
}
137+
138+
template<typename HeapType>
139+
void MixedNetlistRouter<HeapType>::set_timing_info(std::shared_ptr<SetupHoldTimingInfo> timing_info) {
140+
_timing_info = timing_info;
141+
}

vpr/src/route/ParallelNetlistRouter.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
* [0]: "Parallel FPGA Routing with On-the-Fly Net Decomposition", FPT'24 */
1212
#include "netlist_routers.h"
1313
#include "vtr_optional.h"
14-
#include "vtr_thread_pool.h"
1514

1615
#include <tbb/task_group.h>
1716

@@ -36,8 +35,7 @@ class ParallelNetlistRouter : public NetlistRouter {
3635
const RoutingPredictor& routing_predictor,
3736
const vtr::vector<ParentNetId, std::vector<std::unordered_map<RRNodeId, int>>>& choking_spots,
3837
bool is_flat)
39-
: _thread_pool(4) // Use 4 cores (for testing)
40-
, _routers_th(_make_router(router_lookahead, is_flat))
38+
: _routers_th(_make_router(router_lookahead, is_flat))
4139
, _net_list(net_list)
4240
, _router_opts(router_opts)
4341
, _connections_inf(connections_inf)
@@ -61,8 +59,8 @@ class ParallelNetlistRouter : public NetlistRouter {
6159
void set_timing_info(std::shared_ptr<SetupHoldTimingInfo> timing_info);
6260

6361
private:
64-
/** Route all nets in a PartitionTree node and add its children to the task queue. */
65-
void route_partition_tree_node(PartitionTreeNode& node);
62+
/** A single task to route nets inside a PartitionTree node and add tasks for its child nodes to task group \p g. */
63+
void route_partition_tree_node(tbb::task_group& g, PartitionTreeNode& node);
6664

6765
ConnectionRouter<HeapType> _make_router(const RouterLookahead* router_lookahead, bool is_flat) {
6866
auto& device_ctx = g_vpr_ctx.device();
@@ -103,8 +101,6 @@ class ParallelNetlistRouter : public NetlistRouter {
103101

104102
/** The partition tree. Holds the groups of nets for each partition */
105103
vtr::optional<PartitionTree> _tree;
106-
107-
vtr::thread_pool _thread_pool;
108104
};
109105

110106
#include "ParallelNetlistRouter.tpp"

0 commit comments

Comments
 (0)