Skip to content

legalizer frontend #2615

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 8 commits into from
Jun 19, 2024
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
12 changes: 12 additions & 0 deletions vpr/src/base/CheckSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ void CheckSetup(const t_packer_opts& PackerOpts,
"Packing cannot be timing driven without timing analysis enabled\n");
}

if (PackerOpts.load_flat_placement) {
if (PackerOpts.device_layout == "auto") {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Legalization requires a fixed device layout.\n");
}
if (!PlacerOpts.constraints_file.empty()) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Cannot specify a fixed clusters file when running legalization.\n");
}
}


if ((GLOBAL == RouterOpts.route_type)
&& (PlacerOpts.place_algorithm.is_timing_driven())) {
/* Works, but very weird. Can't optimize timing well, since you're
Expand Down
5 changes: 3 additions & 2 deletions vpr/src/base/SetupGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
#include "physical_types.h"

///@brief Find the device satisfying the specified minimum resources
/// minimum_instance_counts and target_device_utilization are not required when specifying a fixed layout
DeviceGrid create_device_grid(const std::string& layout_name,
const std::vector<t_grid_def>& grid_layouts,
const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts,
float target_device_utilization);
const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts = {},
float target_device_utilization = 0.0);

///@brief Find the device close in size to the specified dimensions
DeviceGrid create_device_grid(const std::string& layout_name,
Expand Down
9 changes: 9 additions & 0 deletions vpr/src/base/SetupVPR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void SetupVPR(const t_options* Options,
FileNameOpts->ArchFile = Options->ArchFile;
FileNameOpts->CircuitFile = Options->CircuitFile;
FileNameOpts->NetFile = Options->NetFile;
FileNameOpts->FlatPlaceFile = Options->FlatPlaceFile;
FileNameOpts->PlaceFile = Options->PlaceFile;
FileNameOpts->RouteFile = Options->RouteFile;
FileNameOpts->ActFile = Options->ActFile;
Expand All @@ -136,6 +137,8 @@ void SetupVPR(const t_options* Options,
FileNameOpts->out_file_prefix = Options->out_file_prefix;
FileNameOpts->read_vpr_constraints_file = Options->read_vpr_constraints_file;
FileNameOpts->write_vpr_constraints_file = Options->write_vpr_constraints_file;
FileNameOpts->write_constraints_file = Options->write_constraints_file;
FileNameOpts->write_flat_place_file = Options->write_flat_place_file;
FileNameOpts->write_block_usage = Options->write_block_usage;

FileNameOpts->verify_file_digests = Options->verify_file_digests;
Expand Down Expand Up @@ -239,6 +242,7 @@ void SetupVPR(const t_options* Options,
//Setup the default flow, if no specific stages specified
//do all
if (!Options->do_packing
&& !Options->do_legalize
&& !Options->do_placement
&& !Options->do_routing
&& !Options->do_analysis) {
Expand Down Expand Up @@ -275,6 +279,11 @@ void SetupVPR(const t_options* Options,
if (Options->do_packing) {
PackerOpts->doPacking = STAGE_DO;
}

if (Options->do_legalize) {
PackerOpts->doPacking = STAGE_LOAD;
PackerOpts->load_flat_placement = true;
}
}

ShowSetup(*vpr_setup);
Expand Down
3 changes: 3 additions & 0 deletions vpr/src/base/echo_files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ void alloc_and_load_echo_file_info() {
//Packing
setEchoFileName(E_ECHO_CLUSTERS, "clusters.echo");

//Legalizer
setEchoFileName(E_ECHO_FLAT_PLACE, "post_legalizer_flat_placement.echo");

//Intra-block routing
setEchoFileName(E_ECHO_INTRA_LB_FAILED_ROUTE, "intra_lb_failed_route.echo");

Expand Down
3 changes: 3 additions & 0 deletions vpr/src/base/echo_files.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ enum e_echo_files {
//Packing
E_ECHO_CLUSTERS,

//Legalizer
E_ECHO_FLAT_PLACE,

// Intra-block routing
E_ECHO_INTRA_LB_FAILED_ROUTE,

Expand Down
55 changes: 55 additions & 0 deletions vpr/src/base/load_flat_place.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "globals.h"
#include "load_flat_place.h"
#include "clustered_netlist_utils.h"


/* @brief Prints flat placement file entries for the atoms in one placed cluster. */
static void print_flat_cluster(FILE* fp, ClusterBlockId iblk,
std::vector<AtomBlockId>& atoms);

static void print_flat_cluster(FILE* fp, ClusterBlockId iblk,
std::vector<AtomBlockId>& atoms) {

auto& atom_ctx = g_vpr_ctx.atom();
t_pl_loc loc = g_vpr_ctx.placement().block_locs[iblk].loc;
size_t bnum = size_t(iblk);

for (auto atom : atoms) {
t_pb_graph_node* atom_pbgn = atom_ctx.lookup.atom_pb(atom)->pb_graph_node;
fprintf(fp, "%s %d %d %d %d #%zu %s\n", atom_ctx.nlist.block_name(atom).c_str(),
loc.x, loc.y, loc.sub_tile,
atom_pbgn->flat_site_index,
bnum,
atom_pbgn->pb_type->name);
}
}

/* prints a flat placement file */
void print_flat_placement(const char* flat_place_file) {

FILE* fp;

ClusterAtomsLookup atoms_lookup;
auto& cluster_ctx = g_vpr_ctx.clustering();

if (!g_vpr_ctx.placement().block_locs.empty()) {
fp = fopen(flat_place_file, "w");
for (auto iblk : cluster_ctx.clb_nlist.blocks()) {
auto atoms = atoms_lookup.atoms_in_cluster(iblk);
print_flat_cluster(fp, iblk, atoms);
}
fclose(fp);
}

}

/* ingests and legalizes a flat placement file */
bool load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch) {
VTR_LOG("load_flat_placement(); when implemented, this function:");
VTR_LOG("\n\tLoads flat placement file: %s, ", vpr_setup.FileNameOpts.FlatPlaceFile.c_str());
VTR_LOG("\n\tArch id: %s, ", arch.architecture_id);
VTR_LOG("\n\tPrints clustered netlist file: %s, ", vpr_setup.FileNameOpts.NetFile.c_str());
VTR_LOG("\n\tPrints fix clusters file: %s\n", vpr_setup.FileNameOpts.write_constraints_file.c_str());

return false;
}
16 changes: 16 additions & 0 deletions vpr/src/base/load_flat_place.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef LOAD_FLAT_PLACE_H
#define LOAD_FLAT_PLACE_H

#include "vpr_types.h"

/**
* @brief A function that prints a flat placement file
*/
void print_flat_placement(const char* flat_place_file);

/**
* @brief A function that loads and legalizes a flat placement file
*/
bool load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch);

#endif
20 changes: 20 additions & 0 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,11 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.action(argparse::Action::STORE_TRUE)
.default_value("off");

stage_grp.add_argument<bool, ParseOnOff>(args.do_legalize, "--legalize")
.help("Legalize a flat placement, i.e. reconstruct and place clusters based on a flat placement file, which lists cluster and intra-cluster placement coordinates for each primitive.")
.action(argparse::Action::STORE_TRUE)
.default_value("off");

stage_grp.add_argument<bool, ParseOnOff>(args.do_placement, "--place")
.help("Run placement")
.action(argparse::Action::STORE_TRUE)
Expand Down Expand Up @@ -1590,6 +1595,10 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help("Path to packed netlist file")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.FlatPlaceFile, "--flat_place_file")
.help("Path to input flat placement file")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.PlaceFile, "--place_file")
.help("Path to placement file")
.show_in(argparse::ShowIn::HELP_ONLY);
Expand Down Expand Up @@ -1627,6 +1636,17 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help("Writes out new floorplanning constraints based on current placement to the specified XML file.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.write_constraints_file, "--write_fix_clusters")
.help(
"Output file containing fixed locations of legalized input clusters - does not include clusters without placement coordinates; this file is used during post-legalization placement in order to hold input placement coordinates fixed while VPR places legalizer-generated orphan clusters.")
.default_value("fix_clusters.out")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.write_flat_place_file, "--write_flat_place")
.help(
"VPR's (or reconstructed external) placement solution in flat placement file format; this file lists cluster and intra-cluster placement coordinates for each atom and can be used to reconstruct a clustering and placement solution.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.read_router_lookahead, "--read_router_lookahead")
.help(
"Reads the lookahead data from the specified file instead of computing it.")
Expand Down
4 changes: 4 additions & 0 deletions vpr/src/base/read_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct t_options {
argparse::ArgValue<std::string> ArchFile;
argparse::ArgValue<std::string> CircuitName;
argparse::ArgValue<std::string> NetFile;
argparse::ArgValue<std::string> FlatPlaceFile;
argparse::ArgValue<std::string> PlaceFile;
argparse::ArgValue<std::string> RouteFile;
argparse::ArgValue<std::string> CircuitFile;
Expand All @@ -30,6 +31,8 @@ struct t_options {
argparse::ArgValue<std::string> write_initial_place_file;
argparse::ArgValue<std::string> read_vpr_constraints_file;
argparse::ArgValue<std::string> write_vpr_constraints_file;
argparse::ArgValue<std::string> write_constraints_file;
argparse::ArgValue<std::string> write_flat_place_file;

argparse::ArgValue<std::string> write_placement_delay_lookup;
argparse::ArgValue<std::string> read_placement_delay_lookup;
Expand All @@ -44,6 +47,7 @@ struct t_options {

/* Stage Options */
argparse::ArgValue<bool> do_packing;
argparse::ArgValue<bool> do_legalize;
argparse::ArgValue<bool> do_placement;
argparse::ArgValue<bool> do_routing;
argparse::ArgValue<bool> do_analysis;
Expand Down
21 changes: 14 additions & 7 deletions vpr/src/base/read_place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ void read_place_body(std::ifstream& placement_file,
*/
void print_place(const char* net_file,
const char* net_id,
const char* place_file) {
const char* place_file,
bool is_place_file) {
FILE* fp;

auto& device_ctx = g_vpr_ctx.device();
Expand All @@ -318,15 +319,21 @@ void print_place(const char* net_file,

fp = fopen(place_file, "w");

fprintf(fp, "Netlist_File: %s Netlist_ID: %s\n",
net_file,
net_id);
fprintf(fp, "Array size: %zu x %zu logic blocks\n\n", device_ctx.grid.width(), device_ctx.grid.height());
fprintf(fp, "#block name\tx\ty\tsubblk\tlayer\tblock number\n");
fprintf(fp, "#----------\t--\t--\t------\t-----\t------------\n");
if (is_place_file) {
fprintf(fp, "Netlist_File: %s Netlist_ID: %s\n",
net_file,
net_id);
fprintf(fp, "Array size: %zu x %zu logic blocks\n\n", device_ctx.grid.width(), device_ctx.grid.height());
fprintf(fp, "#block name\tx\ty\tsubblk\tlayer\tblock number\n");
fprintf(fp, "#----------\t--\t--\t------\t-----\t------------\n");
}

if (!place_ctx.block_locs.empty()) { //Only if placement exists
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
// if block is not placed, skip (useful for printing legalizer output)
if (!is_place_file && (place_ctx.block_locs[blk_id].loc.x == INVALID_X)) {
continue;
}
fprintf(fp, "%s\t", cluster_ctx.clb_nlist.block_pb(blk_id)->name);
if (strlen(cluster_ctx.clb_nlist.block_pb(blk_id)->name) < 8)
fprintf(fp, "\t");
Expand Down
13 changes: 12 additions & 1 deletion vpr/src/base/read_place.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,19 @@ void read_place(
*/
void read_constraints(const char* constraints_file);

/**
* This function prints out a place file.
* @param is_place_file: defaults to true. If false, does not print file header; this is useful if
* the output will be used as a constraints file. If is_place_file is false,
* net_file and net_id parameters are not used and can be set to nullptr.
* Note: if false, only placed clusters are printed - clusters without
* placement coordinates (e.g. orphan clusters created during legalization
* will not be included; this file is used as a placement constraints
* file when running placement in order to place orphan clusters.
*/
void print_place(const char* net_file,
const char* net_id,
const char* place_file);
const char* place_file,
bool is_place_file = true);

#endif
67 changes: 63 additions & 4 deletions vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
#include "log.h"
#include "iostream"

#include "load_flat_place.h"

#ifdef VPR_USE_TBB
# define TBB_PREVIEW_GLOBAL_CONTROL 1 /* Needed for compatibility with old TBB versions */
# include <tbb/task_arena.h>
Expand Down Expand Up @@ -393,6 +395,7 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
return false; //Unimplementable
}
}

// For the time being, we decided to create the flat graph after placement is done. Thus, the is_flat parameter for this function
//, since it is called before routing, should be false.
vpr_create_device(vpr_setup, arch, false);
Expand Down Expand Up @@ -595,6 +598,9 @@ bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) {
if (packer_opts.doPacking == STAGE_DO) {
//Do the actual packing
status = vpr_pack(vpr_setup, arch);
if (!status) {
return status;
}

//TODO: to be consistent with placement/routing vpr_pack should really
// load the netlist data structures itself, instead of re-loading
Expand All @@ -604,10 +610,25 @@ bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) {
vpr_load_packing(vpr_setup, arch);
} else {
VTR_ASSERT(packer_opts.doPacking == STAGE_LOAD);
//Load a previous packing from the .net file
vpr_load_packing(vpr_setup, arch);
//Load cluster_constraints data structure here since loading pack file
load_cluster_constraints();

// generate a .net file by legalizing an input flat placement file
if (packer_opts.load_flat_placement) {

//Load and legalizer flat placement file
vpr_load_flat_placement(vpr_setup, arch);

//Load the result from the .net file
vpr_load_packing(vpr_setup, arch);

} else {

//Load a previous packing from the .net file
vpr_load_packing(vpr_setup, arch);

//Load cluster_constraints data structure here since loading pack file
load_cluster_constraints();
}

}

/* Sanity check the resulting netlist */
Expand Down Expand Up @@ -709,6 +730,37 @@ void vpr_load_packing(t_vpr_setup& vpr_setup, const t_arch& arch) {
}
}

bool vpr_load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch) {

// set up the device grid for the legalizer
auto& device_ctx = g_vpr_ctx.mutable_device();
device_ctx.arch = &arch;
device_ctx.grid = create_device_grid(vpr_setup.device_layout, arch.grid_layouts);
if (device_ctx.grid.get_num_layers() > 1) {
VPR_FATAL_ERROR(VPR_ERROR_PACK, "Legalizer currently only supports single layer devices.\n");
}

// load and legalize flat placement file, print .net and fix clusters files
bool status = load_flat_placement(vpr_setup, arch);
if (!status) {
return status;
}

// echo flat placement (orphan clusters will have -1 for X, Y, subtile coordinates)
if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_FLAT_PLACE)) {
print_flat_placement(getEchoFileName(E_ECHO_FLAT_PLACE));
}

// reset the device grid
device_ctx.grid.clear();

// if running placement, use the fix clusters file produced by the legalizer
if (vpr_setup.PlacerOpts.doPlacement) {
vpr_setup.PlacerOpts.constraints_file = vpr_setup.FileNameOpts.write_constraints_file;
}
return true;
}

bool vpr_place_flow(const Netlist<>& net_list, t_vpr_setup& vpr_setup, const t_arch& arch) {
VTR_LOG("\n");
const auto& placer_opts = vpr_setup.PlacerOpts;
Expand Down Expand Up @@ -737,6 +789,13 @@ bool vpr_place_flow(const Netlist<>& net_list, t_vpr_setup& vpr_setup, const t_a
placer_opts.floorplan_num_horizontal_partitions, placer_opts.floorplan_num_vertical_partitions);
}

// Write out a flat placement file if the option is specified
// A flat placement file includes cluster and intra-cluster placement coordinates for
// each primitive and can be used to reconstruct a clustering and placement solution.
if (!filename_opts.write_flat_place_file.empty()) {
print_flat_placement(vpr_setup.FileNameOpts.write_flat_place_file.c_str());
}

return true;
}

Expand Down
Loading