Skip to content

[Place] Independent Placement Verification #2769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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