Skip to content

Refactored read_place and read_user_block_loc functions into two new … #1490

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 9 commits into from
Sep 8, 2020
263 changes: 99 additions & 164 deletions vpr/src/base/read_place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
#include "read_place.h"
#include "read_xml_arch_file.h"

void read_place(const char* net_file,
const char* place_file,
bool verify_file_digests,
const DeviceGrid& grid) {
/*This function reads the header of a placement file.
* The header has two lines:
* One for checking the netlist file
* And another for checking grid dimensions
*/
void read_place_header(const char* net_file,
const char* place_file,
bool verify_file_digests,
const DeviceGrid& grid) {
std::ifstream fstream(place_file);
if (!fstream) {
VPR_FATAL_ERROR(VPR_ERROR_PLACE_F,
Expand All @@ -27,13 +32,13 @@ void read_place(const char* net_file,
}

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

std::string line;
int lineno = 0;
bool seen_netlist_id = false;
bool seen_grid_dimensions = false;
while (std::getline(fstream, line)) { //Parse line-by-line
bool read_header_lines = false;

while (std::getline(fstream, line) && !read_header_lines) { //Parse line-by-line
++lineno;

std::vector<std::string> tokens = vtr::split(line);
Expand Down Expand Up @@ -84,11 +89,6 @@ void read_place(const char* net_file,
&& tokens[6] == "blocks") {
//Load the device grid dimensions

if (seen_grid_dimensions) {
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno,
"Duplicate device grid dimensions specification");
}

size_t place_file_width = vtr::atou(tokens[2]);
size_t place_file_height = vtr::atou(tokens[4]);
if (grid.width() != place_file_width || grid.height() != place_file_height) {
Expand All @@ -97,194 +97,129 @@ void read_place(const char* net_file,
grid.width(), grid.height(), place_file_width, place_file_height);
}

seen_grid_dimensions = true;

} else if (tokens.size() == 4 || (tokens.size() == 5 && tokens[4][0] == '#')) {
//Load the block location
//
//We should have 4 tokens of actual data, with an optional 5th (commented) token indicating VPR's
//internal block number

//Grid dimensions are required by this point
if (!seen_grid_dimensions) {
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno,
"Missing device grid size specification");
}

std::string block_name = tokens[0];
int block_x = vtr::atoi(tokens[1]);
int block_y = vtr::atoi(tokens[2]);
int sub_tile_index = vtr::atoi(tokens[3]);

ClusterBlockId blk_id = cluster_ctx.clb_nlist.find_block(block_name);

if (place_ctx.block_locs.size() != cluster_ctx.clb_nlist.blocks().size()) {
//Resize if needed
place_ctx.block_locs.resize(cluster_ctx.clb_nlist.blocks().size());
}

//Set the location
place_ctx.block_locs[blk_id].loc.x = block_x;
place_ctx.block_locs[blk_id].loc.y = block_y;
place_ctx.block_locs[blk_id].loc.sub_tile = sub_tile_index;
read_header_lines = true; //if you have read the grid dimensions you are done reading the place file header

} else {
//Unrecognized
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno,
"Invalid line '%s' in placement file",
"Invalid line '%s' in placement file header",
line.c_str());
}
}

place_ctx.placement_id = vtr::secure_digest_file(place_file);
}

/** Reads in blocks whose locations are specified in a constraints file. Constraint file is in .place format.
* All blocks specified in this file will be locked down at their specified x, y, subtile locations.
* (Will not be moved by optimizers during placement
/*This function reads either the body of a placement file or a constraints file.
* If it is reading a constraints file it marks blocks as locked as it reads in their locations.
* The bool is_place_file indicates if the file should be read as a place file (is_place_file = true)
* or a constraints file (is_place_file = false).
*/
void read_user_block_loc(const char* constraints_file) {
t_hash **hash_table, *h_ptr;
int xtmp, ytmp;
FILE* fp;
char buf[vtr::bufsize], bname[vtr::bufsize], *ptr;
std::unordered_set<ClusterBlockId> constrained_blocks;
void read_place_body(const char* place_file,
bool is_place_file) {
std::ifstream fstream(place_file);
if (!fstream) {
VPR_FATAL_ERROR(VPR_ERROR_PLACE_F,
"'%s' - Cannot open place file.\n",
place_file);
}

auto& cluster_ctx = g_vpr_ctx.clustering();
auto& device_ctx = g_vpr_ctx.device();
auto& place_ctx = g_vpr_ctx.mutable_placement();

VTR_LOG("\n");
VTR_LOG("Reading locations of blocks from '%s'.\n", constraints_file);
fp = fopen(constraints_file, "r");
if (!fp) VPR_FATAL_ERROR(VPR_ERROR_PLACE_F,
"'%s' - Cannot find block locations file.\n",
constraints_file);

hash_table = alloc_hash_table();
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
insert_in_hash_table(hash_table, cluster_ctx.clb_nlist.block_name(blk_id).c_str(), size_t(blk_id));
place_ctx.block_locs[blk_id].loc.x = OPEN; /* Mark as not seen yet. */
}

for (size_t i = 0; i < device_ctx.grid.width(); i++) {
for (size_t j = 0; j < device_ctx.grid.height(); j++) {
auto type = device_ctx.grid[i][j].type;
if (!is_empty_type(type)) {
for (int k = 0; k < type->capacity; k++) {
if (place_ctx.grid_blocks[i][j].blocks[k] != INVALID_BLOCK_ID) {
place_ctx.grid_blocks[i][j].blocks[k] = EMPTY_BLOCK_ID; /* Flag for err. check */
}
}
}
//Mark unseen blocks for error-checking for constraints file
if (!is_place_file) {
for (auto block_id : cluster_ctx.clb_nlist.blocks()) {
place_ctx.block_locs[block_id].loc.x = OPEN; //Mark as not seen yet
}
}

ptr = vtr::fgets(buf, vtr::bufsize, fp);

while (ptr != nullptr) {
ptr = vtr::strtok(buf, TOKENS, fp, buf);
if (ptr == nullptr) {
ptr = vtr::fgets(buf, vtr::bufsize, fp);
continue; /* Skip blank or comment lines. */
}
std::string line;
int lineno = 0;

if (strlen(ptr) + 1 < vtr::bufsize) {
strcpy(bname, ptr);
} else {
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Block name exceeded buffer size of %zu characters", vtr::bufsize);
}
while (std::getline(fstream, line)) { //Parse line-by-line
++lineno;

ptr = vtr::strtok(nullptr, TOKENS, fp, buf);
if (ptr == nullptr) {
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Incomplete.\n");
}
sscanf(ptr, "%d", &xtmp);
std::vector<std::string> tokens = vtr::split(line);

ptr = vtr::strtok(nullptr, TOKENS, fp, buf);
if (ptr == nullptr) {
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Incomplete.\n");
}
sscanf(ptr, "%d", &ytmp);
if (tokens.empty()) {
continue; //Skip blank lines

ptr = vtr::strtok(nullptr, TOKENS, fp, buf);
if (ptr == nullptr) {
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Incomplete.\n");
}
int k;
sscanf(ptr, "%d", &k);
} else if (tokens[0][0] == '#') {
continue; //Skip commented lines

ptr = vtr::strtok(nullptr, TOKENS, fp, buf);
if (ptr != nullptr) {
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Extra characters at end of line.\n");
}
} else if (is_place_file
&& tokens.size() == 4
&& tokens[0] == "Netlist_File:"
&& tokens[2] == "Netlist_ID:") {
continue; //Skip netlist line if place file, already checked in read_place_header

h_ptr = get_hash_entry(hash_table, bname);
if (h_ptr == nullptr) {
VTR_LOG_WARN("[Line %d] Block %s invalid, no such block.\n",
vtr::get_file_line_number_of_last_opened_file(), bname);
ptr = vtr::fgets(buf, vtr::bufsize, fp);
continue;
}
ClusterBlockId bnum(h_ptr->index);
int i = xtmp;
int j = ytmp;
} else if (is_place_file
&& tokens.size() == 7
&& tokens[0] == "Array"
&& tokens[1] == "size:"
&& tokens[3] == "x"
&& tokens[5] == "logic"
&& tokens[6] == "blocks") {
continue; //Skip checking grid dimensions if place file, already checked in read_place_header

if (place_ctx.block_locs[bnum].loc.x != OPEN) {
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Block %s is listed twice in constraints file.\n", bname);
}
} else if (tokens.size() == 4 || (tokens.size() == 5 && tokens[4][0] == '#')) {
//Load the block location
//
//We should have 4 tokens of actual data, with an optional 5th (commented) token indicating VPR's
//internal block number

if (i < 0 || i > int(device_ctx.grid.width() - 1) || j < 0 || j > int(device_ctx.grid.height() - 1)) {
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, 0,
"Block #%zu (%s) location, (%d,%d) is out of range.\n", size_t(bnum), bname, i, j);
}
std::string block_name = tokens[0];
int block_x = vtr::atoi(tokens[1]);
int block_y = vtr::atoi(tokens[2]);
int sub_tile_index = vtr::atoi(tokens[3]);

place_ctx.block_locs[bnum].loc.x = i; /* Will be reloaded by initial_placement anyway. */
place_ctx.block_locs[bnum].loc.y = j; /* We need to set .x only as a done flag. */
place_ctx.block_locs[bnum].loc.sub_tile = k;
place_ctx.block_locs[bnum].is_fixed = true;
ClusterBlockId blk_id = cluster_ctx.clb_nlist.find_block(block_name);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

find what this returns if it doesn't find the block name - use for invalid block name check


auto physical_tile = device_ctx.grid[i][j].type;
auto logical_block = cluster_ctx.clb_nlist.block_type(bnum);
if (!is_sub_tile_compatible(physical_tile, logical_block, place_ctx.block_locs[bnum].loc.sub_tile)) {
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, 0,
"Attempt to place block %s at illegal location (%d, %d).\n", bname, i, j);
}
//Check if block is listed twice in constraints file
if (!is_place_file) {
if (place_ctx.block_locs[blk_id].loc.x != OPEN) {
VPR_THROW(VPR_ERROR_PLACE, "The block with ID %d is listed twice in the constraints file.\n", blk_id);
}
}

if (k >= physical_tile->capacity || k < 0) {
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(),
"Block %s subtile number (%d) is out of range.\n", bname, k);
}
place_ctx.grid_blocks[i][j].blocks[k] = bnum;
place_ctx.grid_blocks[i][j].usage++;
//Check if block location is out of range of grid dimensions
if (!is_place_file) {
if (block_x < 0 || block_x > int(device_ctx.grid.width() - 1)
|| block_y < 0 || block_y > int(device_ctx.grid.height() - 1)) {
VPR_THROW(VPR_ERROR_PLACE, "The block with ID %d is out of range at location (%d, %d). \n", blk_id, block_x, block_y);
}
}

constrained_blocks.insert(bnum);
if (place_ctx.block_locs.size() != cluster_ctx.clb_nlist.blocks().size()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

check if we need this. if we do, should be out of the loop

//Resize if needed
place_ctx.block_locs.resize(cluster_ctx.clb_nlist.blocks().size());
}

ptr = vtr::fgets(buf, vtr::bufsize, fp);
}
//Set the location
place_ctx.block_locs[blk_id].loc.x = block_x;
place_ctx.block_locs[blk_id].loc.y = block_y;
place_ctx.block_locs[blk_id].loc.sub_tile = sub_tile_index;

for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
auto result = constrained_blocks.find(blk_id);
if (result == constrained_blocks.end()) {
continue;
}
//need to lock down blocks and mark grid block usage if it is a constraints file
Copy link
Contributor Author

Choose a reason for hiding this comment

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

explain why you need to do this (if place file, initial placement does instead)

if (!is_place_file) {
place_ctx.block_locs[blk_id].is_fixed = true;
place_ctx.grid_blocks[block_x][block_y].blocks[sub_tile_index] = blk_id;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Try setting grid all the time, check that it works

place_ctx.grid_blocks[block_x][block_y].usage++;
}

if (place_ctx.block_locs[blk_id].loc.x == OPEN) {
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, 0,
"Block %s location was not specified in the constraints file.\n", cluster_ctx.clb_nlist.block_name(blk_id).c_str());
} else {
//Unrecognized
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno,
"Invalid line '%s' in placement file",
line.c_str());
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

add in check for place file to see if it has checked all blocks

fclose(fp);
free_hash_table(hash_table);
VTR_LOG("Successfully read %s.\n", constraints_file);
VTR_LOG("\n");
if (!is_place_file) {
VTR_LOG("Successfully read %s.\n", place_file);
VTR_LOG("\n");
}
place_ctx.placement_id = vtr::secure_digest_file(place_file);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a bug; shouldn't generate the signature (used to verify that a routing file uses a compatible placement if we later read in that routing file) for the placement if we're not reading a placement file.

}

/**
Expand Down
8 changes: 5 additions & 3 deletions vpr/src/base/read_place.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#ifndef READ_PLACE_H
#define READ_PLACE_H

void read_place(
void read_place_header(
const char* net_file,
const char* place_file,
bool verify_file_hashes,
const DeviceGrid& grid);

void read_place_body(
const char* place_file,
bool is_place_file);

void print_place(const char* net_file,
const char* net_id,
const char* place_file);

void read_user_block_loc(const char* constraints_file);

#endif
4 changes: 3 additions & 1 deletion vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,9 +661,11 @@ void vpr_load_placement(t_vpr_setup& vpr_setup, const t_arch& arch) {
const auto& device_ctx = g_vpr_ctx.device();
auto& place_ctx = g_vpr_ctx.mutable_placement();
const auto& filename_opts = vpr_setup.FileNameOpts;
bool is_a_placement_file = true;

//Load an existing placement from a file
read_place(filename_opts.NetFile.c_str(), filename_opts.PlaceFile.c_str(), filename_opts.verify_file_digests, device_ctx.grid);
read_place_header(filename_opts.NetFile.c_str(), filename_opts.PlaceFile.c_str(), filename_opts.verify_file_digests, device_ctx.grid);
read_place_body(filename_opts.PlaceFile.c_str(), is_a_placement_file);

//Ensure placement macros are loaded so that they can be drawn after placement (e.g. during routing)
place_ctx.pl_macros = alloc_and_load_placement_macros(arch.Directs, arch.num_directs);
Expand Down
5 changes: 3 additions & 2 deletions vpr/src/place/initial_placement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,10 @@ void initial_placement(enum e_pad_loc_type pad_loc_type, const char* constraints
place_ctx.block_locs[blk_id].loc = t_pl_loc();
}

/*Check whether the constraint file is NULL, if it is not read in the block locations from the constraints file here*/
/*Check whether the constraint file is NULL, if not, read in the block locations from the constraints file here*/
if (strlen(constraints_file) != 0) {
read_user_block_loc(constraints_file);
bool is_a_place_file = false; //specifies to read_place_body function that this is a constraints file and should be read as such
read_place_body(constraints_file, is_a_place_file);
}

initial_placement_pl_macros(MAX_NUM_TRIES_TO_PLACE_MACROS_RANDOMLY, free_locations);
Expand Down