Skip to content

Commit 0455242

Browse files
Merge pull request #3778 from verilog-to-routing/swap_evaluator
SwapEvaluator class
2 parents f82aa73 + 37fbe55 commit 0455242

4 files changed

Lines changed: 251 additions & 83 deletions

File tree

vpr/src/place/annealer.cpp

Lines changed: 17 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ PlacementAnnealer::PlacementAnnealer(const t_placer_opts& placer_opts,
248248
, move_stats_file_(nullptr, vtr::fclose)
249249
, outer_crit_iter_count_(1)
250250
, blocks_affected_(placer_state.block_locs().size())
251+
, swap_evaluator_(placer_opts, costs, placer_state, net_cost_handler, interposer_cost_handler, delay_model, criticalities)
251252
, quench_started_(false)
252253
, congestion_modeling_started_(false)
253254
, interposer_cong_modeling_started_(false) {
@@ -585,57 +586,14 @@ t_swap_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
585586
} else {
586587
VTR_ASSERT(create_move_outcome == e_create_move::VALID);
587588

588-
/* To make evaluating the move simpler (e.g. calculating changed bounding box),
589-
* we first move the blocks to their new locations (apply the move to
590-
* blk_loc_registry.block_locs) and then compute the change in cost. If the move
591-
* is accepted, the inverse look-up in blk_loc_registry.grid_blocks is updated
592-
* (committing the move). If the move is rejected, the blocks are returned to
593-
* their original positions (reverting blk_loc_registry.block_locs to its original state).
594-
*
595-
* Note that the inverse look-up blk_loc_registry.grid_blocks is only updated after
596-
* move acceptance is determined, so it should not be used when evaluating a move.
597-
*/
598-
599-
// Update the block positions
600-
blk_loc_registry.apply_move_blocks(blocks_affected_);
601-
602-
// Find all the nets affected by this swap and update their wiring costs.
603-
// This cost value doesn't depend on the timing info.
604-
//
605-
// Also find all the pins affected by the swap, and calculates new connection
606-
// delays and timing costs.
607-
net_cost_handler_.find_affected_nets_and_update_costs(delay_model_, criticalities_, blocks_affected_,
608-
cost_terms_delta, timing_delta_c);
609-
610-
const bool update_interposer_costs = interposer_cost_handler_.has_value() && interposer_cost_handler_->has_active_cost_terms();
611-
if (update_interposer_costs) {
612-
const auto [interposer_cost_delta, interposer_cong_cost_delta] = interposer_cost_handler_->total_proposed_cost(net_cost_handler_.affected_nets());
613-
cost_terms_delta.interposer_cost = interposer_cost_delta;
614-
cost_terms_delta.interposer_cong_cost = interposer_cong_cost_delta;
615-
}
589+
// Apply the move to block_locs and compute the resulting cost deltas.
590+
t_swap_cost_deltas deltas = swap_evaluator_.apply_and_evaluate(blocks_affected_, place_algorithm);
591+
cost_terms_delta = deltas.cost_terms_delta;
592+
timing_delta_c = deltas.timing_delta_c;
593+
delta_c = deltas.delta_c;
594+
const bool update_interposer_costs = deltas.update_interposer_costs;
616595

617-
if (place_algorithm == e_place_algorithm::CRITICALITY_TIMING_PLACE) {
618-
/* Take delta_c as a combination of timing and wiring cost. In
619-
* addition to `timing_tradeoff`, we normalize the cost values.
620-
* CRITICALITY_TIMING_PLACE algorithm works with somewhat stale
621-
* timing information to save CPU time.
622-
*/
623-
VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug,
624-
"\t\tMove bb_delta_c %e, bb_cost_norm %e, timing_tradeoff %f, "
625-
"timing_delta_c %e, timing_cost_norm %e\n",
626-
cost_terms_delta.bb_cost,
627-
costs_.bb_cost_norm,
628-
placer_opts_.timing_tradeoff,
629-
timing_delta_c,
630-
costs_.timing_cost_norm);
631-
delta_c = (1 - placer_opts_.timing_tradeoff) * cost_terms_delta.bb_cost * costs_.bb_cost_norm
632-
+ placer_opts_.timing_tradeoff * timing_delta_c * costs_.timing_cost_norm
633-
+ placer_opts_.congestion_factor * cost_terms_delta.cong_cost * costs_.congestion_cost_norm;
634-
if (update_interposer_costs) {
635-
delta_c += placer_opts_.interposer_cost_params.net_cost_factor * cost_terms_delta.interposer_cost * costs_.interposer_cost_norm
636-
+ placer_opts_.interposer_cost_params.cong_cost_factor * cost_terms_delta.interposer_cong_cost * costs_.interposer_cong_cost_norm;
637-
}
638-
} else if (place_algorithm == e_place_algorithm::SLACK_TIMING_PLACE) {
596+
if (place_algorithm == e_place_algorithm::SLACK_TIMING_PLACE) {
639597
/* For setup slack analysis, we first do a timing analysis to get the newest
640598
* slack values resulted from the proposed block moves. If the move turns out
641599
* to be accepted, we keep the updated slack values and commit the block moves.
@@ -669,17 +627,6 @@ t_swap_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
669627
/* Get the setup slack analysis cost */
670628
//TODO: calculate a weighted average of the slack cost and wiring cost
671629
delta_c = analyze_setup_slack_cost(setup_slacks_, placer_state_) * costs_.timing_cost_norm;
672-
} else {
673-
VTR_ASSERT_SAFE(place_algorithm == e_place_algorithm::BOUNDING_BOX_PLACE);
674-
VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug,
675-
"\t\tMove bb_delta_c %e, bb_cost_norm %e\n",
676-
cost_terms_delta.bb_cost,
677-
costs_.bb_cost_norm);
678-
delta_c = cost_terms_delta.bb_cost * costs_.bb_cost_norm;
679-
if (update_interposer_costs) {
680-
delta_c += placer_opts_.interposer_cost_params.net_cost_factor * cost_terms_delta.interposer_cost * costs_.interposer_cost_norm
681-
+ placer_opts_.interposer_cost_params.cong_cost_factor * cost_terms_delta.interposer_cong_cost * costs_.interposer_cong_cost_norm;
682-
}
683630
}
684631

685632
NocCostTerms noc_delta_c; // change in NoC cost
@@ -717,11 +664,6 @@ t_swap_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
717664
* timing updates. These invalidations are accumulated for a
718665
* big timing update in the outer loop. */
719666
pin_timing_invalidator_->invalidate_affected_connections(blocks_affected_);
720-
721-
/* Update the connection_timing_cost and connection_delay
722-
* values from the temporary values. */
723-
placer_state_.mutable_timing().commit_td_cost(blocks_affected_);
724-
725667
} else if (place_algorithm == e_place_algorithm::SLACK_TIMING_PLACE) {
726668
// Update the timing driven cost as usual
727669
costs_.timing_cost += timing_delta_c;
@@ -731,14 +673,11 @@ t_swap_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
731673
commit_setup_slacks(setup_slacks_, placer_state_);
732674
}
733675

734-
// Update net cost functions and reset flags.
735-
net_cost_handler_.update_move_nets();
736-
if (update_interposer_costs) {
737-
interposer_cost_handler_->commit_costs(net_cost_handler_.affected_nets());
738-
}
739-
740-
// Update clb data structures since we kept the move.
741-
blk_loc_registry.commit_move_blocks(blocks_affected_);
676+
// Make the move permanent. Connection delays and timing costs are committed
677+
// only in CRITICALITY_TIMING_PLACE mode; SLACK_TIMING_PLACE already committed
678+
// them before its timing analysis.
679+
swap_evaluator_.commit(blocks_affected_, update_interposer_costs,
680+
/*commit_td=*/place_algorithm == e_place_algorithm::CRITICALITY_TIMING_PLACE);
742681

743682
if (noc_opts_.noc) {
744683
noc_cost_handler_->commit_noc_costs();
@@ -755,16 +694,11 @@ t_swap_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
755694
} else {
756695
VTR_ASSERT_SAFE(move_outcome == e_move_result::REJECTED);
757696

758-
// Reset the net cost function flags first.
759-
net_cost_handler_.reset_move_nets();
760-
761-
// Restore the blk_loc_registry.block_locs data structures to their state before the move.
762-
blk_loc_registry.revert_move_blocks(blocks_affected_);
697+
// Restore block_locs and reset the scratch/proposed state.
698+
swap_evaluator_.revert(blocks_affected_,
699+
/*revert_td=*/place_algorithm == e_place_algorithm::CRITICALITY_TIMING_PLACE);
763700

764-
if (place_algorithm == e_place_algorithm::CRITICALITY_TIMING_PLACE) {
765-
// Un-stage the values stored in proposed_* data structures
766-
placer_state_.mutable_timing().revert_td_cost(blocks_affected_);
767-
} else if (place_algorithm == e_place_algorithm::SLACK_TIMING_PLACE) {
701+
if (place_algorithm == e_place_algorithm::SLACK_TIMING_PLACE) {
768702
/* Revert the timing delays and costs to pre-update values.
769703
* These routines must be called after reverting the block moves.
770704
*/

vpr/src/place/annealer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
#include "move_generator.h" // movestats
66
#include "net_cost_handler.h"
77
#include "manual_move_generator.h"
8+
#include "swap_evaluator.h"
89
#include "vtr_random.h"
910

11+
#include <memory>
1012
#include <optional>
1113
#include <tuple>
1214

@@ -330,6 +332,9 @@ class PlacementAnnealer {
330332
/// Keep record of moved blocks and affected pins in a swap
331333
t_pl_blocks_to_be_moved blocks_affected_;
332334

335+
/// Evaluates/commits/reverts swaps
336+
SwapEvaluator swap_evaluator_;
337+
333338
private:
334339
/**
335340
* @brief The maximum number of swap attempts before invoking the

vpr/src/place/swap_evaluator.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#include "swap_evaluator.h"
2+
3+
#include "globals.h"
4+
#include "interposer_cost_handler.h"
5+
#include "move_transactions.h"
6+
#include "placer_state.h"
7+
#include "vpr_types.h"
8+
9+
SwapEvaluator::SwapEvaluator(const t_placer_opts& placer_opts,
10+
const t_placer_costs& costs,
11+
PlacerState& placer_state,
12+
NetCostHandler& net_cost_handler,
13+
std::optional<InterposerCostHandler>& interposer_cost_handler,
14+
const PlaceDelayModel* delay_model,
15+
const PlacerCriticalities* criticalities)
16+
: placer_opts_(placer_opts)
17+
, costs_(costs)
18+
, placer_state_(placer_state)
19+
, net_cost_handler_(net_cost_handler)
20+
, interposer_cost_handler_(interposer_cost_handler)
21+
, delay_model_(delay_model)
22+
, criticalities_(criticalities) {}
23+
24+
t_swap_cost_deltas SwapEvaluator::apply_and_evaluate(t_pl_blocks_to_be_moved& blocks_affected,
25+
const t_place_algorithm& place_algorithm) {
26+
t_swap_cost_deltas deltas;
27+
28+
// To make evaluating the move simpler (e.g. calculating changed bounding box),
29+
// we first move the blocks to their new locations (apply the move to
30+
// blk_loc_registry.block_locs) and then compute the change in cost. If the move
31+
// is accepted, the inverse look-up in blk_loc_registry.grid_blocks is updated
32+
// (committing the move). If the move is rejected, the blocks are returned to their
33+
// original positions (reverting blk_loc_registry.block_locs to its original state).
34+
//
35+
// Note that the inverse look-up blk_loc_registry.grid_blocks is only updated after
36+
// move acceptance is determined, so it should not be used when evaluating a move.
37+
38+
// Update the block positions
39+
placer_state_.mutable_blk_loc_registry().apply_move_blocks(blocks_affected);
40+
41+
// Find all the nets affected by this swap and update their costs.
42+
// Also finds all the pins affected by the swap, and calculates new connection
43+
// delays and timing costs.
44+
net_cost_handler_.find_affected_nets_and_update_costs(delay_model_, criticalities_, blocks_affected,
45+
deltas.cost_terms_delta,
46+
deltas.timing_delta_c);
47+
48+
deltas.update_interposer_costs = interposer_cost_handler_.has_value() && interposer_cost_handler_->has_active_cost_terms();
49+
if (deltas.update_interposer_costs) {
50+
const auto [interposer_cost_delta, interposer_cong_cost_delta] = interposer_cost_handler_->total_proposed_cost(net_cost_handler_.affected_nets());
51+
deltas.cost_terms_delta.interposer_cost = interposer_cost_delta;
52+
deltas.cost_terms_delta.interposer_cong_cost = interposer_cong_cost_delta;
53+
}
54+
55+
if (place_algorithm == e_place_algorithm::CRITICALITY_TIMING_PLACE) {
56+
// Take delta_c as a combination of timing and wiring cost. In
57+
// addition to `timing_tradeoff`, we normalize the cost values.
58+
// CRITICALITY_TIMING_PLACE algorithm works with somewhat stale
59+
// timing information to save CPU time.
60+
VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug,
61+
"\t\tMove bb_delta_c %e, bb_cost_norm %e, timing_tradeoff %f, "
62+
"timing_delta_c %e, timing_cost_norm %e\n",
63+
deltas.cost_terms_delta.bb_cost,
64+
costs_.bb_cost_norm,
65+
placer_opts_.timing_tradeoff,
66+
deltas.timing_delta_c,
67+
costs_.timing_cost_norm);
68+
deltas.delta_c = (1 - placer_opts_.timing_tradeoff) * deltas.cost_terms_delta.bb_cost * costs_.bb_cost_norm
69+
+ placer_opts_.timing_tradeoff * deltas.timing_delta_c * costs_.timing_cost_norm
70+
+ placer_opts_.congestion_factor * deltas.cost_terms_delta.cong_cost * costs_.congestion_cost_norm;
71+
if (deltas.update_interposer_costs) {
72+
deltas.delta_c += placer_opts_.interposer_cost_params.net_cost_factor * deltas.cost_terms_delta.interposer_cost * costs_.interposer_cost_norm
73+
+ placer_opts_.interposer_cost_params.cong_cost_factor * deltas.cost_terms_delta.interposer_cong_cost * costs_.interposer_cong_cost_norm;
74+
}
75+
} else if (place_algorithm == e_place_algorithm::SLACK_TIMING_PLACE) {
76+
// delta_c is derived from a setup slack analysis performed by the caller;
77+
// only the component deltas are computed here.
78+
} else {
79+
VTR_ASSERT_SAFE(place_algorithm == e_place_algorithm::BOUNDING_BOX_PLACE);
80+
VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug,
81+
"\t\tMove bb_delta_c %e, bb_cost_norm %e\n",
82+
deltas.cost_terms_delta.bb_cost,
83+
costs_.bb_cost_norm);
84+
deltas.delta_c = deltas.cost_terms_delta.bb_cost * costs_.bb_cost_norm;
85+
if (deltas.update_interposer_costs) {
86+
deltas.delta_c += placer_opts_.interposer_cost_params.net_cost_factor * deltas.cost_terms_delta.interposer_cost * costs_.interposer_cost_norm
87+
+ placer_opts_.interposer_cost_params.cong_cost_factor * deltas.cost_terms_delta.interposer_cong_cost * costs_.interposer_cong_cost_norm;
88+
}
89+
}
90+
91+
return deltas;
92+
}
93+
94+
void SwapEvaluator::commit(t_pl_blocks_to_be_moved& blocks_affected,
95+
bool update_interposer_costs,
96+
bool commit_td) {
97+
if (commit_td) {
98+
// Update the connection_timing_cost and connection_delay
99+
// values from the temporary values.
100+
placer_state_.mutable_timing().commit_td_cost(blocks_affected);
101+
}
102+
103+
// Update net cost functions and reset flags.
104+
net_cost_handler_.update_move_nets();
105+
if (update_interposer_costs) {
106+
interposer_cost_handler_->commit_costs(net_cost_handler_.affected_nets());
107+
}
108+
109+
// Update the grid_blocks inverse look-up now that the move is kept.
110+
placer_state_.mutable_blk_loc_registry().commit_move_blocks(blocks_affected);
111+
}
112+
113+
void SwapEvaluator::revert(t_pl_blocks_to_be_moved& blocks_affected, bool revert_td) {
114+
// Reset the net cost function flags first.
115+
net_cost_handler_.reset_move_nets();
116+
117+
// Restore the blk_loc_registry.block_locs data structures to their state before the move.
118+
placer_state_.mutable_blk_loc_registry().revert_move_blocks(blocks_affected);
119+
120+
if (revert_td) {
121+
// Un-stage the values stored in proposed_* data structures
122+
placer_state_.mutable_timing().revert_td_cost(blocks_affected);
123+
}
124+
}

0 commit comments

Comments
 (0)