Skip to content

Commit 55a254a

Browse files
[ParallelRouter] Non-Deterministic Pruning Revisited
1 parent 886da23 commit 55a254a

File tree

1 file changed

+40
-62
lines changed

1 file changed

+40
-62
lines changed

vpr/src/route/parallel_connection_router.cpp

Lines changed: 40 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#include "parallel_connection_router.h"
22
#include <algorithm>
3+
#include <tuple>
34
#include "router_lookahead.h"
45
#include "rr_graph.h"
56

67
#include "binary_heap.h"
78
#include "bucket.h"
89
#include "rr_graph_fwd.h"
910

10-
// #define IS_DETERMINISTIC
11+
// #define NON_DETERMINISTIC_PRUNING
1112

1213
/**
1314
* @brief This function is relevant when the architecture is 3D. If inter-layer connections are only from OPINs (determine by is_inter_layer_opin_connection),
@@ -194,13 +195,10 @@ std::tuple<bool, bool, t_heap> ParallelConnectionRouter::timing_driven_route_con
194195
return std::make_tuple(true, retry_with_full_bb, out);
195196
}
196197

197-
198-
#ifdef IS_DETERMINISTIC
199-
200-
static inline bool deterministic_post_target_prune_node(float new_total_cost,
201-
float new_back_cost,
202-
float best_back_cost_to_target,
203-
const t_conn_cost_params& params) {
198+
static inline bool post_target_prune_node(float new_total_cost,
199+
float new_back_cost,
200+
float best_back_cost_to_target,
201+
const t_conn_cost_params& params) {
204202
// Divide out the astar_fac, then multiply to get determinism
205203
// This is a correction factor to the forward cost to make the total
206204
// cost an under-estimate.
@@ -221,15 +219,13 @@ static inline bool deterministic_post_target_prune_node(float new_total_cost,
221219
// Max function to prevent the heuristic from going negative
222220
new_expected_cost = std::max(0.f, new_expected_cost);
223221
new_expected_cost *= params.post_target_prune_fac;
224-
if (best_back_cost_to_target < (new_back_cost + new_expected_cost))
222+
if ((new_back_cost + new_expected_cost) > best_back_cost_to_target)
225223
return true;
226224
// NOTE: we do NOT check for equality here. Equality does not matter for
227225
// determinism when draining the queues (may just lead to a bit more work).
228226
return false;
229227
}
230228

231-
#endif // IS_DETERMINISTIC
232-
233229
// TODO: Once we have a heap node struct, clean this up!
234230
static inline bool prune_node(RRNodeId inode,
235231
float new_total_cost,
@@ -238,41 +234,33 @@ static inline bool prune_node(RRNodeId inode,
238234
RRNodeId target_node,
239235
vtr::vector<RRNodeId, t_rr_node_route_inf>& rr_node_route_inf_,
240236
const t_conn_cost_params& params) {
241-
// Get the global information INSIDE this function.
242-
t_rr_node_route_inf* route_inf = &rr_node_route_inf_[inode];
243-
float best_total_cost = route_inf->path_cost;
244-
float best_back_cost = route_inf->backward_path_cost;
245-
RREdgeId best_prev_edge = route_inf->prev_edge;
246-
t_rr_node_route_inf* target_route_inf = &rr_node_route_inf_[target_node];
247-
float best_back_cost_to_target = target_route_inf->backward_path_cost;
248-
float best_total_cost_to_target = target_route_inf->path_cost;
249-
#ifdef IS_DETERMINISTIC
250-
(void)best_total_cost;
251-
(void)best_total_cost_to_target;
252-
// Deterministic version prefers a given EdgeID, so a unique path is returned since,
253-
// in the case of a tie, a determinstic path wins.
254-
// Is first preferred over second?
255-
auto is_preferred_edge = [](RREdgeId first, RREdgeId second) {
256-
return first < second;
257-
};
258237
// Post-target pruning: After the target is reached the first time, should
259238
// use the heuristic to help drain the queues.
260239
if (inode != target_node) {
261-
if (deterministic_post_target_prune_node(new_total_cost, new_back_cost, best_back_cost_to_target, params))
240+
t_rr_node_route_inf* target_route_inf = &rr_node_route_inf_[target_node];
241+
float best_back_cost_to_target = target_route_inf->backward_path_cost;
242+
if (post_target_prune_node(new_total_cost, new_back_cost, best_back_cost_to_target, params))
262243
return true;
263244
}
245+
246+
// Backwards Pruning
264247
// NOTE: When going to the target, we only want to prune on the truth.
265248
// The queues handle using the heuristic to explore nodes faster.
266-
if (best_back_cost < new_back_cost)
249+
t_rr_node_route_inf* route_inf = &rr_node_route_inf_[inode];
250+
float best_back_cost = route_inf->backward_path_cost;
251+
if (new_back_cost > best_back_cost)
267252
return true;
268253
// In the case of a tie, need to be picky about whether to prune or not in
269254
// order to get determinism.
270255
// FIXME: This may not be thread safe. If the best node changes while this
271256
// function is being called, we may have the new_back_cost and best
272257
// prev_edge's being from different heap nodes!
273258
// TODO: Move this to within the lock (the rest can stay for performance).
274-
if (best_back_cost == new_back_cost) {
259+
if (new_back_cost == best_back_cost) {
260+
#ifndef NON_DETERMINISTIC_PRUNING
261+
// With deterministic pruning, cannot always prune on ties.
275262
// In the case of a true tie, just prune, no need to explore neightbors
263+
RREdgeId best_prev_edge = route_inf->prev_edge;
276264
if (new_prev_edge == best_prev_edge)
277265
return true;
278266
// When it comes to invalid edge IDs, in the case of a tied back cost,
@@ -285,27 +273,22 @@ static inline bool prune_node(RRNodeId inode,
285273
if (!new_prev_edge.is_valid())
286274
return false;
287275
// Finally, if this node is not coming from a preferred edge, prune
276+
// Deterministic version prefers a given EdgeID, so a unique path is returned since,
277+
// in the case of a tie, a determinstic path wins.
278+
// Is first preferred over second?
279+
auto is_preferred_edge = [](RREdgeId first, RREdgeId second) {
280+
return first < second;
281+
};
288282
if (!is_preferred_edge(new_prev_edge, best_prev_edge))
289283
return true;
290-
}
291-
#else // IS_DETERMINISTIC
292-
(void)new_prev_edge;
293-
(void)best_prev_edge;
294-
(void)params;
295-
// Non-deterministic version does not prefer a given EdgeID, therefore there
296-
// is a race-condition on which path wins in the case of a tie.
297-
// TODO: Confirm if best_total_cost_to_target should be included here.
298-
if (inode != target_node) {
299-
if (best_total_cost_to_target <= new_total_cost)
300-
return true;
301-
if (best_back_cost_to_target <= new_back_cost)
302-
return true;
303-
}
304-
if (best_total_cost <= new_total_cost)
305-
return true;
306-
if (best_back_cost <= new_back_cost)
284+
#else
285+
std::ignore = new_prev_edge;
286+
// When we do not care about determinism, always prune on equality.
307287
return true;
308-
#endif // IS_DETERMINISTIC
288+
#endif
289+
}
290+
291+
// If all above passes, do not prune.
309292
return false;
310293
}
311294

@@ -315,7 +298,7 @@ static inline bool should_not_explore_neighbors(RRNodeId inode,
315298
RRNodeId target_node,
316299
vtr::vector<RRNodeId, t_rr_node_route_inf>& rr_node_route_inf_,
317300
const t_conn_cost_params& params) {
318-
#ifdef IS_DETERMINISTIC
301+
#ifndef NON_DETERMINISTIC_PRUNING
319302
// For deterministic pruning, cannot enforce anything on the total cost since
320303
// traversal order is not gaurenteed. However, since total cost is used as a
321304
// "key" to signify that this node is the last node that was pushed, we can
@@ -324,27 +307,22 @@ static inline bool should_not_explore_neighbors(RRNodeId inode,
324307
// TODO: Maybe consider having the non-deterministic version do this too.
325308
if (new_total_cost != rr_node_route_inf_[inode].path_cost)
326309
return true;
310+
#else
311+
// For non-deterministic pruning, can greadily just ignore nodes with higher
312+
// total cost.
313+
if (new_total_cost > rr_node_route_inf_[inode].path_cost)
314+
return true;
315+
#endif
327316
// Perform post-target pruning. If this is not done, there is a chance that
328317
// several duplicates of a node is in the queue that will never reach the
329318
// target better than what we found and they will explore all of their
330319
// neighbors which is not good. This is done before obtaining the lock to
331320
// prevent lock contention where possible.
332321
if (inode != target_node) {
333322
float best_back_cost_to_target = rr_node_route_inf_[target_node].backward_path_cost;
334-
if (deterministic_post_target_prune_node(new_total_cost, new_back_cost, best_back_cost_to_target, params))
335-
return true;
336-
}
337-
#else // IS_DETERMINISTIC
338-
(void)params;
339-
if (new_total_cost > rr_node_route_inf_[inode].path_cost)
340-
return true;
341-
if (inode != target_node) {
342-
if (new_total_cost > rr_node_route_inf_[target_node].path_cost)
343-
return true;
344-
if (new_back_cost > rr_node_route_inf_[target_node].backward_path_cost)
323+
if (post_target_prune_node(new_total_cost, new_back_cost, best_back_cost_to_target, params))
345324
return true;
346325
}
347-
#endif // IS_DETERMINISTIC
348326
return false;
349327
}
350328

0 commit comments

Comments
 (0)