Skip to content

Commit 4e9b58f

Browse files
committed
Build PartitionTree incrementally, tune net-decomposing router
1 parent 2f14a9f commit 4e9b58f

15 files changed

+203
-56
lines changed

vpr/src/route/DecompNetlistRouter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class DecompNetlistRouter : public NetlistRouter {
5757
* \ref route_net for each net, which will handle other global updates.
5858
* \return RouteIterResults for this iteration. */
5959
RouteIterResults route_netlist(int itry, float pres_fac, float worst_neg_slack);
60+
void handle_bb_updated_nets(const std::vector<ParentNetId>& nets);
6061
/** Set RCV enable flag for all routers managed by this netlist router.
6162
* Net decomposition does not work with RCV, so calling this fn with x=true is a fatal error. */
6263
void set_rcv_enabled(bool x);
@@ -68,7 +69,7 @@ class DecompNetlistRouter : public NetlistRouter {
6869
/** Get a bitset with sinks to route before net decomposition */
6970
vtr::dynamic_bitset<> get_decomposition_mask(ParentNetId net_id, const PartitionTreeNode& node);
7071
/** Get a bitset with sinks to route before virtual net decomposition */
71-
vtr::dynamic_bitset<> get_vnet_decomposition_mask(const VirtualNet& vnet, const PartitionTreeNode& node);
72+
vtr::dynamic_bitset<> get_decomposition_mask_vnet(const VirtualNet& vnet, const PartitionTreeNode& node);
7273
/** Decompose and route a regular net. Output the resulting vnets to \p left and \p right.
7374
* \return Success status: true if routing is successful and left and right now contain valid virtual nets: false otherwise. */
7475
bool decompose_and_route_net(ParentNetId net_id, const PartitionTreeNode& node, VirtualNet& left, VirtualNet& right);
@@ -115,6 +116,9 @@ class DecompNetlistRouter : public NetlistRouter {
115116
float _pres_fac;
116117
float _worst_neg_slack;
117118

119+
/** The partition tree */
120+
vtr::optional<PartitionTree> _tree;
121+
118122
/** Sinks to be always sampled for decomposition for each net: [0.._net_list.size()-1]
119123
* (i.e. when routing fails after decomposition for a sink, sample it on next iteration) */
120124
vtr::vector<ParentNetId, vtr::dynamic_bitset<>> _net_known_samples;

vpr/src/route/DecompNetlistRouter.tpp

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/** @file Impls for DecompNetlistRouter */
44

55
#include "DecompNetlistRouter.h"
6+
#include "globals.h"
67
#include "netlist_routers.h"
78
#include "route_net.h"
89
#include "sink_sampling.h"
@@ -21,25 +22,43 @@ inline RouteIterResults DecompNetlistRouter<HeapType>::route_netlist(int itry, f
2122
_pres_fac = pres_fac;
2223
_worst_neg_slack = worst_neg_slack;
2324

25+
vtr::Timer t;
26+
2427
/* Organize netlist into a PartitionTree.
2528
* Nets in a given level of nodes are guaranteed to not have any overlapping bounding boxes, so they can be routed in parallel. */
26-
PartitionTree tree(_net_list);
29+
if(!_tree){
30+
_tree = PartitionTree(_net_list);
31+
PartitionTreeDebug::log("Iteration " + std::to_string(itry) + ": built partition tree in " + std::to_string(t.elapsed_sec()) + " s");
32+
}
33+
34+
/* Remove all virtual nets: we will create them for each iteration */
35+
_tree->clear_vnets();
2736

2837
/* Put the root node on the task queue, which will add its child nodes when it's finished. Wait until the entire tree gets routed. */
2938
tbb::task_group g;
30-
route_partition_tree_node(g, tree.root());
39+
route_partition_tree_node(g, _tree->root());
3140
g.wait();
41+
PartitionTreeDebug::log("Routing all nets took " + std::to_string(t.elapsed_sec()) + " s");
3242

3343
/* Combine results from threads */
3444
RouteIterResults out;
3545
for (auto& results : _results_th) {
3646
out.stats.combine(results.stats);
3747
out.rerouted_nets.insert(out.rerouted_nets.end(), results.rerouted_nets.begin(), results.rerouted_nets.end());
48+
out.bb_updated_nets.insert(out.bb_updated_nets.end(), results.bb_updated_nets.begin(), results.bb_updated_nets.end());
3849
out.is_routable &= results.is_routable;
3950
}
51+
4052
return out;
4153
}
4254

55+
/* TODO: Handle this in route_netlist */
56+
template<typename HeapType>
57+
void DecompNetlistRouter<HeapType>::handle_bb_updated_nets(const std::vector<ParentNetId>& nets) {
58+
VTR_ASSERT(_tree);
59+
_tree->update_nets(nets);
60+
}
61+
4362
template<typename HeapType>
4463
void DecompNetlistRouter<HeapType>::set_rcv_enabled(bool x) {
4564
if (x)
@@ -120,6 +139,9 @@ inline bool should_decompose_vnet(const VirtualNet& vnet, const PartitionTreeNod
120139
template<typename HeapType>
121140
void DecompNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group& g, PartitionTreeNode& node) {
122141
auto& route_ctx = g_vpr_ctx.mutable_routing();
142+
vtr::Timer t;
143+
144+
std::vector<ParentNetId> nets(node.nets.begin(), node.nets.end());
123145

124146
/* Sort so that nets with the most sinks are routed first.
125147
* We want to interleave virtual nets with regular ones, so sort an "index vector"
@@ -129,15 +151,14 @@ void DecompNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group& g
129151
std::vector<size_t> order(node.nets.size() + node.vnets.size());
130152
std::iota(order.begin(), order.end(), 0);
131153
std::stable_sort(order.begin(), order.end(), [&](size_t i, size_t j) -> bool {
132-
ParentNetId id1 = i < node.nets.size() ? node.nets[i] : node.vnets[i - node.nets.size()].net_id;
133-
ParentNetId id2 = j < node.nets.size() ? node.nets[j] : node.vnets[j - node.nets.size()].net_id;
154+
ParentNetId id1 = i < node.nets.size() ? nets[i] : node.vnets[i - nets.size()].net_id;
155+
ParentNetId id2 = j < node.nets.size() ? nets[j] : node.vnets[j - nets.size()].net_id;
134156
return _net_list.net_sinks(id1).size() > _net_list.net_sinks(id2).size();
135157
});
136158

137-
vtr::Timer t;
138159
for (size_t i : order) {
139-
if (i < node.nets.size()) { /* Regular net (not decomposed) */
140-
ParentNetId net_id = node.nets[i];
160+
if (i < nets.size()) { /* Regular net (not decomposed) */
161+
ParentNetId net_id = nets[i];
141162
if (!should_route_net(_net_list, net_id, _connections_inf, _budgeting_inf, _worst_neg_slack, true))
142163
continue;
143164
/* Setup the net (reset or prune) only once here in the flow. Then all calls to route_net turn off auto-setup */
@@ -188,6 +209,7 @@ void DecompNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group& g
188209
if (flags.retry_with_full_bb) {
189210
/* ConnectionRouter thinks we should grow the BB. Do that and leave this net unrouted for now */
190211
route_ctx.route_bb[net_id] = full_device_bb();
212+
_results_th.local().bb_updated_nets.push_back(net_id);
191213
/* Disable decomposition for nets like this: they're already problematic */
192214
_is_decomp_disabled[net_id] = true;
193215
continue;
@@ -206,7 +228,7 @@ void DecompNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group& g
206228
continue;
207229
}
208230
}
209-
/* Route the full vnet. Again we don't care about the flags, they should be handled by the regular path */
231+
/* Route the full vnet. We don't care about the flags, they should be handled by the regular path */
210232
auto sink_mask = get_vnet_sink_mask(vnet);
211233
route_net(
212234
_routers_th.local(),
@@ -277,7 +299,7 @@ inline void make_vnet_pair(ParentNetId net_id, const t_bb& bb, Axis cutline_axis
277299

278300
template<typename HeapType>
279301
bool DecompNetlistRouter<HeapType>::decompose_and_route_net(ParentNetId net_id, const PartitionTreeNode& node, VirtualNet& left, VirtualNet& right) {
280-
auto& route_ctx = g_vpr_ctx.routing();
302+
auto& route_ctx = g_vpr_ctx.mutable_routing();
281303
auto& net_bb = route_ctx.route_bb[net_id];
282304

283305
/* Sample enough sinks to provide branch-off points to the virtual nets we create */
@@ -382,7 +404,7 @@ inline std::string describe_vnet(const VirtualNet& vnet) {
382404
template<typename HeapType>
383405
bool DecompNetlistRouter<HeapType>::decompose_and_route_vnet(VirtualNet& vnet, const PartitionTreeNode& node, VirtualNet& left, VirtualNet& right) {
384406
/* Sample enough sinks to provide branch-off points to the virtual nets we create */
385-
auto sink_mask = get_vnet_decomposition_mask(vnet, node);
407+
auto sink_mask = get_decomposition_mask_vnet(vnet, node);
386408

387409
/* Route the *parent* net with the given mask: only the sinks we ask for will be routed */
388410
auto flags = route_net(
@@ -499,6 +521,7 @@ inline bool get_reduction_mask(ParentNetId net_id, Axis cutline_axis, int cutlin
499521
template<typename HeapType>
500522
vtr::dynamic_bitset<> DecompNetlistRouter<HeapType>::get_decomposition_mask(ParentNetId net_id, const PartitionTreeNode& node) {
501523
const auto& route_ctx = g_vpr_ctx.routing();
524+
502525
const RouteTree& tree = route_ctx.route_trees[net_id].value();
503526
size_t num_sinks = tree.num_sinks();
504527

@@ -512,6 +535,7 @@ vtr::dynamic_bitset<> DecompNetlistRouter<HeapType>::get_decomposition_mask(Pare
512535
bool is_reduced = get_reduction_mask(net_id, node.cutline_axis, node.cutline_pos, out);
513536

514537
bool source_on_cutline = is_close_to_cutline(tree.root().inode, node.cutline_axis, node.cutline_pos, 1);
538+
515539
if (!is_reduced || source_on_cutline)
516540
convex_hull_downsample(net_id, route_ctx.route_bb[net_id], out);
517541

@@ -638,7 +662,7 @@ inline bool get_reduction_mask_vnet_with_source(const VirtualNet& vnet, Axis cut
638662
}
639663

640664
template<typename HeapType>
641-
vtr::dynamic_bitset<> DecompNetlistRouter<HeapType>::get_vnet_decomposition_mask(const VirtualNet& vnet, const PartitionTreeNode& node) {
665+
vtr::dynamic_bitset<> DecompNetlistRouter<HeapType>::get_decomposition_mask_vnet(const VirtualNet& vnet, const PartitionTreeNode& node) {
642666
const auto& route_ctx = g_vpr_ctx.routing();
643667
const RouteTree& tree = route_ctx.route_trees[vnet.net_id].value();
644668
int num_sinks = tree.num_sinks();
@@ -650,10 +674,11 @@ vtr::dynamic_bitset<> DecompNetlistRouter<HeapType>::get_vnet_decomposition_mask
650674
* sinks in the small side and unblock. Add convex hull since we are in a vnet which
651675
* may not have a source at all */
652676
if (inside_bb(tree.root().inode, vnet.clipped_bb)) { /* We have source, no need to sample after reduction in most cases */
653-
bool is_reduced = get_reduction_mask_vnet_with_source(vnet, node.cutline_axis, node.cutline_pos, out);
677+
bool is_reduced = get_reduction_mask_vnet_with_source(vnet, node.cutline_axis, node.cutline_pos, out);
654678
bool source_on_cutline = is_close_to_cutline(tree.root().inode, node.cutline_axis, node.cutline_pos, 1);
655-
if (!is_reduced || source_on_cutline)
679+
if (!is_reduced || source_on_cutline){
656680
convex_hull_downsample(vnet.net_id, vnet.clipped_bb, out);
681+
}
657682
} else {
658683
int reduced_sides = get_reduction_mask_vnet_no_source(vnet, node.cutline_axis, node.cutline_pos, out);
659684
if (reduced_sides < 2) {
@@ -666,9 +691,11 @@ vtr::dynamic_bitset<> DecompNetlistRouter<HeapType>::get_vnet_decomposition_mask
666691
/* Sample if a sink is too close to the cutline (and unreached).
667692
* Those sinks are likely to fail routing */
668693
for (size_t isink : isinks) {
694+
RRNodeId rr_sink = route_ctx.net_rr_terminals[vnet.net_id][isink];
695+
if (!inside_bb(rr_sink, vnet.clipped_bb))
696+
continue;
669697
if (is_isink_reached.get(isink))
670698
continue;
671-
RRNodeId rr_sink = route_ctx.net_rr_terminals[vnet.net_id][isink];
672699
if (is_close_to_cutline(rr_sink, node.cutline_axis, node.cutline_pos, 1)) {
673700
out.set(isink, true);
674701
continue;

vpr/src/route/ParallelNetlistRouter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*
1111
* [0]: F. Koşar, "A net-decomposing parallel FPGA router", MS thesis, UofT ECE, 2023 */
1212
#include "netlist_routers.h"
13+
#include "vtr_optional.h"
1314

1415
#include <tbb/task_group.h>
1516

@@ -52,6 +53,7 @@ class ParallelNetlistRouter : public NetlistRouter {
5253
* \ref route_net for each net, which will handle other global updates.
5354
* \return RouteIterResults for this iteration. */
5455
RouteIterResults route_netlist(int itry, float pres_fac, float worst_neg_slack);
56+
void handle_bb_updated_nets(const std::vector<ParentNetId>& nets);
5557
void set_rcv_enabled(bool x);
5658
void set_timing_info(std::shared_ptr<SetupHoldTimingInfo> timing_info);
5759

@@ -95,6 +97,9 @@ class ParallelNetlistRouter : public NetlistRouter {
9597
int _itry;
9698
float _pres_fac;
9799
float _worst_neg_slack;
100+
101+
/** The partition tree */
102+
vtr::optional<PartitionTree> _tree;
98103
};
99104

100105
#include "ParallelNetlistRouter.tpp"

vpr/src/route/ParallelNetlistRouter.tpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
/** @file Impls for ParallelNetlistRouter */
44

5+
#include <string>
56
#include "netlist_routers.h"
67
#include "route_net.h"
78
#include "vtr_time.h"
@@ -20,18 +21,24 @@ inline RouteIterResults ParallelNetlistRouter<HeapType>::route_netlist(int itry,
2021

2122
/* Organize netlist into a PartitionTree.
2223
* Nets in a given level of nodes are guaranteed to not have any overlapping bounding boxes, so they can be routed in parallel. */
23-
PartitionTree tree(_net_list);
24+
vtr::Timer t;
25+
if(!_tree){
26+
_tree = PartitionTree(_net_list);
27+
PartitionTreeDebug::log("Iteration " + std::to_string(itry) + ": built partition tree in " + std::to_string(t.elapsed_sec()) + " s");
28+
}
2429

2530
/* Put the root node on the task queue, which will add its child nodes when it's finished. Wait until the entire tree gets routed. */
2631
tbb::task_group g;
27-
route_partition_tree_node(g, tree.root());
32+
route_partition_tree_node(g, _tree->root());
2833
g.wait();
34+
PartitionTreeDebug::log("Routing all nets took " + std::to_string(t.elapsed_sec()) + " s");
2935

3036
/* Combine results from threads */
3137
RouteIterResults out;
3238
for (auto& results : _results_th) {
3339
out.stats.combine(results.stats);
3440
out.rerouted_nets.insert(out.rerouted_nets.end(), results.rerouted_nets.begin(), results.rerouted_nets.end());
41+
out.bb_updated_nets.insert(out.bb_updated_nets.end(), results.bb_updated_nets.begin(), results.bb_updated_nets.end());
3542
out.is_routable &= results.is_routable;
3643
}
3744
return out;
@@ -41,13 +48,15 @@ template<typename HeapType>
4148
void ParallelNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group& g, PartitionTreeNode& node) {
4249
auto& route_ctx = g_vpr_ctx.mutable_routing();
4350

51+
std::vector<ParentNetId> nets(node.nets.begin(), node.nets.end());
52+
4453
/* Sort so net with most sinks is routed first. */
45-
std::stable_sort(node.nets.begin(), node.nets.end(), [&](ParentNetId id1, ParentNetId id2) -> bool {
54+
std::stable_sort(nets.begin(), nets.end(), [&](ParentNetId id1, ParentNetId id2) -> bool {
4655
return _net_list.net_sinks(id1).size() > _net_list.net_sinks(id2).size();
4756
});
4857

4958
vtr::Timer t;
50-
for (auto net_id : node.nets) {
59+
for (auto net_id : nets) {
5160
auto flags = route_net(
5261
_routers_th.local(),
5362
_net_list,
@@ -76,13 +85,18 @@ void ParallelNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group&
7685
if (flags.retry_with_full_bb) {
7786
/* ConnectionRouter thinks we should grow the BB. Do that and leave this net unrouted for now */
7887
route_ctx.route_bb[net_id] = full_device_bb();
88+
_results_th.local().bb_updated_nets.push_back(net_id);
7989
continue;
8090
}
8191
if (flags.was_rerouted) {
8292
_results_th.local().rerouted_nets.push_back(net_id);
8393
}
8494
}
85-
PartitionTreeDebug::log("Node with " + std::to_string(node.nets.size()) + " nets routed in " + std::to_string(t.elapsed_sec()) + " s");
95+
96+
PartitionTreeDebug::log("Node with " + std::to_string(node.nets.size())
97+
+ " nets and " + std::to_string(node.vnets.size())
98+
+ " virtual nets routed in " + std::to_string(t.elapsed_sec())
99+
+ " s");
86100

87101
/* This node is finished: add left & right branches to the task queue */
88102
if (node.left && node.right) {
@@ -97,6 +111,13 @@ void ParallelNetlistRouter<HeapType>::route_partition_tree_node(tbb::task_group&
97111
}
98112
}
99113

114+
/* TODO: Handle this in route_netlist */
115+
template<typename HeapType>
116+
void ParallelNetlistRouter<HeapType>::handle_bb_updated_nets(const std::vector<ParentNetId>& nets) {
117+
VTR_ASSERT(_tree);
118+
_tree->update_nets(nets);
119+
}
120+
100121
template<typename HeapType>
101122
void ParallelNetlistRouter<HeapType>::set_rcv_enabled(bool x) {
102123
for (auto& router : _routers_th) {

vpr/src/route/SerialNetlistRouter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class SerialNetlistRouter : public NetlistRouter {
3535
~SerialNetlistRouter() {}
3636

3737
RouteIterResults route_netlist(int itry, float pres_fac, float worst_neg_slack);
38+
void handle_bb_updated_nets(const std::vector<ParentNetId>& nets);
3839
void set_rcv_enabled(bool x);
3940
void set_timing_info(std::shared_ptr<SetupHoldTimingInfo> timing_info);
4041

vpr/src/route/SerialNetlistRouter.tpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44

55
#include "SerialNetlistRouter.h"
66
#include "route_net.h"
7+
#include "vtr_time.h"
78

89
template<typename HeapType>
910
inline RouteIterResults SerialNetlistRouter<HeapType>::route_netlist(int itry, float pres_fac, float worst_neg_slack) {
1011
auto& route_ctx = g_vpr_ctx.mutable_routing();
1112
RouteIterResults out;
1213

14+
vtr::Timer t;
15+
1316
/* Sort so net with most sinks is routed first */
1417
auto sorted_nets = std::vector<ParentNetId>(_net_list.nets().begin(), _net_list.nets().end());
1518
std::stable_sort(sorted_nets.begin(), sorted_nets.end(), [&](ParentNetId id1, ParentNetId id2) -> bool {
@@ -45,7 +48,7 @@ inline RouteIterResults SerialNetlistRouter<HeapType>::route_netlist(int itry, f
4548
}
4649

4750
if (flags.retry_with_full_bb) {
48-
/* Grow the BB and retry this net right away. */
51+
/* Grow the BB and retry this net right away. We don't populate out.bb_updated_nets */
4952
route_ctx.route_bb[net_id] = full_device_bb();
5053
inet--;
5154
continue;
@@ -59,9 +62,15 @@ inline RouteIterResults SerialNetlistRouter<HeapType>::route_netlist(int itry, f
5962
}
6063
}
6164

65+
PartitionTreeDebug::log("Routing all nets took " + std::to_string(t.elapsed_sec()) + " s");
6266
return out;
6367
}
6468

69+
/* TODO: Handle this in route_netlist */
70+
template<typename HeapType>
71+
void SerialNetlistRouter<HeapType>::handle_bb_updated_nets(const std::vector<ParentNetId>& /* nets */) {
72+
}
73+
6574
template<typename HeapType>
6675
void SerialNetlistRouter<HeapType>::set_rcv_enabled(bool x) {
6776
_router.set_rcv_enabled(x);

0 commit comments

Comments
 (0)