Skip to content

Refactor init place for floorplanning #1817

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
merged 15 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from 10 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
58 changes: 58 additions & 0 deletions vpr/src/place/grid_tile_lookup.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "grid_tile_lookup.h"

void GridTileLookup::initialize_grid_tile_matrices() {
auto& device_ctx = g_vpr_ctx.device();

for (const auto& type : device_ctx.logical_block_types) {
vtr::NdMatrix<grid_tile_info, 2> type_count({device_ctx.grid.width(), device_ctx.grid.height()});
fill_type_matrix(&type, type_count);
block_type_matrices.push_back(type_count);
}
}

void GridTileLookup::fill_type_matrix(t_logical_block_type_ptr block_type, vtr::NdMatrix<grid_tile_info, 2>& type_count) {
auto& device_ctx = g_vpr_ctx.device();

int num_rows = device_ctx.grid.height();
int num_cols = device_ctx.grid.width();

for (int i_col = type_count.dim_size(0) - 1; i_col >= 0; i_col--) {
for (int j_row = type_count.dim_size(1) - 1; j_row >= 0; j_row--) {
auto& tile = device_ctx.grid[i_col][j_row].type;
type_count[i_col][j_row].cumulative_total = 0;
type_count[i_col][j_row].st_range.set(0, 0);

if (is_tile_compatible(tile, block_type)) {
for (const auto& sub_tile : tile->sub_tiles) {
if (is_sub_tile_compatible(tile, block_type, sub_tile.capacity.low)) {
type_count[i_col][j_row].st_range.set(sub_tile.capacity.low, sub_tile.capacity.high);
type_count[i_col][j_row].cumulative_total = 1;
}
}
}

if (i_col < num_cols - 1) {
type_count[i_col][j_row].cumulative_total += type_count[i_col + 1][j_row].cumulative_total;
}
if (j_row < num_rows - 1) {
type_count[i_col][j_row].cumulative_total += type_count[i_col][j_row + 1].cumulative_total;
}
if (i_col < (num_cols - 1) && j_row < (num_rows - 1)) {
type_count[i_col][j_row].cumulative_total -= type_count[i_col + 1][j_row + 1].cumulative_total;
}
}
}
}

vtr::NdMatrix<grid_tile_info, 2>& GridTileLookup::get_type_grid(t_logical_block_type_ptr block_type) {
return block_type_matrices[block_type->index];
}

void GridTileLookup::print_type_matrix(vtr::NdMatrix<grid_tile_info, 2>& type_count) {
for (int i_col = type_count.dim_size(0) - 1; i_col >= 0; i_col--) {
for (int j_row = type_count.dim_size(1) - 1; j_row >= 0; j_row--) {
VTR_LOG("%d ", type_count[i_col][j_row].cumulative_total);
}
VTR_LOG("\n");
}
}
33 changes: 33 additions & 0 deletions vpr/src/place/grid_tile_lookup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* This class is used to stores a grid for each logical block type. The grid stores the number of cumulative
* tiles that are available for this block type at each grid location. At each grid location, it also stores
* the range of compatible subtiles for the block type.
* This lookup class is used during initial placement when sorting blocks by the size of their floorplan constraint
* regions.
*/
#ifndef VPR_SRC_PLACE_GRID_TILE_LOOKUP_H_
#define VPR_SRC_PLACE_GRID_TILE_LOOKUP_H_

#include "place_util.h"
#include "globals.h"

struct grid_tile_info {
t_capacity_range st_range;
int cumulative_total;
};

class GridTileLookup {
public:
vtr::NdMatrix<grid_tile_info, 2>& get_type_grid(t_logical_block_type_ptr block_type);

void initialize_grid_tile_matrices();

void fill_type_matrix(t_logical_block_type_ptr block_type, vtr::NdMatrix<grid_tile_info, 2>& type_count);

void print_type_matrix(vtr::NdMatrix<grid_tile_info, 2>& type_count);

private:
std::vector<vtr::NdMatrix<grid_tile_info, 2>> block_type_matrices;
};

#endif /* VPR_SRC_PLACE_GRID_TILE_LOOKUP_H_ */
122 changes: 76 additions & 46 deletions vpr/src/place/initial_placement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
struct t_block_score {
int macro_size = 0; //how many members does the macro have, if the block is part of one, this value is zero if the block is not in a macro

int floorplan_constraints = 0; //how many floorplan constraints does it have, if any

int num_equivalent_tiles = 1; //num of physical locations at which this block could be placed
/*
* The number of tiles NOT covered by the block's floorplan constraints. The higher this number, the more
* difficult the block is to place.
*/
int tiles_outside_of_floorplan_constraints = 0;
};

/* The maximum number of tries when trying to place a carry chain at a *
Expand All @@ -31,9 +33,9 @@ static int get_free_sub_tile(std::vector<std::vector<int>>& free_locations, int

static int check_macro_can_be_placed(t_pl_macro pl_macro, int itype, t_pl_loc head_pos);
static int try_place_macro(int itype, int ipos, int isub_tile, t_pl_macro pl_macro);
static void initial_placement_pl_macros(int macros_max_num_tries, std::vector<std::vector<int>>& free_locations);
static void initial_placement_pl_macros(int macros_max_num_tries, std::vector<std::vector<int>>& free_locations, const std::vector<t_pl_macro>& sorted_macros);

static void initial_placement_blocks(std::vector<std::vector<int>>& free_locations, enum e_pad_loc_type pad_loc_type, std::vector<ClusterBlockId> sorted_blocks);
static void initial_placement_blocks(std::vector<std::vector<int>>& free_locations, enum e_pad_loc_type pad_loc_type, const std::vector<ClusterBlockId>& sorted_blocks);

static t_physical_tile_type_ptr pick_placement_type(t_logical_block_type_ptr logical_block,
int num_needed_types,
Expand All @@ -44,10 +46,13 @@ static t_physical_tile_type_ptr pick_placement_type(t_logical_block_type_ptr log
* Used for relative placement, so that the blocks that are more difficult to place can be placed first during initial placement.
* A higher score indicates that the block is more difficult to place.
*/
vtr::vector<ClusterBlockId, t_block_score> assign_block_scores();
static vtr::vector<ClusterBlockId, t_block_score> assign_block_scores();

//Sort the blocks according to how difficult they are to place, prior to initial placement
std::vector<ClusterBlockId> sort_blocks(const vtr::vector<ClusterBlockId, t_block_score>& block_scores);
static std::vector<ClusterBlockId> sort_blocks(const vtr::vector<ClusterBlockId, t_block_score>& block_scores);

//Sort the macros according to how difficult they are to place, prior to initial placement
static std::vector<t_pl_macro> sort_macros(const vtr::vector<ClusterBlockId, t_block_score>& block_scores);

void print_sorted_blocks(const std::vector<ClusterBlockId>& sorted_blocks, const vtr::vector<ClusterBlockId, t_block_score>& block_scores);

Expand Down Expand Up @@ -161,33 +166,15 @@ static int try_place_macro(int itype, int ipos, int isub_tile, t_pl_macro pl_mac
return (macro_placed);
}

static void initial_placement_pl_macros(int macros_max_num_tries, std::vector<std::vector<int>>& free_locations) {
static void initial_placement_pl_macros(int macros_max_num_tries, std::vector<std::vector<int>>& free_locations, const std::vector<t_pl_macro>& sorted_macros) {
int macro_placed;
int itype, itry, ipos, isub_tile;
ClusterBlockId blk_id;

auto& cluster_ctx = g_vpr_ctx.clustering();
auto& place_ctx = g_vpr_ctx.placement();

auto& pl_macros = place_ctx.pl_macros;

// Sorting blocks to place to have most constricted ones to be placed first
std::vector<t_pl_macro> sorted_pl_macros(pl_macros.begin(), pl_macros.end());

auto criteria = [&cluster_ctx](const t_pl_macro lhs, t_pl_macro rhs) {
auto lhs_logical_block = cluster_ctx.clb_nlist.block_type(lhs.members[0].blk_index);
auto rhs_logical_block = cluster_ctx.clb_nlist.block_type(rhs.members[0].blk_index);

auto lhs_num_tiles = lhs_logical_block->equivalent_tiles.size();
auto rhs_num_tiles = rhs_logical_block->equivalent_tiles.size();

return lhs_num_tiles < rhs_num_tiles;
};

std::stable_sort(sorted_pl_macros.begin(), sorted_pl_macros.end(), criteria);

/* Macros are harder to place. Do them first */
for (auto pl_macro : sorted_pl_macros) {
for (auto pl_macro : sorted_macros) {
// Every macro are not placed in the beginnning
macro_placed = false;

Expand Down Expand Up @@ -255,7 +242,7 @@ static void initial_placement_pl_macros(int macros_max_num_tries, std::vector<st

/* Place blocks that are NOT a part of any macro.
* We'll randomly place each block in the clustered netlist, one by one. */
static void initial_placement_blocks(std::vector<std::vector<int>>& free_locations, enum e_pad_loc_type pad_loc_type, std::vector<ClusterBlockId> sorted_blocks) {
static void initial_placement_blocks(std::vector<std::vector<int>>& free_locations, enum e_pad_loc_type pad_loc_type, const std::vector<ClusterBlockId>& sorted_blocks) {
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& place_ctx = g_vpr_ctx.mutable_placement();

Expand Down Expand Up @@ -346,18 +333,25 @@ static t_physical_tile_type_ptr pick_placement_type(t_logical_block_type_ptr log
return nullptr;
}

vtr::vector<ClusterBlockId, t_block_score> assign_block_scores() {
static vtr::vector<ClusterBlockId, t_block_score> assign_block_scores() {
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& place_ctx = g_vpr_ctx.placement();
auto& floorplan_ctx = g_vpr_ctx.floorplanning();
auto& device_ctx = g_vpr_ctx.device();

auto blocks = cluster_ctx.clb_nlist.blocks();
auto pl_macros = place_ctx.pl_macros;
int num_grid_tiles = device_ctx.grid.height() * device_ctx.grid.width();

auto& pl_macros = place_ctx.pl_macros;

t_block_score score;

vtr::vector<ClusterBlockId, t_block_score> block_scores;

block_scores.resize(blocks.size());
block_scores.resize(cluster_ctx.clb_nlist.blocks().size());

//GridTileLookup class provides info needed for calculating number of tiles covered by a region
GridTileLookup grid_tiles;
grid_tiles.initialize_grid_tile_matrices();

/*
* For the blocks with no floorplan constraints, and the blocks that are not part of macros,
Expand All @@ -366,13 +360,21 @@ vtr::vector<ClusterBlockId, t_block_score> assign_block_scores() {
*/

//go through all blocks and store floorplan constraints and num equivalent tiles
for (auto blk_id : blocks) {
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
if (is_cluster_constrained(blk_id)) {
block_scores[blk_id].floorplan_constraints = 1;
PartitionRegion pr = floorplan_ctx.cluster_constraints[blk_id];
auto block_type = cluster_ctx.clb_nlist.block_type(blk_id);
int num_floorplan_tiles = get_part_reg_size(pr, block_type, grid_tiles);
if (num_floorplan_tiles == 0) {
VPR_FATAL_ERROR(VPR_ERROR_PLACE,
"Initial placement failed.\n"
"The specified floorplan region for block %s (# %d) has no available locations for its type. \n"
"Please specify a different floorplan region for the block. Note that if the region has a specified subtile, "
"an incompatible subtile location may be the cause of the floorplan region failure. \n",
cluster_ctx.clb_nlist.block_name(blk_id).c_str(), blk_id);
}
block_scores[blk_id].tiles_outside_of_floorplan_constraints = num_grid_tiles - num_floorplan_tiles;
}
auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id);
auto num_tiles = logical_block->equivalent_tiles.size();
block_scores[blk_id].num_equivalent_tiles = num_tiles;
}

//go through placement macros and store size of macro for each block
Expand All @@ -386,16 +388,24 @@ vtr::vector<ClusterBlockId, t_block_score> assign_block_scores() {
return block_scores;
}

std::vector<ClusterBlockId> sort_blocks(const vtr::vector<ClusterBlockId, t_block_score>& block_scores) {
static std::vector<ClusterBlockId> sort_blocks(const vtr::vector<ClusterBlockId, t_block_score>& block_scores) {
auto& cluster_ctx = g_vpr_ctx.clustering();

auto blocks = cluster_ctx.clb_nlist.blocks();

std::vector<ClusterBlockId> sorted_blocks(blocks.begin(), blocks.end());

/*
* The criteria considers blocks that belong to a macro or to a floorplan region more difficult to place.
* The bigger the macro, and/or the tighter the floorplan constraint, the earlier the block will be in
* the list of sorted blocks.
* The tiles_outside_of_floorplan_constraints will dominate the criteria, since the number of tiles will
* likely be significantly bigger than the macro size. This is okay since the floorplan constraints give
* a more accurate picture of how difficult a block is to place.
*/
auto criteria = [block_scores](ClusterBlockId lhs, ClusterBlockId rhs) {
int lhs_score = 100 * block_scores[lhs].macro_size + 10 * block_scores[lhs].floorplan_constraints + 10 / (block_scores[lhs].num_equivalent_tiles);
int rhs_score = 100 * block_scores[rhs].macro_size + 10 * block_scores[rhs].floorplan_constraints + 10 / (block_scores[rhs].num_equivalent_tiles);
int lhs_score = 10 * block_scores[lhs].macro_size + block_scores[lhs].tiles_outside_of_floorplan_constraints;
int rhs_score = 10 * block_scores[rhs].macro_size + block_scores[rhs].tiles_outside_of_floorplan_constraints;

return lhs_score > rhs_score;
};
Expand All @@ -406,10 +416,29 @@ std::vector<ClusterBlockId> sort_blocks(const vtr::vector<ClusterBlockId, t_bloc
return sorted_blocks;
}

static std::vector<t_pl_macro> sort_macros(const vtr::vector<ClusterBlockId, t_block_score>& block_scores) {
auto& place_ctx = g_vpr_ctx.placement();
auto& pl_macros = place_ctx.pl_macros;

// Sorting blocks to place to have most constricted ones to be placed first
std::vector<t_pl_macro> sorted_pl_macros(pl_macros.begin(), pl_macros.end());

auto criteria = [block_scores](const t_pl_macro lhs, t_pl_macro rhs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be refactored to place blocks & macros in one loop, with the sorted_blocks vector controlling it all.

int lhs_score = 10 * block_scores[lhs.members[0].blk_index].macro_size + block_scores[lhs.members[0].blk_index].tiles_outside_of_floorplan_constraints;
int rhs_score = 10 * block_scores[rhs.members[0].blk_index].macro_size + block_scores[rhs.members[0].blk_index].tiles_outside_of_floorplan_constraints;

return lhs_score > rhs_score;
};

std::stable_sort(sorted_pl_macros.begin(), sorted_pl_macros.end(), criteria);

return sorted_pl_macros;
}

void print_sorted_blocks(const std::vector<ClusterBlockId>& sorted_blocks, const vtr::vector<ClusterBlockId, t_block_score>& block_scores) {
VTR_LOG("\nPrinting sorted blocks: \n");
for (unsigned int i = 0; i < sorted_blocks.size(); i++) {
VTR_LOG("Block_Id: %zu, Macro size: %d, Num floorplan constraints: %d, Num equivalent tiles %d \n", sorted_blocks[i], block_scores[sorted_blocks[i]].macro_size, block_scores[sorted_blocks[i]].floorplan_constraints, block_scores[sorted_blocks[i]].num_equivalent_tiles);
VTR_LOG("Block_Id: %zu, Macro size: %d, Num tiles outside floorplan constraints: %d\n", sorted_blocks[i], block_scores[sorted_blocks[i]].macro_size, block_scores[sorted_blocks[i]].tiles_outside_of_floorplan_constraints);
}
}

Expand All @@ -421,15 +450,16 @@ void initial_placement(enum e_pad_loc_type pad_loc_type, const char* constraints
* array that gives every legal value of (x,y,z) that can accommodate a block.
*/

//Sort blocks
vtr::vector<ClusterBlockId, t_block_score> block_scores = assign_block_scores();
std::vector<ClusterBlockId> sorted_blocks = sort_blocks(block_scores);

/* Go through cluster blocks to calculate the tightest placement
* floorplan constraint for each constrained block
*/
propagate_place_constraints();

//Sort blocks and placement macros according to how difficult they are to place
vtr::vector<ClusterBlockId, t_block_score> block_scores = assign_block_scores();
std::vector<ClusterBlockId> sorted_blocks = sort_blocks(block_scores);
std::vector<t_pl_macro> sorted_macros = sort_macros(block_scores);

// Loading legal placement locations
zero_initialize_grid_blocks();
alloc_and_load_legal_placement_locations(legal_pos);
Expand Down Expand Up @@ -483,7 +513,7 @@ void initial_placement(enum e_pad_loc_type pad_loc_type, const char* constraints
* as fixed so they do not get moved during initial placement or during simulated annealing*/
mark_fixed_blocks();

initial_placement_pl_macros(MAX_NUM_TRIES_TO_PLACE_MACROS_RANDOMLY, free_locations);
initial_placement_pl_macros(MAX_NUM_TRIES_TO_PLACE_MACROS_RANDOMLY, free_locations, sorted_macros);

// All the macros are placed, update the legal_pos[][] array and free_locations[] array
for (const auto& type : device_ctx.physical_tile_types) {
Expand Down
Loading