Skip to content

Commit 246053d

Browse files
Merge pull request #3203 from AlexPoupakis/deterministic_parallel_router
Deterministic parallel router
2 parents b1394d1 + 56bbd01 commit 246053d

File tree

8 files changed

+258
-2
lines changed

8 files changed

+258
-2
lines changed

doc/src/vpr/command_line_usage.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,6 +1887,9 @@ The following options are only valid when the router is in timing-driven mode (t
18871887

18881888
* ``classic``: The classic VPR lookahead
18891889
* ``map``: A more advanced lookahead which accounts for diverse wire types and their connectivity
1890+
* ``compressed_map``: The algorithm is similar to map lookahead with the exception of sparse sampling of the chip to reduce the run-time to build the router lookahead and also its memory footprint.
1891+
* ``extended_map``: A more advanced and extended lookahead which accounts for a more exhaustive node sampling method.
1892+
* ``simple``: A purely distance-based lookahead loaded from an external file using :option:`--read_router_lookahead`. This lookahead returns a cost estimate for channel nodes by querying a lookup table, while for any other node type it returns zero.
18901893

18911894
**Default:** ``map``
18921895

vpr/src/base/ShowSetup.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,9 @@ static void ShowRouterOpts(const t_router_opts& RouterOpts) {
435435
case e_router_lookahead::EXTENDED_MAP:
436436
VTR_LOG("EXTENDED_MAP\n");
437437
break;
438+
case e_router_lookahead::SIMPLE:
439+
VTR_LOG("SIMPLE\n");
440+
break;
438441
case e_router_lookahead::NO_OP:
439442
VTR_LOG("NO_OP\n");
440443
break;

vpr/src/base/read_options.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,8 @@ struct ParseRouterLookahead {
10701070
conv_value.set_value(e_router_lookahead::COMPRESSED_MAP);
10711071
else if (str == "extended_map")
10721072
conv_value.set_value(e_router_lookahead::EXTENDED_MAP);
1073+
else if (str == "simple")
1074+
conv_value.set_value(e_router_lookahead::SIMPLE);
10731075
else {
10741076
std::stringstream msg;
10751077
msg << "Invalid conversion from '"
@@ -1089,6 +1091,8 @@ struct ParseRouterLookahead {
10891091
conv_value.set_value("map");
10901092
} else if (val == e_router_lookahead::COMPRESSED_MAP) {
10911093
conv_value.set_value("compressed_map");
1094+
} else if (val == e_router_lookahead::SIMPLE) {
1095+
conv_value.set_value("simple");
10921096
} else {
10931097
VTR_ASSERT(val == e_router_lookahead::EXTENDED_MAP);
10941098
conv_value.set_value("extended_map");
@@ -1097,7 +1101,7 @@ struct ParseRouterLookahead {
10971101
}
10981102

10991103
std::vector<std::string> default_choices() {
1100-
return {"classic", "map", "compressed_map", "extended_map"};
1104+
return {"classic", "map", "compressed_map", "extended_map", "simple"};
11011105
}
11021106
};
11031107

@@ -2970,6 +2974,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
29702974
" to reduce the run-time to build the router lookahead and also its memory footprint\n"
29712975
" * extended_map: A more advanced and extended lookahead which accounts for a more\n"
29722976
" exhaustive node sampling method\n"
2977+
" * simple: A purely distance-based lookahead loaded from an external file\n"
29732978
"\n"
29742979
" The extended map differs from the map lookahead in the lookahead computation.\n"
29752980
" It is better suited for architectures that have specialized routing for specific\n"

vpr/src/base/vpr_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ enum class e_router_lookahead {
107107
COMPRESSED_MAP,
108108
///@brief Lookahead with a more extensive node sampling method
109109
EXTENDED_MAP,
110+
///@brief Simple distance-based lookahead
111+
SIMPLE,
110112
///@brief A no-operation lookahead which always returns zero
111113
NO_OP
112114
};

vpr/src/route/parallel_connection_router.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ static inline bool post_target_prune_node(float new_total_cost,
3333
// Max function to prevent the heuristic from going negative
3434
new_expected_cost = std::max(0.f, new_expected_cost);
3535
new_expected_cost *= params.post_target_prune_fac;
36-
if ((new_back_cost + new_expected_cost) > best_back_cost_to_target)
36+
37+
// NOTE: in the check below, the multiplication factor is used to account for floating point errors.
38+
if ((new_back_cost + new_expected_cost) * 0.999f > best_back_cost_to_target)
3739
return true;
3840
// NOTE: we do NOT check for equality here. Equality does not matter for
3941
// determinism when draining the queues (may just lead to a bit more work).

vpr/src/route/router_lookahead/router_lookahead.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "router_lookahead_map.h"
55
#include "router_lookahead_compressed_map.h"
66
#include "router_lookahead_extended_map.h"
7+
#include "router_lookahead_simple.h"
78
#include "vpr_error.h"
89
#include "globals.h"
910

@@ -30,6 +31,8 @@ static std::unique_ptr<RouterLookahead> make_router_lookahead_object(const t_det
3031
return std::make_unique<CompressedMapLookahead>(det_routing_arch, is_flat);
3132
} else if (router_lookahead_type == e_router_lookahead::EXTENDED_MAP) {
3233
return std::make_unique<ExtendedMapLookahead>(is_flat);
34+
} else if (router_lookahead_type == e_router_lookahead::SIMPLE) {
35+
return std::make_unique<SimpleLookahead>();
3336
} else if (router_lookahead_type == e_router_lookahead::NO_OP) {
3437
return std::make_unique<NoOpLookahead>();
3538
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* The router lookahead provides an estimate of the cost from an intermediate node to the target node
3+
* during directed (A*-like) routing.
4+
*
5+
* The lookahead in this file requires an externally loaded lookahead cost map which will be queried
6+
* based only on the distance between the currently explored node and the target sink.
7+
*
8+
* This lookahead can be made admissible if the loaded cost map contains the minimum delay and minimum
9+
* congestion costs per distance.
10+
*/
11+
12+
#include <algorithm>
13+
#include <thread>
14+
#include <unordered_map>
15+
#include <vector>
16+
#include <queue>
17+
#include <fstream>
18+
#include "globals.h"
19+
#include "vtr_time.h"
20+
#include "router_lookahead.h"
21+
#include "router_lookahead_simple.h"
22+
#include "router_lookahead_map_utils.h"
23+
#include "rr_graph.h"
24+
#include "connection_router_interface.h"
25+
#include "arch_util.h"
26+
27+
#ifdef VTR_ENABLE_CAPNPROTO
28+
#include "capnp/serialize.h"
29+
#include "map_lookahead.capnp.h"
30+
#include "ndmatrix_serdes.h"
31+
#include "intra_cluster_serdes.h"
32+
#include "mmap_file.h"
33+
#include "serdes_utils.h"
34+
#endif /* VTR_ENABLE_CAPNPROTO */
35+
36+
/******** File-Scope Variables ********/
37+
38+
//Look-up table from CHANX/CHANY (to SINKs) for various distances
39+
static t_simple_cost_map simple_cost_map;
40+
41+
/******** File-Scope Functions ********/
42+
43+
static util::Cost_Entry get_wire_cost_entry(e_rr_type rr_type,
44+
int seg_index,
45+
int from_layer_num,
46+
int delta_x,
47+
int delta_y,
48+
int to_layer_num);
49+
50+
static void read_router_lookahead(const std::string& file);
51+
static void write_router_lookahead(const std::string& file);
52+
53+
/******** Interface class member function definitions ********/
54+
55+
float SimpleLookahead::get_expected_cost(RRNodeId current_node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const {
56+
// Get the total cost using the combined delay and congestion costs
57+
auto [delay_cost, cong_cost] = get_expected_delay_and_cong(current_node, target_node, params, R_upstream);
58+
return delay_cost + cong_cost;
59+
}
60+
61+
std::pair<float, float> SimpleLookahead::get_expected_delay_and_cong(RRNodeId from_node, RRNodeId to_node, const t_conn_cost_params& params, float /*R_upstream*/) const {
62+
auto& device_ctx = g_vpr_ctx.device();
63+
auto& rr_graph = device_ctx.rr_graph;
64+
65+
float expected_delay_cost = std::numeric_limits<float>::max() / 1e12;
66+
float expected_cong_cost = std::numeric_limits<float>::max() / 1e12;
67+
68+
e_rr_type from_type = rr_graph.node_type(from_node);
69+
util::Cost_Entry cost_entry(0, 0);
70+
if (is_chanxy(from_type) || is_chanz(from_type)) {
71+
int from_layer_num = rr_graph.node_layer(from_node);
72+
int to_layer_num = rr_graph.node_layer(to_node);
73+
74+
auto [delta_x, delta_y] = util::get_xy_deltas(from_node, to_node);
75+
delta_x = abs(delta_x);
76+
delta_y = abs(delta_y);
77+
78+
auto from_cost_index = rr_graph.node_cost_index(from_node);
79+
int from_seg_index = device_ctx.rr_indexed_data[from_cost_index].seg_index;
80+
81+
cost_entry = get_wire_cost_entry(from_type, from_seg_index, from_layer_num, delta_x, delta_y, to_layer_num);
82+
}
83+
84+
if (cost_entry.valid()) {
85+
float expected_delay = cost_entry.delay;
86+
float expected_cong = cost_entry.congestion;
87+
88+
expected_delay_cost = params.criticality * expected_delay;
89+
expected_cong_cost = (1.0 - params.criticality) * expected_cong;
90+
}
91+
92+
return std::make_pair(expected_delay_cost, expected_cong_cost);
93+
}
94+
95+
void SimpleLookahead::read(const std::string& file) {
96+
read_router_lookahead(file);
97+
}
98+
99+
void SimpleLookahead::write(const std::string& file) const {
100+
if (vtr::check_file_name_extension(file, ".csv")) {
101+
std::vector<int> simple_cost_map_size(simple_cost_map.ndims());
102+
for (size_t i = 0; i < simple_cost_map.ndims(); ++i) {
103+
simple_cost_map_size[i] = static_cast<int>(simple_cost_map.dim_size(i));
104+
}
105+
dump_readable_router_lookahead_map(file, simple_cost_map_size, get_wire_cost_entry);
106+
} else {
107+
VTR_ASSERT(vtr::check_file_name_extension(file, ".capnp") || vtr::check_file_name_extension(file, ".bin"));
108+
write_router_lookahead(file);
109+
}
110+
}
111+
112+
/******** Function Definitions ********/
113+
114+
static util::Cost_Entry get_wire_cost_entry(e_rr_type rr_type, int seg_index, int from_layer_num, int delta_x, int delta_y, int to_layer_num) {
115+
VTR_ASSERT_SAFE(rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY);
116+
VTR_ASSERT_SAFE(from_layer_num < static_cast<int>(simple_cost_map.dim_size(0)));
117+
VTR_ASSERT_SAFE(to_layer_num < static_cast<int>(simple_cost_map.dim_size(1)));
118+
VTR_ASSERT_SAFE(seg_index < static_cast<int>(simple_cost_map.dim_size(3)));
119+
VTR_ASSERT_SAFE(delta_x < static_cast<int>(simple_cost_map.dim_size(4)));
120+
VTR_ASSERT_SAFE(delta_y < static_cast<int>(simple_cost_map.dim_size(5)));
121+
122+
int chan_index = 0;
123+
if (rr_type == e_rr_type::CHANY) {
124+
chan_index = 1;
125+
}
126+
127+
return simple_cost_map[from_layer_num][to_layer_num][chan_index][seg_index][delta_x][delta_y];
128+
}
129+
130+
//
131+
// When writing capnp targetted serialization, always allow compilation when
132+
// VTR_ENABLE_CAPNPROTO=OFF. Generally this means throwing an exception
133+
// instead.
134+
//
135+
#ifndef VTR_ENABLE_CAPNPROTO
136+
137+
#define DISABLE_ERROR \
138+
"is disabled because VTR_ENABLE_CAPNPROTO=OFF." \
139+
"Re-compile with CMake option VTR_ENABLE_CAPNPROTO=ON to enable."
140+
141+
void read_router_lookahead(const std::string& /*file*/) {
142+
VPR_THROW(VPR_ERROR_PLACE, "SimpleLookahead::read_router_lookahead " DISABLE_ERROR);
143+
}
144+
145+
void write_router_lookahead(const std::string& /*file*/) {
146+
VPR_THROW(VPR_ERROR_PLACE, "SimpleLookahead::write_router_lookahead " DISABLE_ERROR);
147+
}
148+
149+
#else /* VTR_ENABLE_CAPNPROTO */
150+
151+
static void ToCostEntry(util::Cost_Entry* out, const VprMapCostEntry::Reader& in) {
152+
out->delay = in.getDelay();
153+
out->congestion = in.getCongestion();
154+
}
155+
156+
static void FromCostEntry(VprMapCostEntry::Builder* out, const util::Cost_Entry& in) {
157+
out->setDelay(in.delay);
158+
out->setCongestion(in.congestion);
159+
}
160+
161+
void read_router_lookahead(const std::string& file) {
162+
vtr::ScopedStartFinishTimer timer("Loading router wire lookahead map");
163+
MmapFile f(file);
164+
165+
/* Increase reader limit to 1G words to allow for large files. */
166+
::capnp::ReaderOptions opts = default_large_capnp_opts();
167+
::capnp::FlatArrayMessageReader reader(f.getData(), opts);
168+
169+
auto map = reader.getRoot<VprMapLookahead>();
170+
171+
ToNdMatrix<6, VprMapCostEntry, util::Cost_Entry>(&simple_cost_map, map.getCostMap(), ToCostEntry);
172+
}
173+
174+
void write_router_lookahead(const std::string& file) {
175+
::capnp::MallocMessageBuilder builder;
176+
177+
auto map = builder.initRoot<VprMapLookahead>();
178+
179+
auto cost_map = map.initCostMap();
180+
FromNdMatrix<6, VprMapCostEntry, util::Cost_Entry>(&cost_map, simple_cost_map, FromCostEntry);
181+
182+
writeMessageToFile(file, &builder);
183+
}
184+
185+
#endif
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
#include "vtr_ndmatrix.h"
4+
#include "router_lookahead.h"
5+
#include "router_lookahead_map_utils.h"
6+
7+
/**
8+
* @brief A lookahead that can only read a cost map from a file and query it based on distance.
9+
*
10+
* SimpleLookahead cannot compute a cost map, instead it can only read a single cost map from an external file.
11+
* This cost map is similar to that of MapLookahead, and it only refers to channel segments. There is no additional
12+
* cost map for sources/opins or intra-cluster estimates.
13+
*/
14+
class SimpleLookahead : public RouterLookahead {
15+
protected:
16+
float get_expected_cost(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
17+
std::pair<float, float> get_expected_delay_and_cong(RRNodeId from_node, RRNodeId to_node, const t_conn_cost_params& params, float R_upstream) const override;
18+
19+
void compute(const std::vector<t_segment_inf>& /*segment_inf*/) override {
20+
VPR_THROW(VPR_ERROR_ROUTE, "SimpleLookahead::compute unsupported, try to load lookahead from a file.");
21+
}
22+
23+
void compute_intra_tile() override {
24+
VPR_THROW(VPR_ERROR_ROUTE, "SimpleLookahead::compute_intra_tile unimplemented");
25+
}
26+
27+
void read(const std::string& file) override;
28+
29+
void read_intra_cluster(const std::string& /*file*/) override {
30+
VPR_THROW(VPR_ERROR_ROUTE, "SimpleLookahead::read_intra_cluster unimplemented");
31+
}
32+
33+
void write(const std::string& file) const override;
34+
35+
void write_intra_cluster(const std::string& /*file*/) const override {
36+
VPR_THROW(VPR_ERROR_ROUTE, "SimpleLookahead::write_intra_cluster unimplemented");
37+
}
38+
39+
float get_opin_distance_min_delay(int /*physical_tile_idx*/, int /*from_layer*/, int /*to_layer*/, int /*dx*/, int /*dy*/) const override {
40+
return -1;
41+
}
42+
};
43+
44+
/* provides delay/congestion estimates to travel specified distances
45+
* in the x/y direction */
46+
// This is a 6D array storing the cost to travel from a node of type CHANX/CHANY to a point that is dx, dy further, and is on the "layer_num" layer.
47+
// To store this information, the first index is the layer number that the node under consideration is on, the second index is the layer number of the target node, the third index represents the type of channel (X/Y)
48+
// that the node under consideration belongs to, the forth is the segment type (specified in the architecture file under the "segmentlist" tag), the fourth is the
49+
// target "layer_num" mentioned above, the fifth is dx, and the last one is dy.
50+
typedef vtr::NdMatrix<util::Cost_Entry, 6> t_simple_cost_map; //[0..num_layers][0..num_layers][0..1][[0..num_seg_types-1][0..device_ctx.grid.width()-1][0..device_ctx.grid.height()-1]
51+
//[0..1] entry distinguish between CHANX/CHANY start nodes respectively
52+
// The first index is the layer number that the node under consideration is on, and the second index
53+
// is the layer number that the target node is on.

0 commit comments

Comments
 (0)