Skip to content

[AP][FullLegalizer] Basic Min. Disturbance Full Legalizer #2921

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 7 commits into from
Mar 10, 2025
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
91 changes: 82 additions & 9 deletions vpr/src/analytical_place/analytical_placement_flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,83 @@ static void print_ap_netlist_stats(const APNetlist& netlist) {
VTR_LOG("\n");
}

/**
* @brief Passes the flat placement information to a provided partial placement.
*
* @param flat_placement_info The flat placement information to be read.
* @param ap_netlist The APNetlist that used to iterate over its blocks.
* @param prepacker The Prepacker to get molecule of blocks in the ap_netlist.
* @param p_placement The partial placement to be updated which is assumend
* to be generated on ap_netlist or have the same blocks.
*/
static void convert_flat_to_partial_placement(const FlatPlacementInfo& flat_placement_info, const APNetlist& ap_netlist, const Prepacker& prepacker, PartialPlacement& p_placement){
for (APBlockId ap_blk_id : ap_netlist.blocks()) {
// Get the molecule that AP block represents
PackMoleculeId mol_id = ap_netlist.block_molecule(ap_blk_id);
const t_pack_molecule& mol = prepacker.get_molecule(mol_id);
// Get location of a valid atom in the molecule and verify that
// all atoms of the molecule share same placement information.
float atom_loc_x, atom_loc_y, atom_loc_layer;
int atom_loc_sub_tile;
bool found_valid_atom = false;
for (AtomBlockId atom_blk_id: mol.atom_block_ids) {
if (!atom_blk_id.is_valid())
continue;
float current_loc_x = flat_placement_info.blk_x_pos[atom_blk_id];
float current_loc_y = flat_placement_info.blk_y_pos[atom_blk_id];
float current_loc_layer = flat_placement_info.blk_layer[atom_blk_id];
int current_loc_sub_tile = flat_placement_info.blk_sub_tile[atom_blk_id];
if (found_valid_atom) {
if (current_loc_x != atom_loc_x || current_loc_y != atom_loc_y || current_loc_layer != atom_loc_layer || current_loc_sub_tile != atom_loc_sub_tile)
VPR_FATAL_ERROR(VPR_ERROR_AP, "Molecule of ID %zu contains atom %s (ID: %zu) with a location (%g, %g, layer: %g, subtile: %d) "
"that conflicts the location of other atoms in this molecule of (%g, %g, layer: %g, subtile: %d).",
mol_id, g_vpr_ctx.atom().netlist().block_name(atom_blk_id).c_str(), atom_blk_id,
current_loc_x, current_loc_y, current_loc_layer, current_loc_sub_tile,
atom_loc_x, atom_loc_y, atom_loc_layer, atom_loc_sub_tile);
} else {
atom_loc_x = current_loc_x;
atom_loc_y = current_loc_y;
atom_loc_layer = current_loc_layer;
atom_loc_sub_tile = current_loc_sub_tile;
found_valid_atom = true;
}
}
// Ensure that there is a valid atom in the molecule to pass its location.
VTR_ASSERT_MSG(found_valid_atom, "Each molecule must contain at least one valid atom");
// Pass the placement information
p_placement.block_x_locs[ap_blk_id] = atom_loc_x;
p_placement.block_y_locs[ap_blk_id] = atom_loc_y;
p_placement.block_layer_nums[ap_blk_id] = atom_loc_layer;
p_placement.block_sub_tiles[ap_blk_id] = atom_loc_sub_tile;
}
}

/**
* @brief If a flat placement is provided, skips the Global Placer and
* converts it to a partial placement. Otherwise, runs the Global Placer.
*/
static PartialPlacement run_global_placer(const AtomNetlist& atom_nlist, const APNetlist& ap_netlist, const Prepacker& prepacker, const DeviceContext& device_ctx) {
if (g_vpr_ctx.atom().flat_placement_info().valid) {
VTR_LOG("Flat Placement is provided in the AP flow, skipping the Global Placement.\n");
PartialPlacement p_placement(ap_netlist);
convert_flat_to_partial_placement(g_vpr_ctx.atom().flat_placement_info(),
ap_netlist,
prepacker,
p_placement);
return p_placement;
} else {
// Run the Global Placer
std::unique_ptr<GlobalPlacer> global_placer = make_global_placer(e_global_placer::SimPL,
ap_netlist,
prepacker,
atom_nlist,
device_ctx.grid,
device_ctx.logical_block_types,
device_ctx.physical_tile_types);
return global_placer->place();
}
}

void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
// Start an overall timer for the Analytical Placement flow.
vtr::ScopedStartFinishTimer timer("Analytical Placement");
Expand All @@ -78,15 +155,11 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
constraints);
print_ap_netlist_stats(ap_netlist);

// Run the Global Placer
std::unique_ptr<GlobalPlacer> global_placer = make_global_placer(e_global_placer::SimPL,
ap_netlist,
prepacker,
atom_nlist,
device_ctx.grid,
device_ctx.logical_block_types,
device_ctx.physical_tile_types);
PartialPlacement p_placement = global_placer->place();
// Run the Global Placer.
PartialPlacement p_placement = run_global_placer(atom_nlist,
ap_netlist,
prepacker,
device_ctx);

// Verify that the partial placement is valid before running the full
// legalizer.
Expand Down
3 changes: 2 additions & 1 deletion vpr/src/analytical_place/ap_flow_enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*/
enum class e_ap_full_legalizer {
Naive, ///< The Naive Full Legalizer, which clusters atoms placed in the same tile and tries to place them in that tile according to the flat placement.
APPack ///< The APPack Full Legalizer, which uses the flat placement to improve the Packer and Placer.
APPack, ///< The APPack Full Legalizer, which uses the flat placement to improve the Packer and Placer.
Basic_Min_Disturbance ///< The Basic Min. Disturbance Full Legalizer, which tries to reconstruct a clustered placement that is as close to the incoming flat placement as it can.
};

/**
Expand Down
5 changes: 5 additions & 0 deletions vpr/src/analytical_place/full_legalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ std::unique_ptr<FullLegalizer> make_full_legalizer(e_ap_full_legalizer full_lega
vpr_setup,
arch,
device_grid);
case e_ap_full_legalizer::Basic_Min_Disturbance:
VTR_LOG("Basic Minimum Disturbance Full Legalizer selected!\n");
VPR_FATAL_ERROR(VPR_ERROR_AP,
"Basic Min. Disturbance Full Legalizer has not been implemented yet.");

default:
VPR_FATAL_ERROR(VPR_ERROR_AP,
"Unrecognized full legalizer type");
Expand Down
3 changes: 3 additions & 0 deletions vpr/src/base/ShowSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,9 @@ static void ShowAnalyticalPlacerOpts(const t_ap_opts& APOpts) {
case e_ap_full_legalizer::APPack:
VTR_LOG("appack\n");
break;
case e_ap_full_legalizer::Basic_Min_Disturbance:
VTR_LOG("basic-min-disturbance\n");
break;
default:
VPR_FATAL_ERROR(VPR_ERROR_UNKNOWN, "Unknown full_legalizer_type\n");
}
Expand Down
9 changes: 7 additions & 2 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ struct ParseAPFullLegalizer {
conv_value.set_value(e_ap_full_legalizer::Naive);
else if (str == "appack")
conv_value.set_value(e_ap_full_legalizer::APPack);
else if (str == "basic-min-disturbance")
conv_value.set_value(e_ap_full_legalizer::Basic_Min_Disturbance);
else {
std::stringstream msg;
msg << "Invalid conversion from '" << str << "' to e_ap_full_legalizer (expected one of: " << argparse::join(default_choices(), ", ") << ")";
Expand All @@ -158,14 +160,16 @@ struct ParseAPFullLegalizer {
case e_ap_full_legalizer::APPack:
conv_value.set_value("appack");
break;
case e_ap_full_legalizer::Basic_Min_Disturbance:
conv_value.set_value("basic-min-disturbance");
default:
VTR_ASSERT(false);
}
return conv_value;
}

std::vector<std::string> default_choices() {
return {"naive", "appack"};
return {"naive", "appack", "basic-min-disturbance"};
}
};

Expand Down Expand Up @@ -1822,7 +1826,8 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help(
"Controls which Full Legalizer to use in the AP Flow.\n"
" * naive: Use a Naive Full Legalizer which will try to create clusters exactly where their atoms are placed.\n"
" * appack: Use APPack, which takes the Packer in VPR and uses the flat atom placement to create better clusters.")
" * appack: Use APPack, which takes the Packer in VPR and uses the flat atom placement to create better clusters.\n"
" * basic-min-disturbance: Use the Basic Min. Disturbance Full Legalizer which tries to reconstruct a clustered placement that is as close to the incoming flat placement as possible.\n")
.default_value("appack")
.show_in(argparse::ShowIn::HELP_ONLY);

Expand Down
17 changes: 17 additions & 0 deletions vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,25 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {

{ // Analytical Place
if (vpr_setup.APOpts.doAP == STAGE_DO) {
// Passing flat placement input if provided and not loaded yet.
if (!vpr_setup.FileNameOpts.read_flat_place_file.empty() &&
!g_vpr_ctx.atom().flat_placement_info().valid) {
g_vpr_ctx.mutable_atom().mutable_flat_placement_info() = read_flat_placement(
vpr_setup.FileNameOpts.read_flat_place_file,
g_vpr_ctx.atom().netlist());
}

// TODO: Make this return a bool if the placement was successful or not.
run_analytical_placement_flow(vpr_setup);

// Write out a flat placement file at the end of Analytical Placement
// flow if the option is specified.
if (!vpr_setup.FileNameOpts.write_flat_place_file.empty()) {
write_flat_placement(vpr_setup.FileNameOpts.write_flat_place_file.c_str(),
g_vpr_ctx.clustering().clb_nlist,
g_vpr_ctx.placement().block_locs(),
g_vpr_ctx.clustering().atoms_lookup);
}
}
// Print the placement generated by AP to a .place file.
auto& filename_opts = vpr_setup.FileNameOpts;
Expand Down