3
3
#include " initial_placement.h"
4
4
#include " noc_place_utils.h"
5
5
#include " noc_place_checkpoint.h"
6
+ #include " vtr_math.h"
6
7
7
8
/* *
8
9
* @brief Evaluates whether a NoC router swap should be accepted or not.
@@ -32,7 +33,8 @@ static void place_constrained_noc_router(ClusterBlockId router_blk_id);
32
33
* NoC routers.
33
34
* @param seed Used for shuffling NoC routers.
34
35
*/
35
- static void place_noc_routers_randomly (std::vector<ClusterBlockId>& unfixed_routers, int seed);
36
+ static void place_noc_routers_randomly (std::vector<ClusterBlockId>& unfixed_routers,
37
+ int seed);
36
38
37
39
/* *
38
40
* @brief Runs a simulated annealing optimizer for NoC routers.
@@ -41,6 +43,16 @@ static void place_noc_routers_randomly(std::vector<ClusterBlockId>& unfixed_rout
41
43
*/
42
44
static void noc_routers_anneal (const t_noc_opts& noc_opts);
43
45
46
+ /* *
47
+ * @brief Check whether normalization factors need to be updated.
48
+ *
49
+ * @param costs Most recent NoC cost terms.
50
+ * @param old_costs NoC cost terms from the last time normalization
51
+ * factors were updated.
52
+ */
53
+ static bool is_renormalization_needed (const t_placer_costs& costs,
54
+ const t_placer_costs& old_costs);
55
+
44
56
static bool accept_noc_swap (double delta_cost, double prob) {
45
57
if (delta_cost <= 0.0 ) {
46
58
return true ;
@@ -58,6 +70,46 @@ static bool accept_noc_swap(double delta_cost, double prob) {
58
70
}
59
71
}
60
72
73
+ static bool is_renormalization_needed (const t_placer_costs& costs,
74
+ const t_placer_costs& old_costs) {
75
+ constexpr double COST_DIFF_TOLERANCE = 0.1 ;
76
+ bool renormalization_needed = false ;
77
+
78
+ // aggregate bandwidth has changed significantly
79
+ renormalization_needed |= !vtr::isclose (costs.noc_cost_terms .aggregate_bandwidth ,
80
+ old_costs.noc_cost_terms .aggregate_bandwidth ,
81
+ COST_DIFF_TOLERANCE,
82
+ 0 .);
83
+
84
+ // latency cost has changed significantly
85
+ renormalization_needed |= !vtr::isclose (costs.noc_cost_terms .latency ,
86
+ old_costs.noc_cost_terms .latency ,
87
+ COST_DIFF_TOLERANCE,
88
+ 0 .);
89
+
90
+ // if both old and new latency overrun costs are too small, ignore their difference
91
+ // Too small latency overrun costs are the result of round-off error
92
+ if (costs.noc_cost_terms .latency_overrun > MIN_EXPECTED_NOC_LATENCY_COST ||
93
+ old_costs.noc_cost_terms .latency_overrun > MIN_EXPECTED_NOC_LATENCY_COST) {
94
+ renormalization_needed |= !vtr::isclose (costs.noc_cost_terms .latency_overrun ,
95
+ old_costs.noc_cost_terms .latency_overrun ,
96
+ COST_DIFF_TOLERANCE,
97
+ 0 .);
98
+ }
99
+
100
+ // if both old and new congestion costs are too small, ignore their difference
101
+ // Too small congestion costs are the result of round-off error
102
+ if (costs.noc_cost_terms .congestion > MIN_EXPECTED_NOC_CONGESTION_COST ||
103
+ old_costs.noc_cost_terms .congestion > MIN_EXPECTED_NOC_CONGESTION_COST) {
104
+ renormalization_needed |= !vtr::isclose (costs.noc_cost_terms .congestion ,
105
+ old_costs.noc_cost_terms .congestion ,
106
+ COST_DIFF_TOLERANCE,
107
+ 0 .);
108
+ }
109
+
110
+ return renormalization_needed;
111
+ }
112
+
61
113
static void place_constrained_noc_router (ClusterBlockId router_blk_id) {
62
114
auto & cluster_ctx = g_vpr_ctx.clustering ();
63
115
const auto & floorplanning_ctx = g_vpr_ctx.floorplanning ();
@@ -156,13 +208,17 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) {
156
208
157
209
// Only NoC related costs are considered
158
210
t_placer_costs costs;
211
+ // NoC costs from the last time normalization factors were updated
212
+ t_placer_costs old_costs;
159
213
160
214
// Initialize NoC-related costs
161
215
costs.noc_cost_terms .aggregate_bandwidth = comp_noc_aggregate_bandwidth_cost ();
162
216
std::tie (costs.noc_cost_terms .latency , costs.noc_cost_terms .latency_overrun ) = comp_noc_latency_cost ();
163
217
costs.noc_cost_terms .congestion = comp_noc_congestion_cost ();
164
218
update_noc_normalization_factors (costs);
165
219
costs.cost = calculate_noc_cost (costs.noc_cost_terms , costs.noc_cost_norm_factors , noc_opts);
220
+ old_costs = costs;
221
+
166
222
167
223
// Maximum distance in each direction that a router can travel in a move
168
224
// It is assumed that NoC routers are organized in a square grid.
@@ -182,6 +238,9 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) {
182
238
const int N_MOVES_PER_ROUTER = 35000 ;
183
239
const int N_MOVES = num_router_clusters * N_MOVES_PER_ROUTER;
184
240
241
+ const int RENORMALIZATION_LIM = 1024 ;
242
+ int renormalization_cnt = 0 ;
243
+
185
244
const double starting_prob = 0.5 ;
186
245
const double prob_step = starting_prob / N_MOVES;
187
246
@@ -201,6 +260,9 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) {
201
260
* Range limit and the probability of accepting swaps with positive delta cost
202
261
* decrease linearly as more swaps are evaluated. Late in the annealing,
203
262
* NoC routers are swapped only with their neighbors as the range limit approaches 1.
263
+ *
264
+ * After each RENORMALIZATION_LIM accepted moves, if NoC cost terms have changed
265
+ * significantly, I update the normalization factors and re-compute the total cost.
204
266
*/
205
267
206
268
// Generate and evaluate router moves
@@ -230,6 +292,17 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) {
230
292
if (costs.cost < checkpoint.get_cost () || !checkpoint.is_valid ()) {
231
293
checkpoint.save_checkpoint (costs.cost );
232
294
}
295
+
296
+ renormalization_cnt++;
297
+ if (renormalization_cnt == RENORMALIZATION_LIM) {
298
+ renormalization_cnt = 0 ;
299
+ if (is_renormalization_needed (costs, old_costs)) {
300
+ update_noc_normalization_factors (costs);
301
+ costs.cost = calculate_noc_cost (costs.noc_cost_terms , costs.noc_cost_norm_factors , noc_opts);
302
+ old_costs = costs;
303
+ }
304
+ }
305
+
233
306
} else { // The proposed move is rejected
234
307
revert_move_blocks (blocks_affected);
235
308
revert_noc_traffic_flow_routes (blocks_affected);
0 commit comments