Skip to content

Commit

Permalink
Merge pull request #2769 from AlexandreSinger/feature-verify-placement
Browse files Browse the repository at this point in the history
[Place] Independent Placement Verification
  • Loading branch information
AlexandreSinger authored Nov 7, 2024
2 parents e179d88 + c096e2f commit 045a9e8
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 159 deletions.
13 changes: 12 additions & 1 deletion vpr/src/analytical_place/full_legalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#include "full_legalizer.h"

#include <cmath>
#include <list>
#include <unordered_set>
#include <vector>
Expand All @@ -27,6 +26,7 @@
#include "physical_types.h"
#include "place_constraints.h"
#include "place_macro.h"
#include "verify_placement.h"
#include "vpr_api.h"
#include "vpr_context.h"
#include "vpr_error.h"
Expand Down Expand Up @@ -396,5 +396,16 @@ void FullLegalizer::legalize(const PartialPlacement& p_placement) {

// Place the clusters based on where the atoms want to be placed.
place_clusters(clb_nlist, p_placement);

// Verify that the placement created by the full legalizer is valid.
unsigned num_placement_errors = verify_placement(g_vpr_ctx);
if (num_placement_errors == 0) {
VTR_LOG("Completed placement consistency check successfully.\n");
} else {
VPR_ERROR(VPR_ERROR_AP,
"Completed placement consistency check, %u errors found.\n"
"Aborting program.\n",
num_placement_errors);
}
}

3 changes: 3 additions & 0 deletions vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,9 @@ bool vpr_place_flow(const Netlist<>& net_list, t_vpr_setup& vpr_setup, const t_a
vpr_load_placement(vpr_setup, arch);
}

// FIXME: This synchronization is not consistent with the rest of
// placement. This requires it to happen after the placement is
// verified. See issue #2801
sync_grid_to_blocks();
post_place_sync();
}
Expand Down
146 changes: 12 additions & 134 deletions vpr/src/place/place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include <optional>

#include "NetPinTimingInvalidator.h"
#include "clustered_netlist.h"
#include "device_grid.h"
#include "verify_placement.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_util.h"
Expand Down Expand Up @@ -228,11 +231,6 @@ static int check_placement_costs(const t_placer_costs& costs,
PlacerState& placer_state,
NetCostHandler& net_cost_handler);


static int check_placement_consistency(const BlkLocRegistry& blk_loc_registry);
static int check_block_placement_consistency(const BlkLocRegistry& blk_loc_registry);
static int check_macro_placement_consistency(const BlkLocRegistry& blk_loc_registry);

static float starting_t(const t_annealing_state* state,
t_placer_costs* costs,
t_annealing_sched annealing_sched,
Expand Down Expand Up @@ -1943,12 +1941,19 @@ static void check_place(const t_placer_costs& costs,
* every block, blocks are in legal spots, etc. Also recomputes *
* the final placement cost from scratch and makes sure it is *
* within roundoff of what we think the cost is. */
const ClusteredNetlist& clb_nlist = g_vpr_ctx.clustering().clb_nlist;
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
const auto& cluster_constraints = g_vpr_ctx.floorplanning().cluster_constraints;

int error = 0;

error += check_placement_consistency(placer_state.blk_loc_registry());
// Verify the placement invariants independent to the placement flow.
error += verify_placement(placer_state.blk_loc_registry(),
clb_nlist,
device_grid,
cluster_constraints);

error += check_placement_costs(costs, delay_model, criticalities, place_algorithm, placer_state, net_cost_handler);
error += check_placement_floorplanning(placer_state.block_locs());

if (noc_opts.noc) {
// check the NoC costs during placement if the user is using the NoC supported flow
Expand Down Expand Up @@ -2000,133 +2005,6 @@ static int check_placement_costs(const t_placer_costs& costs,
return error;
}

static int check_placement_consistency(const BlkLocRegistry& blk_loc_registry) {
return check_block_placement_consistency(blk_loc_registry) + check_macro_placement_consistency(blk_loc_registry);
}

static int check_block_placement_consistency(const BlkLocRegistry& blk_loc_registry) {
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& device_ctx = g_vpr_ctx.device();
const auto& block_locs = blk_loc_registry.block_locs();
const auto& grid_blocks = blk_loc_registry.grid_blocks();

int error = 0;

vtr::vector<ClusterBlockId, int> bdone(cluster_ctx.clb_nlist.blocks().size(), 0);

/* Step through device grid and placement. Check it against blocks */
for (int layer_num = 0; layer_num < (int)device_ctx.grid.get_num_layers(); layer_num++) {
for (int i = 0; i < (int)device_ctx.grid.width(); i++) {
for (int j = 0; j < (int)device_ctx.grid.height(); j++) {
const t_physical_tile_loc tile_loc(i, j, layer_num);
const auto& type = device_ctx.grid.get_physical_type(tile_loc);
if (grid_blocks.get_usage(tile_loc) > type->capacity) {
VTR_LOG_ERROR(
"%d blocks were placed at grid location (%d,%d,%d), but location capacity is %d.\n",
grid_blocks.get_usage(tile_loc), i, j, layer_num, type->capacity);
error++;
}
int usage_check = 0;
for (int k = 0; k < type->capacity; k++) {
ClusterBlockId bnum = grid_blocks.block_at_location({i, j, k, layer_num});
if (bnum == ClusterBlockId::INVALID()) {
continue;
}

auto logical_block = cluster_ctx.clb_nlist.block_type(bnum);
auto physical_tile = type;
t_pl_loc block_loc = block_locs[bnum].loc;

if (physical_tile_type(block_loc) != physical_tile) {
VTR_LOG_ERROR(
"Block %zu type (%s) does not match grid location (%zu,%zu, %d) type (%s).\n",
size_t(bnum), logical_block->name.c_str(), i, j, layer_num, physical_tile->name.c_str());
error++;
}

auto& loc = block_locs[bnum].loc;
if (loc.x != i || loc.y != j || loc.layer != layer_num
|| !is_sub_tile_compatible(physical_tile, logical_block,
loc.sub_tile)) {
VTR_LOG_ERROR(
"Block %zu's location is (%d,%d,%d,%d) but found in grid at (%d,%d,%d,%d).\n",
size_t(bnum),
loc.x,
loc.y,
loc.sub_tile,
loc.layer,
i,
j,
k,
layer_num);
error++;
}
++usage_check;
bdone[bnum]++;
}
if (usage_check != grid_blocks.get_usage(tile_loc)) {
VTR_LOG_ERROR(
"%d block(s) were placed at location (%d,%d,%d), but location contains %d block(s).\n",
grid_blocks.get_usage(tile_loc),
tile_loc.x,
tile_loc.y,
tile_loc.layer_num,
usage_check);
error++;
}
}
}
}

/* Check that every block exists in the device_ctx.grid and cluster_ctx.blocks arrays somewhere. */
for (ClusterBlockId blk_id : cluster_ctx.clb_nlist.blocks())
if (bdone[blk_id] != 1) {
VTR_LOG_ERROR("Block %zu listed %d times in device context grid.\n",
size_t(blk_id), bdone[blk_id]);
error++;
}

return error;
}

int check_macro_placement_consistency(const BlkLocRegistry& blk_loc_registry) {
const auto& pl_macros = blk_loc_registry.place_macros().macros();
const auto& block_locs = blk_loc_registry.block_locs();
const auto& grid_blocks = blk_loc_registry.grid_blocks();

int error = 0;

/* Check the pl_macro placement are legal - blocks are in the proper relative position. */
for (size_t imacro = 0; imacro < pl_macros.size(); imacro++) {
auto head_iblk = pl_macros[imacro].members[0].blk_index;

for (size_t imember = 0; imember < pl_macros[imacro].members.size(); imember++) {
auto member_iblk = pl_macros[imacro].members[imember].blk_index;

// Compute the supposed member's x,y,z location
t_pl_loc member_pos = block_locs[head_iblk].loc + pl_macros[imacro].members[imember].offset;

// Check the blk_loc_registry.block_locs data structure first
if (block_locs[member_iblk].loc != member_pos) {
VTR_LOG_ERROR(
"Block %zu in pl_macro #%zu is not placed in the proper orientation.\n",
size_t(member_iblk), imacro);
error++;
}

// Then check the blk_loc_registry.grid data structure
if (grid_blocks.block_at_location(member_pos) != member_iblk) {
VTR_LOG_ERROR(
"Block %zu in pl_macro #%zu is not placed in the proper orientation.\n",
size_t(member_iblk), imacro);
error++;
}
} // Finish going through all the members
} // Finish going through all the macros

return error;
}

#ifdef VERBOSE
void print_clb_placement(const char* fname) {
/* Prints out the clb placements to a file. */
Expand Down
15 changes: 0 additions & 15 deletions vpr/src/place/place_constraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,6 @@
#include "place_util.h"
#include "vpr_context.h"

int check_placement_floorplanning(const vtr::vector_map<ClusterBlockId, t_block_loc>& block_locs) {
int error = 0;
auto& cluster_ctx = g_vpr_ctx.clustering();

for (ClusterBlockId blk_id : cluster_ctx.clb_nlist.blocks()) {
t_pl_loc loc = block_locs[blk_id].loc;
if (!cluster_floorplanning_legal(blk_id, loc)) {
error++;
VTR_LOG_ERROR("Block %zu is not in correct floorplanning region.\n", size_t(blk_id));
}
}

return error;
}

bool is_cluster_constrained(ClusterBlockId blk_id) {
auto& floorplanning_ctx = g_vpr_ctx.floorplanning();
const PartitionRegion& pr = floorplanning_ctx.cluster_constraints[blk_id];
Expand Down
9 changes: 0 additions & 9 deletions vpr/src/place/place_constraints.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
#include "place_macro.h"
#include "grid_tile_lookup.h"

/**
* @brief Check that placement of each block is within the floorplan constraint region
* of that block (if the block has any constraints).
*
* @param block_locs Contains the location where each clustered block is placed.
* @return int The number of errors (inconsistencies in adherence to floorplanning constraints).
*/
int check_placement_floorplanning(const vtr::vector_map<ClusterBlockId, t_block_loc>& block_locs);

/**
* @brief Check if the block has floorplanning constraints.
*
Expand Down
Loading

0 comments on commit 045a9e8

Please sign in to comment.