diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 3f2ad3413a6..e77c70f5ed6 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -35,7 +35,7 @@ const char* get_arch_file_name() { return arch_file_name; } -InstPort::InstPort(std::string str) { +InstPort::InstPort(const std::string& str) { std::vector inst_port = vtr::split(str, "."); if (inst_port.size() == 1) { diff --git a/libs/libarchfpga/src/arch_util.h b/libs/libarchfpga/src/arch_util.h index 7d882450a5a..f502d6c783a 100644 --- a/libs/libarchfpga/src/arch_util.h +++ b/libs/libarchfpga/src/arch_util.h @@ -22,7 +22,7 @@ class InstPort { static constexpr int UNSPECIFIED = -1; InstPort() = default; - InstPort(std::string str); + InstPort(const std::string& str); std::string instance_name() const { return instance_.name; } std::string port_name() const { return port_.name; } diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index dc98b5f3cc7..359a5410b0c 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -163,7 +163,7 @@ static void ProcessEquivalentSiteCustomConnection(pugi::xml_node Parent, t_sub_tile* SubTile, t_physical_tile_type* PhysicalTileType, t_logical_block_type* LogicalBlockType, - std::string site_name, + const std::string& site_name, const pugiutil::loc_data& loc_data); static void ProcessPinLocations(pugi::xml_node Locations, t_physical_tile_type* PhysicalTileType, @@ -369,7 +369,7 @@ static bool attribute_to_bool(const pugi::xml_node node, static int find_switch_by_name(const t_arch& arch, const std::string& switch_name); -e_side string_to_side(const std::string& side_str); +static e_side string_to_side(const std::string& side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); @@ -1551,10 +1551,10 @@ static void ProcessPb_TypePort_Power(pugi::xml_node Parent, t_port* port, e_powe static void ProcessPb_TypePort(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, const bool is_root_pb_type, const pugiutil::loc_data& loc_data) { std::vector expected_attributes = {"name", "num_pins", "port_class"}; if (is_root_pb_type) { - expected_attributes.push_back("equivalent"); + expected_attributes.emplace_back("equivalent"); if (Parent.name() == "input"s || Parent.name() == "clock"s) { - expected_attributes.push_back("is_non_clock_global"); + expected_attributes.emplace_back("is_non_clock_global"); } } @@ -2815,7 +2815,7 @@ static void ProcessDevice(pugi::xml_node Node, t_arch* arch, t_default_fc_spec& // tag Cur = get_single_child(Node, "connection_block", loc_data); expect_only_attributes(Cur, {"input_switch_name", "input_inter_die_switch_name"}, loc_data); - arch->ipin_cblock_switch_name.push_back(get_attribute(Cur, "input_switch_name", loc_data).as_string()); + arch->ipin_cblock_switch_name.emplace_back(get_attribute(Cur, "input_switch_name", loc_data).as_string()); std::string inter_die_conn = get_attribute(Cur, "input_inter_die_switch_name", loc_data, ReqOpt::OPTIONAL).as_string(""); if (inter_die_conn != "") { arch->ipin_cblock_switch_name.push_back(inter_die_conn); @@ -3212,7 +3212,7 @@ static void ProcessEquivalentSiteCustomConnection(pugi::xml_node Parent, t_sub_tile* SubTile, t_physical_tile_type* PhysicalTileType, t_logical_block_type* LogicalBlockType, - std::string site_name, + const std::string& site_name, const pugiutil::loc_data& loc_data) { pugi::xml_node CurDirect; @@ -3395,7 +3395,7 @@ static void ProcessPinLocations(pugi::xml_node Locations, for (int h = 0; h < PhysicalTileType->height; ++h) { for (e_side side : {TOP, RIGHT, BOTTOM, LEFT}) { for (const auto& token : pin_locs->assignments[sub_tile_index][w][h][l][side]) { - InstPort inst_port(token.c_str()); + InstPort inst_port(token); //A pin specification should contain only the block name, and not any instance count information if (inst_port.instance_low_index() != InstPort::UNSPECIFIED || inst_port.instance_high_index() != InstPort::UNSPECIFIED) { @@ -3746,8 +3746,8 @@ static void ProcessSegments(pugi::xml_node Parent, if (!Segs[i].longline) { //Long line doesn't accpet or since it assumes full population - expected_subtags.push_back("sb"); - expected_subtags.push_back("cb"); + expected_subtags.emplace_back("sb"); + expected_subtags.emplace_back("cb"); } /* Get the type */ @@ -3756,16 +3756,16 @@ static void ProcessSegments(pugi::xml_node Parent, Segs[i].directionality = BI_DIRECTIONAL; //Bidir requires the following tags - expected_subtags.push_back("wire_switch"); - expected_subtags.push_back("opin_switch"); + expected_subtags.emplace_back("wire_switch"); + expected_subtags.emplace_back("opin_switch"); } else if (0 == strcmp(tmp, "unidir")) { Segs[i].directionality = UNI_DIRECTIONAL; //Unidir requires the following tags - expected_subtags.push_back("mux"); - expected_subtags.push_back("mux_inter_die"); + expected_subtags.emplace_back("mux"); + expected_subtags.emplace_back("mux_inter_die"); } else { @@ -3951,8 +3951,6 @@ static void ProcessSwitchblocks(pugi::xml_node Parent, t_arch* arch, const pugiu Node = Node.next_sibling(Node.name()); } - - return; } static void ProcessCB_SB(pugi::xml_node Node, std::vector& list, const pugiutil::loc_data& loc_data) { @@ -4713,7 +4711,7 @@ static int find_switch_by_name(const t_arch& arch, const std::string& switch_nam return OPEN; } -e_side string_to_side(const std::string& side_str) { +static e_side string_to_side(const std::string& side_str) { e_side side = NUM_SIDES; if (side_str.empty()) { side = NUM_SIDES; diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index c446c44a94b..180b60e35bd 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -30,19 +30,6 @@ t_logical_block_type_ptr ClusteredNetlist::block_type(const ClusterBlockId id) c return block_types_[id]; } -const std::vector& ClusteredNetlist::blocks_per_type(const t_logical_block_type& blk_type) const { - // empty vector is declared static to avoid re-allocation every time the function is called - static std::vector empty_vector; - if (blocks_per_type_.count(blk_type.index) == 0) { - return empty_vector; - } - - // the vector is returned as const reference to avoid unnecessary copies, - // especially that returned vectors may be very large as they contain - // all clustered blocks with a specific block type - return blocks_per_type_.at(blk_type.index); -} - ClusterNetId ClusteredNetlist::block_net(const ClusterBlockId blk_id, const int logical_pin_index) const { auto pin_id = block_pin(blk_id, logical_pin_index); @@ -123,8 +110,6 @@ ClusterBlockId ClusteredNetlist::create_block(const char* name, t_pb* pb, t_logi block_pbs_.insert(blk_id, pb); block_types_.insert(blk_id, type); - blocks_per_type_[type->index].push_back(blk_id); - //Allocate and initialize every potential pin of the block block_logical_pins_.insert(blk_id, std::vector(get_max_num_pins(type), ClusterPinId::INVALID())); } @@ -185,14 +170,11 @@ ClusterNetId ClusteredNetlist::create_net(const std::string& name) { } void ClusteredNetlist::remove_block_impl(const ClusterBlockId blk_id) { - //find the block type, so we can remove it from blocks_per_type_ data structure - auto blk_type = block_type(blk_id); //Remove & invalidate pointers free_pb(block_pbs_[blk_id]); delete block_pbs_[blk_id]; block_pbs_.insert(blk_id, NULL); block_types_.insert(blk_id, NULL); - std::remove(blocks_per_type_[blk_type->index].begin(), blocks_per_type_[blk_type->index].end(), blk_id); block_logical_pins_.insert(blk_id, std::vector()); } diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 7a1bd15f28b..43a31cd8267 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -134,9 +134,6 @@ class ClusteredNetlist : public Netlist& blocks_per_type(const t_logical_block_type& blk_type) const; - ///@brief Returns the net of the block attached to the specific pin index ClusterNetId block_net(const ClusterBlockId blk_id, const int pin_index) const; diff --git a/vpr/src/base/read_circuit.cpp b/vpr/src/base/read_circuit.cpp index ac46b3857ac..dd2be16f7cd 100644 --- a/vpr/src/base/read_circuit.cpp +++ b/vpr/src/base/read_circuit.cpp @@ -191,22 +191,22 @@ static void show_circuit_stats(const AtomNetlist& netlist) { //Determine the maximum length of a type name for nice formatting size_t max_block_type_len = 0; - for (auto kv : block_type_counts) { + for (const auto& kv : block_type_counts) { max_block_type_len = std::max(max_block_type_len, kv.first.size()); } size_t max_net_type_len = 0; - for (auto kv : net_stats) { + for (const auto& kv : net_stats) { max_net_type_len = std::max(max_net_type_len, kv.first.size()); } //Print the statistics VTR_LOG("Circuit Statistics:\n"); VTR_LOG(" Blocks: %zu\n", netlist.blocks().size()); - for (auto kv : block_type_counts) { + for (const auto& kv : block_type_counts) { VTR_LOG(" %-*s: %7zu\n", max_block_type_len, kv.first.c_str(), kv.second); } VTR_LOG(" Nets : %zu\n", netlist.nets().size()); - for (auto kv : net_stats) { + for (const auto& kv : net_stats) { VTR_LOG(" %-*s: %7.1f\n", max_net_type_len, kv.first.c_str(), kv.second); } VTR_LOG(" Netlist Clocks: %zu\n", find_netlist_logical_clock_drivers(netlist).size()); diff --git a/vpr/src/base/read_place.cpp b/vpr/src/base/read_place.cpp index 130ec5469e7..f3374e89824 100644 --- a/vpr/src/base/read_place.cpp +++ b/vpr/src/base/read_place.cpp @@ -92,8 +92,12 @@ void read_place_header(std::ifstream& placement_file, bool seen_netlist_id = false; bool seen_grid_dimensions = false; + // store the current position in file + // if an invalid line is read, we might need to return to the beginning of that line + std::streampos file_pos = placement_file.tellg(); + while (std::getline(placement_file, line) && (!seen_netlist_id || !seen_grid_dimensions)) { //Parse line-by-line - ++lineno; + ++lineno; std::vector tokens = vtr::split(line); @@ -103,9 +107,9 @@ void read_place_header(std::ifstream& placement_file, } else if (tokens[0][0] == '#') { continue; //Skip commented lines - } else if (tokens.size() == 4 - && tokens[0] == "Netlist_File:" - && tokens[2] == "Netlist_ID:") { + } else if (tokens.size() == 4 && + tokens[0] == "Netlist_File:" && + tokens[2] == "Netlist_ID:") { //Check that the netlist used to generate this placement matches the one loaded // //NOTE: this is an optional check which causes no errors if this line is missing. @@ -120,45 +124,76 @@ void read_place_header(std::ifstream& placement_file, std::string place_netlist_id = tokens[3]; std::string place_netlist_file = tokens[1]; - if (place_netlist_id != cluster_ctx.clb_nlist.netlist_id().c_str()) { + if (place_netlist_id != cluster_ctx.clb_nlist.netlist_id()) { auto msg = vtr::string_fmt( "The packed netlist file that generated placement (File: '%s' ID: '%s')" " does not match current netlist (File: '%s' ID: '%s')", place_netlist_file.c_str(), place_netlist_id.c_str(), net_file, cluster_ctx.clb_nlist.netlist_id().c_str()); if (verify_file_digests) { + msg += " To ignore the packed netlist mismatch, use '--verify_file_digests off' command line option."; vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, msg.c_str()); } else { VTR_LOGF_WARN(place_file, lineno, "%s\n", msg.c_str()); + VTR_LOG_WARN("The packed netlist mismatch is ignored because" + "--verify_file_digests command line option is off."); } } seen_netlist_id = true; - } else if (tokens.size() == 7 - && tokens[0] == "Array" - && tokens[1] == "size:" - && tokens[3] == "x" - && tokens[5] == "logic" - && tokens[6] == "blocks") { + } else if (tokens.size() == 7 && + tokens[0] == "Array" && + tokens[1] == "size:" && + tokens[3] == "x" && + tokens[5] == "logic" && + tokens[6] == "blocks") { //Load the device grid dimensions 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) { - vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, - "Current FPGA size (%d x %d) is different from size when placement generated (%d x %d)", - grid.width(), grid.height(), place_file_width, place_file_height); + auto msg = vtr::string_fmt( + "Current FPGA size (%d x %d) is different from size when placement generated (%d x %d)", + grid.width(), grid.height(), place_file_width, place_file_height); + if (verify_file_digests) { + msg += " To ignore this size mismatch, use '--verify_file_digests off' command line option."; + vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, msg.c_str()); + } else { + VTR_LOGF_WARN(place_file, lineno, "%s\n", msg.c_str()); + VTR_LOG_WARN("The FPGA size mismatch is ignored because" + "--verify_file_digests command line option is off."); + } } seen_grid_dimensions = true; } else { //Unrecognized - vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, - "Invalid line '%s' in placement file header", - line.c_str()); + auto msg = vtr::string_fmt( + "Invalid line '%s' in placement file header. " + "Expected to see netlist filename and device size first.", + line.c_str()); + + if (verify_file_digests) { + msg += " To ignore this unexpected line, use '--verify_file_digests off' command line option."; + vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, msg.c_str()); + } else { + VTR_LOGF_WARN(place_file, lineno, "%s\n", msg.c_str()); + VTR_LOG_WARN("Unexpected line in the placement file header is ignored because" + "--verify_file_digests command line option is off."); + } + + if ((tokens.size() == 4 || (tokens.size() > 4 && tokens[4][0] == '#')) || + (tokens.size() == 5 || (tokens.size() > 5 && tokens[5][0] == '#'))) { + placement_file.seekg(file_pos); + break; + } } + + // store the current position in the file before reading the next line + // we might need to return to this position + file_pos = placement_file.tellg(); } } @@ -200,7 +235,8 @@ void read_place_body(std::ifstream& placement_file, } else if (tokens[0][0] == '#') { continue; //Skip commented lines - } else if ((tokens.size() == 4 || (tokens.size() > 4 && tokens[4][0] == '#')) || (tokens.size() == 5 || (tokens.size() > 5 && tokens[5][0] == '#'))) { + } else if ((tokens.size() == 4 || (tokens.size() > 4 && tokens[4][0] == '#')) || + (tokens.size() == 5 || (tokens.size() > 5 && tokens[5][0] == '#'))) { //Load the block location // // If the place file corresponds to a 3D architecture, it should contain 5 tokens of actual data, with an optional 6th (commented) token indicating VPR's internal block number. @@ -250,7 +286,10 @@ void read_place_body(std::ifstream& placement_file, //Check if block is listed multiple times with conflicting locations in constraints file if (seen_blocks[blk_id] > 0) { - if (block_x != place_ctx.block_locs[blk_id].loc.x || block_y != place_ctx.block_locs[blk_id].loc.y || sub_tile_index != place_ctx.block_locs[blk_id].loc.sub_tile || block_layer != place_ctx.block_locs[blk_id].loc.layer) { + if (block_x != place_ctx.block_locs[blk_id].loc.x || + block_y != place_ctx.block_locs[blk_id].loc.y || + sub_tile_index != place_ctx.block_locs[blk_id].loc.sub_tile || + block_layer != place_ctx.block_locs[blk_id].loc.layer) { std::string cluster_name = cluster_ctx.clb_nlist.block_name(blk_id); VPR_THROW(VPR_ERROR_PLACE, "The location of cluster %s (#%d) is specified %d times in the constraints file with conflicting locations. \n" diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 1294cc80836..fac75c5fbb3 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -13,17 +13,13 @@ #include #include -#include -#include #include -#include #include "vtr_assert.h" #include "vtr_math.h" #include "vtr_log.h" #include "vtr_version.h" #include "vtr_time.h" -#include "vtr_path.h" #include "vpr_types.h" #include "vpr_utils.h" @@ -44,15 +40,12 @@ #include "stats.h" #include "read_options.h" #include "echo_files.h" -#include "read_xml_arch_file.h" #include "SetupVPR.h" #include "ShowSetup.h" #include "CheckArch.h" #include "CheckSetup.h" #include "rr_graph.h" #include "pb_type_graph.h" -#include "route_common.h" -#include "timing_place_lookup.h" #include "route.h" #include "route_export.h" #include "vpr_api.h" @@ -65,7 +58,6 @@ #include "concrete_timing_info.h" #include "netlist_writer.h" #include "AnalysisDelayCalculator.h" -#include "RoutingDelayCalculator.h" #include "check_route.h" #include "constant_nets.h" #include "atom_netlist_utils.h" @@ -86,15 +78,12 @@ #include "tatum/echo_writer.hpp" #include "read_route.h" -#include "read_blif.h" #include "read_place.h" #include "arch_util.h" #include "post_routing_pb_pin_fixup.h" -#include "log.h" -#include "iostream" #include "load_flat_place.h" @@ -410,7 +399,6 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) { bool place_success = vpr_place_flow(placement_net_list, vpr_setup, arch); if (!place_success) { - std::cout << "failed placement" << std::endl; return false; //Unimplementable } } @@ -1463,7 +1451,7 @@ bool vpr_analysis_flow(const Netlist<>& net_list, Arch.architecture_id, post_routing_packing_output_file_name.c_str()); } else { - VTR_LOG_WARN("Sychronization between packing and routing results is not applied due to illegal circuit implementation\n"); + VTR_LOG_WARN("Synchronization between packing and routing results is not applied due to illegal circuit implementation\n"); } VTR_LOG("\n"); } diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index b6ccba2d4d9..310cac8877a 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -348,7 +348,7 @@ struct ClusteringHelperContext : public Context { t_ext_pin_util_targets target_external_pin_util; // During clustering, a block is related to un-clustered primitives with nets. - // This relation has three types: low fanout, high fanout, and trasitive + // This relation has three types: low fanout, high fanout, and transitive // high_fanout_thresholds stores the threshold for nets to a block type to be considered high fanout t_pack_high_fanout_thresholds high_fanout_thresholds; @@ -395,6 +395,12 @@ struct PlacementContext : public Context { ///@brief The pl_macros array stores all the placement macros (usually carry chains). std::vector pl_macros; + ///@brief Stores ClusterBlockId of all movable clustered blocks (blocks that are not locked down to a single location) + std::vector movable_blocks; + + ///@brief Stores ClusterBlockId of all movable clustered of each block type + std::vector> movable_blocks_per_type; + /** * @brief Compressed grid space for each block type * diff --git a/vpr/src/place/initial_placement.cpp b/vpr/src/place/initial_placement.cpp index 109dd16013c..8e7a634befa 100644 --- a/vpr/src/place/initial_placement.cpp +++ b/vpr/src/place/initial_placement.cpp @@ -219,9 +219,15 @@ static void place_all_blocks(const t_placer_opts& placer_opts, */ static void check_initial_placement_legality(); +/** + * @brief Fills movable_blocks in global PlacementContext + */ +static void alloc_and_load_movable_blocks(); + static void check_initial_placement_legality() { auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.placement(); + auto& device_ctx = g_vpr_ctx.device(); int unplaced_blocks = 0; @@ -242,6 +248,28 @@ static void check_initial_placement_legality() { "If VPR was run with floorplan constraints, the constraints may be too tight.\n", unplaced_blocks); } + + for (auto movable_blk_id : place_ctx.movable_blocks) { + if (place_ctx.block_locs[movable_blk_id].is_fixed) { + VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Fixed block was mistakenly marked as movable during initial placement.\n"); + } + } + + for (const auto& logical_block_type : device_ctx.logical_block_types) { + const auto& movable_blocks_of_type = place_ctx.movable_blocks_per_type[logical_block_type.index]; + for (const auto& movable_blk_id : movable_blocks_of_type) { + if (place_ctx.block_locs[movable_blk_id].is_fixed) { + VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Fixed block %d of logical type %s was mistakenly marked as movable during initial placement.\n", + (size_t)movable_blk_id, logical_block_type.name); + } + if (cluster_ctx.clb_nlist.block_type(movable_blk_id)->index != logical_block_type.index) { + VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Clustered block %d of logical type %s was mistakenly marked as logical type %s.\n", + (size_t)movable_blk_id, + cluster_ctx.clb_nlist.block_type(movable_blk_id)->name, + logical_block_type.name); + } + } + } } bool is_block_placed(ClusterBlockId blk_id) { @@ -1124,6 +1152,30 @@ bool place_one_block(const ClusterBlockId& blk_id, return placed_macro; } +static void alloc_and_load_movable_blocks() { + auto& place_ctx = g_vpr_ctx.mutable_placement(); + const auto& cluster_ctx = g_vpr_ctx.clustering(); + const auto& device_ctx = g_vpr_ctx.device(); + + place_ctx.movable_blocks.clear(); + place_ctx.movable_blocks_per_type.clear(); + + size_t n_logical_blocks = device_ctx.logical_block_types.size(); + place_ctx.movable_blocks_per_type.resize(n_logical_blocks); + + + // iterate over all clustered blocks and store block ids of movable ones + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + const auto& loc = place_ctx.block_locs[blk_id]; + if (!loc.is_fixed) { + place_ctx.movable_blocks.push_back(blk_id); + + const t_logical_block_type_ptr block_type = cluster_ctx.clb_nlist.block_type(blk_id); + place_ctx.movable_blocks_per_type[block_type->index].push_back(blk_id); + } + } +} + void initial_placement(const t_placer_opts& placer_opts, const char* constraints_file, const t_noc_opts& noc_opts) { @@ -1140,7 +1192,7 @@ void initial_placement(const t_placer_opts& placer_opts, propagate_place_constraints(); /*Mark the blocks that have already been locked to one spot via floorplan constraints - * as fixed so they do not get moved during initial placement or later during the simulated annealing stage of placement*/ + * as fixed, so they do not get moved during initial placement or later during the simulated annealing stage of placement*/ mark_fixed_blocks(); @@ -1161,6 +1213,8 @@ void initial_placement(const t_placer_opts& placer_opts, //Place all blocks place_all_blocks(placer_opts, block_scores, placer_opts.pad_loc_type, constraints_file); + alloc_and_load_movable_blocks(); + // ensure all blocks are placed and that NoC routing has no cycles check_initial_placement_legality(); diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 3ec00c26970..4a9c280b77c 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -226,7 +226,7 @@ e_block_move_result record_macro_swaps(t_pl_blocks_to_be_moved& blocks_affected, //to a new position offset from its current position by swap_offset. The new location must be where //blk_to is located and blk_to must be part of imacro_to. e_block_move_result record_macro_macro_swaps(t_pl_blocks_to_be_moved& blocks_affected, const int imacro_from, int& imember_from, const int imacro_to, ClusterBlockId blk_to, t_pl_offset swap_offset) { - //Adds the macro imacro_to to the set of affected block caused by swapping 'blk_to' to it's + //Adds the macro imacro_to to the set of affected block caused by swapping 'blk_to' to its //new position. // //This function is only called when both the main swap's from/to blocks are placement macros. @@ -489,7 +489,7 @@ std::set determine_locations_emptied_by_move(t_pl_blocks_to_be_moved& std::set moved_to; for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; ++iblk) { - //When a block is moved it's old location becomes free + //When a block is moved its old location becomes free moved_from.emplace(blocks_affected.moved_blocks[iblk].old_loc); //But any block later moved to a position fills it @@ -595,81 +595,47 @@ ClusterBlockId propose_block_to_move(const t_placer_opts& /* placer_opts */, return b_from; } -//Pick a random block to be swapped with another random block. +const std::vector& movable_blocks_per_type(const t_logical_block_type& blk_type) { + const auto& place_ctx = g_vpr_ctx.placement(); + + // the vector is returned as const reference to avoid unnecessary copies, + // especially that returned vectors may be very large as they contain + // all clustered blocks with a specific block type + return place_ctx.movable_blocks_per_type[blk_type.index]; +} + +//Pick a random movable block to be swapped with another random block. //If none is found return ClusterBlockId::INVALID() ClusterBlockId pick_from_block() { - /* Some blocks may be fixed, and should never be moved from their * - * initial positions. If we randomly selected such a block try * - * another random block. * - * * - * We need to track the blocks we have tried to avoid an infinite * - * loop if all blocks are fixed. */ - auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.mutable_placement(); - std::unordered_set tried_from_blocks; - - //Keep selecting random blocks as long as there are any untried blocks - //Can get slow if there are many blocks but only a few (or none) can move - while (tried_from_blocks.size() < cluster_ctx.clb_nlist.blocks().size()) { - //Pick a block at random - ClusterBlockId b_from = ClusterBlockId(vtr::irand((int)cluster_ctx.clb_nlist.blocks().size() - 1)); - - //Record it as tried - tried_from_blocks.insert(b_from); + // get the number of movable clustered blocks + const size_t n_movable_blocks = place_ctx.movable_blocks.size(); - if (place_ctx.block_locs[b_from].is_fixed) { - continue; //Fixed location, try again - } - - //Found a movable block + if (n_movable_blocks > 0) { + //Pick a movable block at random and return it + auto b_from = ClusterBlockId(vtr::irand((int)n_movable_blocks - 1)); return b_from; + } else { + //No movable blocks found + return ClusterBlockId::INVALID(); } - - //No movable blocks found - return ClusterBlockId::INVALID(); } -//Pick a random block with a specific blk_type to be swapped with another random block. +//Pick a random movable block with a specific blk_type to be swapped with another random block. //If none is found return ClusterBlockId::INVALID() ClusterBlockId pick_from_block(const int logical_blk_type_index) { - /* Some blocks may be fixed, and should never be moved from their * - * initial positions. If we randomly selected such a block try * - * another random block. * - * * - * We need to track the blocks we have tried to avoid an infinite * - * loop if all blocks are fixed. */ - auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.mutable_placement(); - t_logical_block_type blk_type_temp; - blk_type_temp.index = logical_blk_type_index; - const auto& blocks_per_type = cluster_ctx.clb_nlist.blocks_per_type(blk_type_temp); - //no blocks with this type is available - if (blocks_per_type.empty()) { + const auto& movable_blocks_of_type = place_ctx.movable_blocks_per_type[logical_blk_type_index]; + + if (movable_blocks_of_type.empty()) { return ClusterBlockId::INVALID(); } - std::unordered_set tried_from_blocks; - - //Keep selecting random blocks as long as there are any untried blocks with type "blk_type" - //Can get slow if there are many blocks but only a few (or none) can move - while (tried_from_blocks.size() < blocks_per_type.size()) { - //Pick a block at random - ClusterBlockId b_from = ClusterBlockId(blocks_per_type[vtr::irand((int)blocks_per_type.size() - 1)]); - //Record it as tried - tried_from_blocks.insert(b_from); - - if (place_ctx.block_locs[b_from].is_fixed) { - continue; //Fixed location, try again - } - //Found a movable block - return b_from; - } + auto b_from = ClusterBlockId(movable_blocks_of_type[vtr::irand((int)movable_blocks_of_type.size() - 1)]); - //No movable blocks found - //Unreachable statement - return ClusterBlockId::INVALID(); + return b_from; } //Pick a random highly critical block to be swapped with another random block. @@ -1084,9 +1050,9 @@ bool find_compatible_compressed_loc_in_range(t_logical_block_type_ptr type, else possibilities = delta_cx; - while (!legal && (int)tried_cx_to.size() < possibilities) { //Until legal or all possibilities exhaused + while (!legal && (int)tried_cx_to.size() < possibilities) { //Until legal or all possibilities exhausted //Pick a random x-location within [min_cx, max_cx], - //until we find a legal swap, or have exhuasted all possiblites + //until we find a legal swap, or have exhausted all possibilities to_loc.x = search_range.xmin + vtr::irand(delta_cx); VTR_ASSERT(to_loc.x >= search_range.xmin); diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index 24bdfcb7ebc..0977a40946a 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -7,7 +7,7 @@ /* Cut off for incremental bounding box updates. * * 4 is fastest -- I checked. */ /* To turn off incremental bounding box updates, set this to a huge value */ -#define SMALL_NET 4 +constexpr size_t SMALL_NET = 4; /* This is for the placement swap routines. A swap attempt could be * * rejected, accepted or aborted (due to the limitations placed on the * @@ -129,6 +129,13 @@ ClusterBlockId propose_block_to_move(const t_placer_opts& placer_opts, ClusterNetId* net_from, int* pin_from); +/** + * Returns all movable clustered blocks with a specified logical block type. + * @param blk_type Specifies the logical block block type. + * @return A const reference to a vector containing all movable blocks with the specified logical block type. + */ +const std::vector& movable_blocks_per_type(const t_logical_block_type& blk_type); + /** * @brief Select a random block to be swapped with another block * diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 357b8532016..a38d5f442d9 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -647,9 +647,6 @@ void try_place(const Netlist<>& net_list, move_lim = (int)(annealing_sched.inner_num * pow(net_list.blocks().size(), 1.3333)); - //create the move generator based on the chosen strategy - create_move_generators(move_generator, move_generator2, placer_opts, move_lim, noc_opts.noc_centroid_weight); - alloc_and_load_placement_structs(placer_opts.place_cost_exp, placer_opts, noc_opts, directs, num_directs); vtr::ScopedStartFinishTimer timer("Placement"); @@ -662,6 +659,9 @@ void try_place(const Netlist<>& net_list, placer_opts.constraints_file.c_str(), noc_opts); + //create the move generator based on the chosen strategy + create_move_generators(move_generator, move_generator2, placer_opts, move_lim, noc_opts.noc_centroid_weight); + if (!placer_opts.write_initial_place_file.empty()) { print_place(nullptr, nullptr, @@ -4411,14 +4411,13 @@ static void print_placement_move_types_stats(const MoveTypeStat& move_type_stat) auto& device_ctx = g_vpr_ctx.device(); - auto& cluster_ctx = g_vpr_ctx.clustering(); int count = 0; int num_of_avail_moves = move_type_stat.blk_type_moves.size() / device_ctx.logical_block_types.size(); //Print placement information for each block type for (const auto& itype : device_ctx.logical_block_types) { //Skip non-existing block types in the netlist - if (itype.index == 0 || cluster_ctx.clb_nlist.blocks_per_type(itype).empty()) { + if (itype.index == 0 || movable_blocks_per_type(itype).empty()) { continue; } diff --git a/vpr/src/place/simpleRL_move_generator.cpp b/vpr/src/place/simpleRL_move_generator.cpp index 172178f49ce..45e43e05762 100644 --- a/vpr/src/place/simpleRL_move_generator.cpp +++ b/vpr/src/place/simpleRL_move_generator.cpp @@ -85,8 +85,7 @@ int KArmedBanditAgent::action_to_blk_type_(const size_t action_idx) { } std::vector KArmedBanditAgent::get_available_logical_blk_types_() { - auto& device_ctx = g_vpr_ctx.device(); - auto& cluster_ctx = g_vpr_ctx.clustering(); + const auto& device_ctx = g_vpr_ctx.device(); std::vector available_blk_types; @@ -95,13 +94,19 @@ std::vector KArmedBanditAgent::get_available_logical_blk_types_() { continue; } - const auto& blk_per_type = cluster_ctx.clb_nlist.blocks_per_type(logical_blk_type); + const auto& blk_per_type = movable_blocks_per_type(logical_blk_type); if (!blk_per_type.empty()) { available_blk_types.push_back(logical_blk_type.index); } } + // when there is no movable blocks, RL agent always selects the empty logical block + // since there are no empty blocks in the netlist, the move is always aborted + if (available_blk_types.empty()) { + available_blk_types.push_back(device_ctx.EMPTY_LOGICAL_BLOCK_TYPE->index); + } + return available_blk_types; } @@ -311,8 +316,10 @@ t_propose_action SoftmaxAgent::propose_action() { } void SoftmaxAgent::set_block_ratio_() { - auto& cluster_ctx = g_vpr_ctx.clustering(); - size_t num_total_blocks = cluster_ctx.clb_nlist.blocks().size(); + const auto& place_ctx = g_vpr_ctx.placement(); + size_t num_movable_total_blocks = place_ctx.movable_blocks.size(); + + num_movable_total_blocks = std::max(num_movable_total_blocks, 1); // allocate enough space for available block types in the netlist block_type_ratio_.resize(num_available_types_); @@ -324,8 +331,8 @@ void SoftmaxAgent::set_block_ratio_() { for (size_t itype = 0; itype < num_available_types_; itype++) { t_logical_block_type blk_type; blk_type.index = agent_to_phy_blk_type(itype); - auto num_blocks = cluster_ctx.clb_nlist.blocks_per_type(blk_type).size(); - block_type_ratio_[itype] = (float)num_blocks / num_total_blocks; + auto num_blocks = movable_blocks_per_type(blk_type).size(); + block_type_ratio_[itype] = (float)num_blocks / num_movable_total_blocks; block_type_ratio_[itype] /= available_moves_.size(); } } diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong_odin/strong_fix_pins_random/config/golden_results.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong_odin/strong_fix_pins_random/config/golden_results.txt index f7631cf97e0..53e1a99cf04 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong_odin/strong_fix_pins_random/config/golden_results.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong_odin/strong_fix_pins_random/config/golden_results.txt @@ -1,2 +1,2 @@ arch circuit script_params vtr_flow_elapsed_time vtr_max_mem_stage vtr_max_mem error odin_synth_time max_odin_mem parmys_synth_time max_parmys_mem abc_depth abc_synth_time abc_cec_time abc_sec_time max_abc_mem ace_time max_ace_mem num_clb num_io num_memories num_mult vpr_status vpr_revision vpr_build_info vpr_compiler vpr_compiled hostname rundir max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_mem pack_time placed_wirelength_est place_mem place_time place_quench_time placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est placed_geomean_nonvirtual_intradomain_critical_path_delay_est place_delay_matrix_lookup_time place_quench_timing_analysis_time place_quench_sta_time place_total_timing_analysis_time place_total_sta_time min_chan_width routed_wirelength min_chan_width_route_success_iteration logic_block_area_total logic_block_area_used min_chan_width_routing_area_total min_chan_width_routing_area_per_tile min_chan_width_route_time min_chan_width_total_timing_analysis_time min_chan_width_total_sta_time crit_path_routed_wirelength crit_path_route_success_iteration crit_path_total_nets_routed crit_path_total_connections_routed crit_path_total_heap_pushes crit_path_total_heap_pops critical_path_delay geomean_nonvirtual_intradomain_critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS crit_path_routing_area_total crit_path_routing_area_per_tile router_lookahead_computation_time crit_path_route_time crit_path_total_timing_analysis_time crit_path_total_sta_time - k6_N10_mem32K_40nm.xml stereovision3.v common 4.02 vpr 61.07 MiB 0.13 10072 -1 -1 4 0.16 -1 -1 33252 -1 -1 19 11 0 0 success v8.0.0-6793-gb52911b9f release IPO VTR_ASSERT_LEVEL=2 GNU 7.5.0 on Linux-4.15.0-167-generic x86_64 2022-11-27T15:52:14 betzgrp-wintermute.eecg.utoronto.ca /home/elgamma8/research/pack_refactor/vtr-verilog-to-routing 62540 11 30 262 292 2 104 60 7 7 49 clb auto 22.4 MiB 0.17 491 61.1 MiB 0.14 0.00 2.22129 -174.848 -2.22129 2.12256 0.08 0.000609229 0.000514776 0.0130362 0.0113054 30 570 24 1.07788e+06 1.02399e+06 58936.16 1202.776 1.53 0.218794 0.187902 537 22 693 1872 55819 14529 2.35993 2.22897 -183.816 -2.35993 0 0 90369.8 1844.28 0.02 0.10 0.0321781 0.0283564 + k6_N10_mem32K_40nm.xml stereovision3.v common 4.02 vpr 61.07 MiB 0.13 10072 -1 -1 4 0.16 -1 -1 33252 -1 -1 19 11 0 0 success v8.0.0-6793-gb52911b9f release IPO VTR_ASSERT_LEVEL=2 GNU 7.5.0 on Linux-4.15.0-167-generic x86_64 2022-11-27T15:52:14 betzgrp-wintermute.eecg.utoronto.ca /home/elgamma8/research/pack_refactor/vtr-verilog-to-routing 62540 11 30 262 292 2 104 60 7 7 49 clb auto 22.4 MiB 0.17 491 61.1 MiB 0.14 0.00 2.22129 -174.848 -2.22129 2.12256 0.08 0.000609229 0.000514776 0.0130362 0.0113054 30 570 24 1.07788e+06 1.02399e+06 77018.1 1571.80 1.53 0.218794 0.187902 537 22 693 1872 55819 14529 2.35993 2.22897 -183.816 -2.35993 0 0 90369.8 1844.28 0.02 0.10 0.0321781 0.0283564