Skip to content

Commit c9e6075

Browse files
Merge pull request #2942 from AlexandreSinger/feature-ap-partial-legalizer
[AP][GlobalPlacement] Improved Partial Legalizer Legality
2 parents ccb2396 + ce50295 commit c9e6075

18 files changed

+1487
-275
lines changed

vpr/src/analytical_place/analytical_solver.cpp

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -236,41 +236,17 @@ void QPHybridSolver::init_linear_system() {
236236
A_sparse.setFromTriplets(tripletList.begin(), tripletList.end());
237237
}
238238

239-
/**
240-
* @brief Helper method to update the linear system with anchors to the current
241-
* partial placement.
242-
*
243-
* For each moveable block (with row = i) in the netlist:
244-
* A[i][i] = A[i][i] + coeff_pseudo_anchor;
245-
* b[i] = b[i] + pos[block(i)] * coeff_pseudo_anchor;
246-
* Where coeff_pseudo_anchor grows with each iteration.
247-
*
248-
* This is basically a fast way of adding a connection between all moveable
249-
* blocks in the netlist and their target fixed placement location.
250-
*
251-
* See add_connection_to_system.
252-
*
253-
* @param A_sparse_diff The ceofficient matrix to update.
254-
* @param b_x_diff The x-dimension constant vector to update.
255-
* @param b_y_diff The y-dimension constant vector to update.
256-
* @param p_placement The location the moveable blocks should be anchored
257-
* to.
258-
* @param num_moveable_blocks The number of moveable blocks in the netlist.
259-
* @param row_id_to_blk_id Lookup for the row id from the APBlock Id.
260-
* @param iteration The current iteration of the Global Placer.
261-
*/
262-
static inline void update_linear_system_with_anchors(Eigen::SparseMatrix<double>& A_sparse_diff,
263-
Eigen::VectorXd& b_x_diff,
264-
Eigen::VectorXd& b_y_diff,
265-
PartialPlacement& p_placement,
266-
size_t num_moveable_blocks,
267-
vtr::vector<APRowId, APBlockId> row_id_to_blk_id,
268-
unsigned iteration) {
239+
void QPHybridSolver::update_linear_system_with_anchors(
240+
Eigen::SparseMatrix<double>& A_sparse_diff,
241+
Eigen::VectorXd& b_x_diff,
242+
Eigen::VectorXd& b_y_diff,
243+
PartialPlacement& p_placement,
244+
unsigned iteration) {
269245
// Anchor weights grow exponentially with iteration.
270-
double coeff_pseudo_anchor = 0.01 * std::exp((double)iteration / 5);
271-
for (size_t row_id_idx = 0; row_id_idx < num_moveable_blocks; row_id_idx++) {
246+
double coeff_pseudo_anchor = anchor_weight_mult_ * std::exp((double)iteration / anchor_weight_exp_fac_);
247+
for (size_t row_id_idx = 0; row_id_idx < num_moveable_blocks_; row_id_idx++) {
272248
APRowId row_id = APRowId(row_id_idx);
273-
APBlockId blk_id = row_id_to_blk_id[row_id];
249+
APBlockId blk_id = row_id_to_blk_id_[row_id];
274250
double pseudo_w = coeff_pseudo_anchor;
275251
A_sparse_diff.coeffRef(row_id_idx, row_id_idx) += pseudo_w;
276252
b_x_diff(row_id_idx) += pseudo_w * p_placement.block_x_locs[blk_id];
@@ -289,8 +265,7 @@ void QPHybridSolver::solve(unsigned iteration, PartialPlacement& p_placement) {
289265
// anchor-points (fixed block positions).
290266
if (iteration != 0) {
291267
update_linear_system_with_anchors(A_sparse_diff, b_x_diff, b_y_diff,
292-
p_placement, num_moveable_blocks_,
293-
row_id_to_blk_id_, iteration);
268+
p_placement, iteration);
294269
}
295270
// Verify that the constant vectors are valid.
296271
VTR_ASSERT_DEBUG(!b_x_diff.hasNaN() && "b_x has NaN!");

vpr/src/analytical_place/analytical_solver.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,21 @@ class QPHybridSolver : public AnalyticalSolver {
155155
/// sparse.
156156
static constexpr size_t star_num_pins_threshold = 3;
157157

158+
// The following constants are used to configure the anchor weighting.
159+
// The weights of anchors grow exponentially each iteration by the following
160+
// function:
161+
// anchor_w = anchor_weight_mult_ * e^(iter / anchor_weight_exp_fac_)
162+
// The numbers below were empircally found to work well.
163+
164+
/// @brief Multiplier for the anchorweight. The smaller this number is, the
165+
/// weaker the anchors will be at the start.
166+
static constexpr double anchor_weight_mult_ = 0.001;
167+
168+
/// @brief Factor for controlling the growth of the exponential term in the
169+
/// weight factor function. Larger numbers will cause the anchor
170+
/// weights to grow slower.
171+
static constexpr double anchor_weight_exp_fac_ = 5.0;
172+
158173
/**
159174
* @brief Initializes the linear system of Ax = b_x and Ay = b_y based on
160175
* the APNetlist and the fixed APBlock locations.
@@ -165,6 +180,35 @@ class QPHybridSolver : public AnalyticalSolver {
165180
*/
166181
void init_linear_system();
167182

183+
/**
184+
* @brief Helper method to update the linear system with anchors to the
185+
* current partial placement.
186+
*
187+
* For each moveable block (with row = i) in the netlist:
188+
* A[i][i] = A[i][i] + coeff_pseudo_anchor;
189+
* b[i] = b[i] + pos[block(i)] * coeff_pseudo_anchor;
190+
* Where coeff_pseudo_anchor grows with each iteration.
191+
*
192+
* This is basically a fast way of adding a connection between all moveable
193+
* blocks in the netlist and their target fixed placement location.
194+
*
195+
* See add_connection_to_system.
196+
*
197+
* @param A_sparse_diff The ceofficient matrix to update.
198+
* @param b_x_diff The x-dimension constant vector to update.
199+
* @param b_y_diff The y-dimension constant vector to update.
200+
* @param p_placement The location the moveable blocks should be
201+
* anchored to.
202+
* @param num_moveable_blocks The number of moveable blocks in the netlist.
203+
* @param row_id_to_blk_id Lookup for the row id from the APBlock Id.
204+
* @param iteration The current iteration of the Global Placer.
205+
*/
206+
void update_linear_system_with_anchors(Eigen::SparseMatrix<double>& A_sparse_diff,
207+
Eigen::VectorXd& b_x_diff,
208+
Eigen::VectorXd& b_y_diff,
209+
PartialPlacement& p_placement,
210+
unsigned iteration);
211+
168212
// The following variables represent the linear system without any anchor
169213
// points. These are filled in the constructor and never modified.
170214
// When the anchor-points are taken into consideration, the diagonal of the

vpr/src/analytical_place/flat_placement_bins.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ class FlatPlacementBins {
111111
inline const vtr::Rect<double>& bin_region(FlatPlacementBinId bin_id) const {
112112
VTR_ASSERT(bin_id.is_valid());
113113
return bin_region_[bin_id];
114-
;
115114
}
116115

117116
/**

vpr/src/analytical_place/flat_placement_density_manager.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ FlatPlacementDensityManager::FlatPlacementDensityManager(const APNetlist& ap_net
8080
auto tile_type = device_grid.get_physical_type(tile_loc);
8181
int tw = tile_type->width;
8282
int th = tile_type->height;
83+
VTR_ASSERT_SAFE(tw != 0 && th != 0);
8384
vtr::Rect<double> new_bin_region(vtr::Point<double>(x, y),
8485
vtr::Point<double>(x + tw,
8586
y + th));
@@ -162,6 +163,10 @@ void FlatPlacementDensityManager::remove_block_from_bin(APBlockId blk_id,
162163
}
163164

164165
void FlatPlacementDensityManager::import_placement_into_bins(const PartialPlacement& p_placement) {
166+
// Empty the bins such that all blocks are no longer within the bins.
167+
empty_bins();
168+
169+
// Insert each block in the netlist into their bin based on their placement.
165170
// TODO: Maybe import the fixed block locations in the constructor and then
166171
// only import the moveable block locations.
167172
for (APBlockId blk_id : ap_netlist_.blocks()) {
@@ -215,9 +220,9 @@ void FlatPlacementDensityManager::empty_bins() {
215220
// Reset all of the bins and their utilizations.
216221
for (FlatPlacementBinId bin_id : bins_.bins()) {
217222
bins_.remove_all_blocks_from_bin(bin_id);
218-
bin_utilization_[bin_id] = PrimitiveVector();
219-
bin_overfill_[bin_id] = calc_bin_overfill(bin_utilization_[bin_id], bin_capacity_[bin_id]);
220-
bin_underfill_[bin_id] = calc_bin_underfill(bin_utilization_[bin_id], bin_capacity_[bin_id]);
223+
bin_utilization_[bin_id].clear();
224+
bin_overfill_[bin_id].clear();
225+
bin_underfill_[bin_id] = bin_capacity_[bin_id];
221226
}
222227
// Once all the bins are reset, all bins should be empty; therefore no bins
223228
// are overfilled.

vpr/src/analytical_place/flat_placement_density_manager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ class FlatPlacementDensityManager {
185185
* @brief Import the given flat placement into the bins.
186186
*
187187
* This will place AP blocks into the bins that they are placed over.
188+
*
189+
* This will reset the bins before importing the placement. Anything inside
190+
* the bins will be removed.
188191
*/
189192
void import_placement_into_bins(const PartialPlacement& p_placement);
190193

vpr/src/analytical_place/flat_placement_mass_calculator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ static void print_capacities(const std::vector<PrimitiveVector>& logical_block_t
234234
VTR_LOG("\n");
235235
}
236236
VTR_LOG("\n");
237+
// TODO: Print the masses of each model.
237238
}
238239

239240
FlatPlacementMassCalculator::FlatPlacementMassCalculator(const APNetlist& ap_netlist,

vpr/src/analytical_place/global_placer.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@
1313
#include "analytical_solver.h"
1414
#include "ap_flow_enums.h"
1515
#include "ap_netlist.h"
16+
#include "ap_netlist_fwd.h"
1617
#include "atom_netlist.h"
1718
#include "device_grid.h"
19+
#include "flat_placement_bins.h"
1820
#include "flat_placement_density_manager.h"
21+
#include "globals.h"
1922
#include "partial_legalizer.h"
2023
#include "partial_placement.h"
2124
#include "physical_types.h"
25+
#include "primitive_vector.h"
2226
#include "vpr_error.h"
2327
#include "vtr_log.h"
2428
#include "vtr_time.h"
@@ -90,9 +94,74 @@ SimPLGlobalPlacer::SimPLGlobalPlacer(e_partial_legalizer partial_legalizer_type,
9094
partial_legalizer_ = make_partial_legalizer(partial_legalizer_type,
9195
ap_netlist_,
9296
density_manager_,
97+
prepacker,
9398
log_verbosity_);
9499
}
95100

101+
/**
102+
* @brief Helper method to print the statistics on the given partial placement.
103+
*/
104+
static void print_placement_stats(const PartialPlacement& p_placement,
105+
const APNetlist& ap_netlist,
106+
FlatPlacementDensityManager& density_manager) {
107+
// Print the placement HPWL
108+
VTR_LOG("\tPlacement HPWL: %f\n", p_placement.get_hpwl(ap_netlist));
109+
110+
// Print density information. Need to reset the density manager to ensure
111+
// the data is valid.
112+
density_manager.import_placement_into_bins(p_placement);
113+
114+
// Print the number of overfilled bins.
115+
size_t num_overfilled_bins = density_manager.get_overfilled_bins().size();
116+
VTR_LOG("\tNumber of overfilled bins: %zu\n", num_overfilled_bins);
117+
118+
// Print the average overfill
119+
float total_overfill = 0.0f;
120+
for (FlatPlacementBinId bin_id : density_manager.get_overfilled_bins()) {
121+
total_overfill += density_manager.get_bin_overfill(bin_id).manhattan_norm();
122+
}
123+
float avg_overfill = 0.0f;
124+
if (num_overfilled_bins != 0)
125+
avg_overfill = total_overfill / static_cast<float>(num_overfilled_bins);
126+
VTR_LOG("\tAverage overfill magnitude: %f\n", avg_overfill);
127+
128+
// Print the number of overfilled tiles per type.
129+
const auto& physical_tile_types = g_vpr_ctx.device().physical_tile_types;
130+
const auto& device_grid = g_vpr_ctx.device().grid;
131+
std::vector<unsigned> overfilled_tiles_by_type(physical_tile_types.size(), 0);
132+
for (FlatPlacementBinId bin_id : density_manager.get_overfilled_bins()) {
133+
const auto& bin_region = density_manager.flat_placement_bins().bin_region(bin_id);
134+
auto tile_loc = t_physical_tile_loc((int)bin_region.xmin(),
135+
(int)bin_region.ymin(),
136+
0);
137+
auto tile_type = device_grid.get_physical_type(tile_loc);
138+
overfilled_tiles_by_type[tile_type->index]++;
139+
}
140+
VTR_LOG("\tOverfilled bins by tile type:\n");
141+
for (size_t type_idx = 0; type_idx < physical_tile_types.size(); type_idx++) {
142+
VTR_LOG("\t\t%10s: %zu\n",
143+
physical_tile_types[type_idx].name.c_str(),
144+
overfilled_tiles_by_type[type_idx]);
145+
}
146+
147+
// Count the number of blocks that were placed in a bin which they cannot
148+
// physically be placed into (according to their mass).
149+
unsigned num_misplaced_blocks = 0;
150+
for (FlatPlacementBinId bin_id : density_manager.get_overfilled_bins()) {
151+
for (APBlockId ap_blk_id : density_manager.flat_placement_bins().bin_contained_blocks(bin_id)) {
152+
// Get the blk mass and project it onto the capacity of its bin.
153+
PrimitiveVector blk_mass = density_manager.mass_calculator().get_block_mass(ap_blk_id);
154+
PrimitiveVector projected_mass = blk_mass;
155+
projected_mass.project(density_manager.get_bin_capacity(bin_id));
156+
// If the projected mass does not match its match, this implies that
157+
// there this block does not belong in this bin.
158+
if (projected_mass != blk_mass)
159+
num_misplaced_blocks++;
160+
}
161+
}
162+
VTR_LOG("\tNumber of blocks in an incompatible bin: %zu\n", num_misplaced_blocks);
163+
}
164+
96165
/**
97166
* @brief Helper method to print the header of the per-iteration status updates
98167
* of the global placer.
@@ -177,6 +246,13 @@ PartialPlacement SimPLGlobalPlacer::place() {
177246
if (hpwl_relative_gap < target_hpwl_relative_gap_)
178247
break;
179248
}
249+
250+
// Print some statistics on the final placement.
251+
VTR_LOG("Placement after Global Placement:\n");
252+
print_placement_stats(p_placement,
253+
ap_netlist_,
254+
*density_manager_);
255+
180256
// Return the placement from the final iteration.
181257
// TODO: investigate saving the best solution found so far. It should be
182258
// cheap to save a copy of the PartialPlacement object.

vpr/src/analytical_place/global_placer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ class SimPLGlobalPlacer : public GlobalPlacer {
116116
/// lower-bound placements. The placer will stop if the difference
117117
/// between the two bounds, normalized to the upper-bound, is smaller
118118
/// than this number.
119-
static constexpr double target_hpwl_relative_gap_ = 0.10;
119+
/// This number was empircally found to work well.
120+
static constexpr double target_hpwl_relative_gap_ = 0.05;
120121

121122
/// @brief The solver which generates the lower-bound placement.
122123
std::unique_ptr<AnalyticalSolver> solver_;

0 commit comments

Comments
 (0)