1
1
#include " parallel_connection_router.h"
2
2
#include < algorithm>
3
+ #include < tuple>
3
4
#include " router_lookahead.h"
4
5
#include " rr_graph.h"
5
6
6
7
#include " binary_heap.h"
7
8
#include " bucket.h"
8
9
#include " rr_graph_fwd.h"
9
10
10
- // #define IS_DETERMINISTIC
11
+ // #define NON_DETERMINISTIC_PRUNING
11
12
12
13
/* *
13
14
* @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
194
195
return std::make_tuple (true , retry_with_full_bb, out);
195
196
}
196
197
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) {
204
202
// Divide out the astar_fac, then multiply to get determinism
205
203
// This is a correction factor to the forward cost to make the total
206
204
// cost an under-estimate.
@@ -221,15 +219,13 @@ static inline bool deterministic_post_target_prune_node(float new_total_cost,
221
219
// Max function to prevent the heuristic from going negative
222
220
new_expected_cost = std::max (0 .f , new_expected_cost);
223
221
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 )
225
223
return true ;
226
224
// NOTE: we do NOT check for equality here. Equality does not matter for
227
225
// determinism when draining the queues (may just lead to a bit more work).
228
226
return false ;
229
227
}
230
228
231
- #endif // IS_DETERMINISTIC
232
-
233
229
// TODO: Once we have a heap node struct, clean this up!
234
230
static inline bool prune_node (RRNodeId inode,
235
231
float new_total_cost,
@@ -238,41 +234,33 @@ static inline bool prune_node(RRNodeId inode,
238
234
RRNodeId target_node,
239
235
vtr::vector<RRNodeId, t_rr_node_route_inf>& rr_node_route_inf_,
240
236
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
- };
258
237
// Post-target pruning: After the target is reached the first time, should
259
238
// use the heuristic to help drain the queues.
260
239
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))
262
243
return true ;
263
244
}
245
+
246
+ // Backwards Pruning
264
247
// NOTE: When going to the target, we only want to prune on the truth.
265
248
// 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)
267
252
return true ;
268
253
// In the case of a tie, need to be picky about whether to prune or not in
269
254
// order to get determinism.
270
255
// FIXME: This may not be thread safe. If the best node changes while this
271
256
// function is being called, we may have the new_back_cost and best
272
257
// prev_edge's being from different heap nodes!
273
258
// 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.
275
262
// In the case of a true tie, just prune, no need to explore neightbors
263
+ RREdgeId best_prev_edge = route_inf->prev_edge ;
276
264
if (new_prev_edge == best_prev_edge)
277
265
return true ;
278
266
// 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,
285
273
if (!new_prev_edge.is_valid ())
286
274
return false ;
287
275
// 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
+ };
288
282
if (!is_preferred_edge (new_prev_edge, best_prev_edge))
289
283
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.
307
287
return true ;
308
- #endif // IS_DETERMINISTIC
288
+ #endif
289
+ }
290
+
291
+ // If all above passes, do not prune.
309
292
return false ;
310
293
}
311
294
@@ -315,7 +298,7 @@ static inline bool should_not_explore_neighbors(RRNodeId inode,
315
298
RRNodeId target_node,
316
299
vtr::vector<RRNodeId, t_rr_node_route_inf>& rr_node_route_inf_,
317
300
const t_conn_cost_params& params) {
318
- #ifdef IS_DETERMINISTIC
301
+ #ifndef NON_DETERMINISTIC_PRUNING
319
302
// For deterministic pruning, cannot enforce anything on the total cost since
320
303
// traversal order is not gaurenteed. However, since total cost is used as a
321
304
// "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,
324
307
// TODO: Maybe consider having the non-deterministic version do this too.
325
308
if (new_total_cost != rr_node_route_inf_[inode].path_cost )
326
309
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
327
316
// Perform post-target pruning. If this is not done, there is a chance that
328
317
// several duplicates of a node is in the queue that will never reach the
329
318
// target better than what we found and they will explore all of their
330
319
// neighbors which is not good. This is done before obtaining the lock to
331
320
// prevent lock contention where possible.
332
321
if (inode != target_node) {
333
322
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))
345
324
return true ;
346
325
}
347
- #endif // IS_DETERMINISTIC
348
326
return false ;
349
327
}
350
328
0 commit comments