diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 708a8006bc2..5dd7ae89e67 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -665,6 +665,7 @@ static void SetupPlacerOpts(const t_options& Options, t_placer_opts* PlacerOpts) PlacerOpts->recompute_crit_iter = Options.RecomputeCritIter; PlacerOpts->timing_tradeoff = Options.PlaceTimingTradeoff; + PlacerOpts->congestion_tradeoff = Options.CongestionTradeoff; /* Depends on PlacerOpts->place_algorithm */ PlacerOpts->delay_offset = Options.place_delay_offset; @@ -786,8 +787,6 @@ static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { } NocOpts->noc_sat_routing_log_search_progress = Options.noc_sat_routing_log_search_progress; NocOpts->noc_placement_file_name = Options.noc_placement_file_name; - - } static void SetupServerOpts(const t_options& Options, t_server_opts* ServerOpts) { diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index f19dc626e4f..4f91dcf3892 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -398,6 +398,8 @@ struct ParsePlaceAlgorithm { conv_value.set_value(CRITICALITY_TIMING_PLACE); } else if (str == "slack_timing") { conv_value.set_value(SLACK_TIMING_PLACE); + } else if (str == "congestion_aware") { + conv_value.set_value(CONGESTION_AWARE_PLACE); } else { std::stringstream msg; msg << "Invalid conversion from '" << str << "' to e_place_algorithm (expected one of: " << argparse::join(default_choices(), ", ") << ")"; @@ -419,6 +421,8 @@ struct ParsePlaceAlgorithm { conv_value.set_value("bounding_box"); } else if (val == CRITICALITY_TIMING_PLACE) { conv_value.set_value("criticality_timing"); + } else if (val == CONGESTION_AWARE_PLACE) { + conv_value.set_value("congestion_aware"); } else { VTR_ASSERT(val == SLACK_TIMING_PLACE); conv_value.set_value("slack_timing"); @@ -427,7 +431,7 @@ struct ParsePlaceAlgorithm { } std::vector default_choices() { - return {"bounding_box", "criticality_timing", "slack_timing"}; + return {"bounding_box", "criticality_timing", "slack_timing", "congestion_aware"}; } }; @@ -1398,6 +1402,8 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio " Sets the routing congestion drawing state\n" " * exit \n" " Exits VPR with specified exit code\n" + " * set_congestion \n" + " Sets the routing congestion drawing state\n" "\n" " Example:\n" " 'save_graphics place.png; \\\n" @@ -2007,9 +2013,10 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio "Controls which placement algorithm is used. Valid options:\n" " * bounding_box: Focuses purely on minimizing the bounding box wirelength of the circuit. Turns off timing analysis if specified.\n" " * criticality_timing: Focuses on minimizing both the wirelength and the connection timing costs (criticality * delay).\n" - " * slack_timing: Focuses on improving the circuit slack values to reduce critical path delay.\n") + " * slack_timing: Focuses on improving the circuit slack values to reduce critical path delay.\n" + " * congestion_aware: Focuses on improving routability.\n") .default_value("criticality_timing") - .choices({"bounding_box", "criticality_timing", "slack_timing"}) + .choices({"bounding_box", "criticality_timing", "slack_timing", "congestion_aware"}) .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.PlaceQuenchAlgorithm, "--place_quench_algorithm") @@ -2019,9 +2026,10 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio "Valid options:\n" " * bounding_box: Focuses purely on minimizing the bounding box wirelength of the circuit. Turns off timing analysis if specified.\n" " * criticality_timing: Focuses on minimizing both the wirelength and the connection timing costs (criticality * delay).\n" - " * slack_timing: Focuses on improving the circuit slack values to reduce critical path delay.\n") + " * slack_timing: Focuses on improving the circuit slack values to reduce critical path delay.\n" + " * congestion_aware: Focuses on improving routability.\n") .default_value("criticality_timing") - .choices({"bounding_box", "criticality_timing", "slack_timing"}) + .choices({"bounding_box", "criticality_timing", "slack_timing", "congestion_aware"}) .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.PlaceChanWidth, "--place_chan_width") @@ -2072,7 +2080,6 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value({"100"}) .show_in(argparse::ShowIn::HELP_ONLY); - place_grp.add_argument(args.place_high_fanout_net, "--place_high_fanout_net") .help( "Sets the assumed high fanout net during placement. " @@ -2242,6 +2249,14 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("0.5") .show_in(argparse::ShowIn::HELP_ONLY); + place_timing_grp.add_argument(args.CongestionTradeoff, "--congest_tradeoff") + .help( + "Trade-off control the bouding value for the contestion matrix.\n" + " a value near routing channel width can be a good value.\n" + " a high value let the VPR to ignore the congestion aware placement and continue its own course of action.\n") + .default_value("0.5") + .show_in(argparse::ShowIn::HELP_ONLY); + place_timing_grp.add_argument(args.RecomputeCritIter, "--recompute_crit_iter") .help("Controls how many temperature updates occur between timing analysis during placement") .default_value("1") @@ -2910,13 +2925,13 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("0.25") .show_in(argparse::ShowIn::HELP_ONLY); - noc_grp.add_argument(args.noc_centroid_weight, "--noc_centroid_weight") + noc_grp.add_argument(args.noc_centroid_weight, "--noc_centroid_weight") .help( "Sets the minimum fraction of swaps attempted by the placer that are NoC blocks." "This value is an integer ranging from 0-100. 0 means NoC blocks will be moved at the same rate as other blocks. 100 means all swaps attempted by the placer are NoC router blocks.") .default_value("0") .show_in(argparse::ShowIn::HELP_ONLY); - + noc_grp.add_argument(args.noc_swap_percentage, "--noc_swap_percentage") .help( "Sets the minimum fraction of swaps attempted by the placer that are NoC blocks. " @@ -2968,8 +2983,9 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio auto& server_grp = parser.add_argument_group("server options"); server_grp.add_argument(args.is_server_mode_enabled, "--server") - .help("Run in server mode." - "Accept client application connection and respond to requests." ) + .help( + "Run in server mode." + "Accept client application connection and respond to requests.") .action(argparse::Action::STORE_TRUE) .default_value("off"); diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 4f91f693a8e..678f5303879 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -176,6 +176,7 @@ struct t_options { /* Timing-driven placement options only */ argparse::ArgValue PlaceTimingTradeoff; + argparse::ArgValue CongestionTradeoff; argparse::ArgValue RecomputeCritIter; argparse::ArgValue inner_loop_recompute_divider; argparse::ArgValue quench_recompute_divider; diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 762c1fe86e9..be533590802 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -971,7 +971,8 @@ struct t_annealing_sched { enum e_place_algorithm { BOUNDING_BOX_PLACE, CRITICALITY_TIMING_PLACE, - SLACK_TIMING_PLACE + SLACK_TIMING_PLACE, + CONGESTION_AWARE_PLACE }; enum e_place_bounding_box_mode { @@ -1021,7 +1022,7 @@ class t_place_algorithm { ///@brief Check if the algorithm belongs to the timing driven category. inline bool is_timing_driven() const { - return algo == CRITICALITY_TIMING_PLACE || algo == SLACK_TIMING_PLACE; + return algo == CRITICALITY_TIMING_PLACE || algo == SLACK_TIMING_PLACE || algo == CONGESTION_AWARE_PLACE; } ///@brief Accessor: returns the underlying e_place_algorithm enum value. @@ -1159,6 +1160,7 @@ struct t_placer_opts { t_place_algorithm place_algorithm; t_place_algorithm place_quench_algorithm; float timing_tradeoff; + float congestion_tradeoff; float place_cost_exp; int place_chan_width; enum e_pad_loc_type pad_loc_type; diff --git a/vpr/src/place/move_generator.h b/vpr/src/place/move_generator.h index 15315e4b01a..61957832d5d 100644 --- a/vpr/src/place/move_generator.h +++ b/vpr/src/place/move_generator.h @@ -14,9 +14,11 @@ struct MoveOutcomeStats { float delta_cost_norm = std::numeric_limits::quiet_NaN(); float delta_bb_cost_norm = std::numeric_limits::quiet_NaN(); float delta_timing_cost_norm = std::numeric_limits::quiet_NaN(); + float delta_cong_cost_norm = std::numeric_limits::quiet_NaN(); float delta_bb_cost_abs = std::numeric_limits::quiet_NaN(); float delta_timing_cost_abs = std::numeric_limits::quiet_NaN(); + float delta_cong_cost_abs = std::numeric_limits::quiet_NaN(); e_move_result outcome = ABORTED; float elapsed_time = std::numeric_limits::quiet_NaN(); diff --git a/vpr/src/place/net_cost_handler.cpp b/vpr/src/place/net_cost_handler.cpp index 97384c5f1e8..4fee09412de 100644 --- a/vpr/src/place/net_cost_handler.cpp +++ b/vpr/src/place/net_cost_handler.cpp @@ -52,6 +52,9 @@ enum class NetUpdateState { static constexpr int MAX_FANOUT_CROSSING_COUNT = 50; +static vtr::NdMatrix cong_matrix; +static vtr::NdMatrix cong_matrix_new; + /** * @brief Crossing counts for nets with different #'s of pins. From * ICCAD 94 pp. 690 - 695 (with linear interpolation applied by me). @@ -300,8 +303,8 @@ static void update_layer_bb(ClusterNetId net_id, bool is_output_pin); /** -* @brief This function is called in update_layer_bb to update the net's bounding box incrementally if -* the pin under consideration change layer. + * @brief This function is called in update_layer_bb to update the net's bounding box incrementally if + * the pin under consideration change layer. * @param net_id ID of the net which the moving pin belongs to * @param pin_old_loc Old location of the moving pin * @param pin_new_loc New location of the moving pin @@ -510,8 +513,7 @@ void BBUpdater::get_non_updatable_bb(const ClusterNetId& net) { ::get_non_updatable_bb(net, ts_info.ts_bb_coord_new[net], ts_info.ts_layer_sink_pin_count[size_t(net)]); - } - else { + } else { ::get_non_updatable_layer_bb(net, ts_info.layer_ts_bb_coord_new[net], ts_info.ts_layer_sink_pin_count[size_t(net)]); @@ -527,8 +529,7 @@ void BBUpdater::update_bb(ClusterNetId net_id, t_physical_tile_loc pin_old_loc, pin_old_loc, pin_new_loc, is_driver); - } - else { + } else { ::update_layer_bb(net_id, ts_info.layer_ts_bb_edge_new[net_id], ts_info.layer_ts_bb_coord_new[net_id], @@ -542,8 +543,7 @@ void BBUpdater::update_bb(ClusterNetId net_id, t_physical_tile_loc pin_old_loc, double BBUpdater::get_net_cost(const ClusterNetId net_id) { if (m_cube_bb) { return ::get_net_cost(net_id, ts_info.ts_bb_coord_new[net_id]); - } - else { + } else { return ::get_net_layer_bb_wire_cost(net_id, ts_info.layer_ts_bb_coord_new[net_id], ts_info.ts_layer_sink_pin_count[size_t(net_id)]); } } @@ -1376,10 +1376,10 @@ static inline void update_bb_layer_changed(ClusterNetId net_id, VTR_ASSERT_SAFE(old_layer_num != new_layer_num); /* - This funcitn is called when BB per layer is used and when the moving block is moving from one layer to another. - Thus, we need to update bounding box on both "from" and "to" layer. Here, we update the bounding box on "from" or - "old_layer". Then, "add_block_to_bb" is called to update the bounding box on the new layer. - */ + * This funcitn is called when BB per layer is used and when the moving block is moving from one layer to another. + * Thus, we need to update bounding box on both "from" and "to" layer. Here, we update the bounding box on "from" or + * "old_layer". Then, "add_block_to_bb" is called to update the bounding box on the new layer. + */ if (x_old == curr_bb_coord[old_layer_num].xmax) { update_bb_edge(net_id, bb_edge_new, @@ -1484,10 +1484,10 @@ static void add_block_to_bb(const t_physical_tile_loc& new_pin_loc, int y_new = new_pin_loc.y; /* - This function is called to only update the bounding box on the new layer from a block - moving to this layer from another layer. Thus, we only need to assess the effect of this - new block on the edges. - */ + * This function is called to only update the bounding box on the new layer from a block + * moving to this layer from another layer. Thus, we only need to assess the effect of this + * new block on the edges. + */ if (x_new > bb_coord_old.xmax) { bb_edge_new.xmax = 1; @@ -1787,10 +1787,10 @@ static double get_net_layer_bb_wire_cost(ClusterNetId /* net_id */, continue; } /* - adjust the bounding box half perimeter by the wirelength correction - factor based on terminal count, which is 1 for the source + the number - of sinks on this layer. - */ + * adjust the bounding box half perimeter by the wirelength correction + * factor based on terminal count, which is 1 for the source + the number + * of sinks on this layer. + */ crossing = wirelength_crossing_count(layer_pin_sink_count[layer_num] + 1); /* Could insert a check for xmin == xmax. In that case, assume * @@ -1830,6 +1830,58 @@ static double get_net_wirelength_estimate(ClusterNetId net_id, const t_bb& bb) { return ncost; } +void get_cong_matrix(ClusterNetId net_id, const t_bb& bb) { + /* Finds the cost due to one net by looking at its coordinate bounding * + * box. */ + // auto& cluster_ctx = g_vpr_ctx.clustering(); + + /* Could insert a check for xmin == xmax. In that case, assume * + * connection will be made with no bends and hence no x-cost. * + * Same thing for y-cost. */ + + /* Cost = wire length along channel * cross_count / average * + * channel capacity. Do this for x, then y direction and add. */ + for (int i = bb.xmin; i < bb.xmax; i++) { + for (int j = bb.ymin; j < bb.ymax; j++) { + cong_matrix[i][j] += get_net_wirelength_estimate(net_id, bb) / double((bb.xmax - bb.xmin + 1) * (bb.ymax - bb.ymin + 1)); + } + } +} + +double get_cong_cost(double chan_width) { + auto& device_ctx = g_vpr_ctx.device(); + double max = 0.0; + double avg = 1e-4, var = 0.0; + double num = 0.0; + double max_width = chan_width; + for (int i = 0; i < int(device_ctx.grid.width()); i++) { + for (int j = 0; j < int(device_ctx.grid.height()); j++) { + if (max < cong_matrix_new[i][j]) { + max = cong_matrix_new[i][j]; + } + } + } + + for (int i = 0; i < int(device_ctx.grid.width()); i++) { + for (int j = 0; j < int(device_ctx.grid.height()); j++) { + if (cong_matrix_new[i][j] > max_width) { + avg += cong_matrix_new[i][j] - max_width; + num += 1.0; + } + } + } + + for (int i = 0; i < int(device_ctx.grid.width()); i++) { + for (int j = 0; j < int(device_ctx.grid.height()); j++) { + double var_var = cong_matrix_new[i][j] - avg; + var_var = var_var * var_var; + var += var_var; + } + } + var = var / double((device_ctx.grid.width() * device_ctx.grid.height())); + return avg; +} + static double get_net_wirelength_from_layer_bb(ClusterNetId /* net_id */, const std::vector& bb, const vtr::NdMatrixProxy layer_pin_sink_count) { @@ -1889,7 +1941,7 @@ static double wirelength_crossing_count(size_t fanout) { } static void set_bb_delta_cost(double& bb_delta_c) { - for (const ClusterNetId ts_net: ts_info.ts_nets_to_update) { + for (const ClusterNetId ts_net : ts_info.ts_nets_to_update) { ClusterNetId net_id = ts_net; pl_net_cost.proposed_net_cost[net_id] = bb_updater.get_net_cost(net_id); @@ -1942,12 +1994,22 @@ void find_affected_nets_and_update_costs( set_bb_delta_cost(bb_delta_c); } -double comp_bb_cost(e_cost_methods method) { +double comp_bb_cost(e_cost_methods method, const t_place_algorithm& place_algorithm) { double cost = 0; double expected_wirelength = 0.0; auto& cluster_ctx = g_vpr_ctx.clustering(); auto& placer_state = placer_state_ref->get(); auto& place_move_ctx = placer_state.mutable_move(); + auto& device_ctx = g_vpr_ctx.device(); + // VTR_LOG("\n\n\nwidth = %d and height= %d\n\n\n",device_ctx.grid.width(), device_ctx.grid.height()); + if (place_algorithm == CONGESTION_AWARE_PLACE) { + for (int i = 0; i < int(device_ctx.grid.width()); i++) { + for (int j = 0; j < int(device_ctx.grid.height()); j++) { + cong_matrix[i][j] = 0.0; + // cong_matrix_new[i][j] = 0.0; + } + } + } for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ @@ -1964,6 +2026,10 @@ double comp_bb_cost(e_cost_methods method) { place_move_ctx.num_sink_pin_layer[size_t(net_id)]); } + if (place_algorithm == CONGESTION_AWARE_PLACE) { + get_cong_matrix(net_id, place_move_ctx.bb_coords[net_id]); + } + pl_net_cost.net_cost[net_id] = get_net_cost(net_id, place_move_ctx.bb_coords[net_id]); cost += pl_net_cost.net_cost[net_id]; if (method == e_cost_methods::CHECK) @@ -1971,6 +2037,24 @@ double comp_bb_cost(e_cost_methods method) { } } + if (place_algorithm == CONGESTION_AWARE_PLACE) { + for (int i = 0; i < int(device_ctx.grid.width()); i++) { + for (int j = 0; j < int(device_ctx.grid.height()); j++) { + cong_matrix_new[i][j] = cong_matrix[i][j]; + } + } + } + + // cost = get_cong_cost(); + if (place_algorithm == CONGESTION_AWARE_PLACE) { + for (int i = 0; i < int(device_ctx.grid.width()); i++) { + for (int j = 0; j < int(device_ctx.grid.height()); j++) { + VTR_LOG("%4.0f\t", cong_matrix[i][j]); + } + VTR_LOG("\n"); + } + } + if (method == e_cost_methods::CHECK) { VTR_LOG("\n"); VTR_LOG("BB estimate of min-dist (placement) wire length: %.0f\n", @@ -2075,8 +2159,13 @@ void recompute_costs_from_scratch(const t_placer_opts& placer_opts, }; double new_bb_cost = recompute_bb_cost(); + double new_cong_cost = 0.0; + if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + new_cong_cost = get_cong_cost(placer_opts.congestion_tradeoff); + } check_and_print_cost(new_bb_cost, costs->bb_cost, "bb_cost"); costs->bb_cost = new_bb_cost; + costs->cong_cost = new_cong_cost; if (placer_opts.place_algorithm.is_timing_driven()) { double new_timing_cost = 0.; @@ -2138,10 +2227,10 @@ void alloc_and_load_chan_w_factors_for_place_cost(float place_cost_exp) { auto& device_ctx = g_vpr_ctx.device(); /* - Access arrays below as chan?_place_cost_fac[subhigh][sublow]. Since subhigh must be greater than or - equal to sublow, we will only access the lower half of a matrix, but we allocate the whole matrix anyway - for simplicity so we can use the vtr utility matrix functions. - */ + * Access arrays below as chan?_place_cost_fac[subhigh][sublow]. Since subhigh must be greater than or + * equal to sublow, we will only access the lower half of a matrix, but we allocate the whole matrix anyway + * for simplicity so we can use the vtr utility matrix functions. + */ chanx_place_cost_fac.resize({device_ctx.grid.height(), device_ctx.grid.height() + 1}); chany_place_cost_fac.resize({device_ctx.grid.width(), device_ctx.grid.width() + 1}); diff --git a/vpr/src/place/net_cost_handler.h b/vpr/src/place/net_cost_handler.h index 8ab0af8e554..3a2407132f5 100644 --- a/vpr/src/place/net_cost_handler.h +++ b/vpr/src/place/net_cost_handler.h @@ -74,7 +74,7 @@ void find_affected_nets_and_update_costs( * @param method * @return The bounding box cost of the placement, computed by the 3D method. */ -double comp_bb_cost(e_cost_methods method); +double comp_bb_cost(e_cost_methods method, const t_place_algorithm& place_algorithm); /** * @brief Finds the bb cost from scratch (based on per-layer BB). @@ -156,4 +156,8 @@ void init_try_swap_net_cost_structs(size_t num_nets, bool cube_bb); */ void free_try_swap_net_cost_structs(); +void get_cong_matrix(ClusterNetId net_id, const t_bb& bb); + +double get_cong_cost(double chan_width); + void set_net_handlers_placer_state(PlacerState& placer_state); diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 2cd55402d47..e7a04624836 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -99,6 +99,8 @@ constexpr float INVALID_COST = std::numeric_limits::quiet_NaN(); /********************** Variables local to place.c ***************************/ +float congestion_tradeoff = 1.0; + std::unique_ptr f_move_stats_file(nullptr, vtr::fclose); @@ -269,7 +271,7 @@ static void invalidate_affected_connections( static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks, const PlacerState& placer_state); -static e_move_result assess_swap(double delta_c, double t); +static e_move_result assess_swap(double delta_c, double t, double cong_delta_c, double cost, const t_placer_opts& placer_opts); static void update_placement_cost_normalization_factors(t_placer_costs* costs, const t_placer_opts& placer_opts, const t_noc_opts& noc_opts); @@ -490,12 +492,16 @@ void try_place(const Netlist<>& net_list, if (placer_opts.place_algorithm.is_timing_driven()) { if (cube_bb) { - costs.bb_cost = comp_bb_cost(e_cost_methods::NORMAL); + costs.bb_cost = comp_bb_cost(e_cost_methods::NORMAL, placer_opts.place_algorithm); } else { VTR_ASSERT_SAFE(!cube_bb); costs.bb_cost = comp_layer_bb_cost(e_cost_methods::NORMAL); } + if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + costs.cong_cost = get_cong_cost(placer_opts.congestion_tradeoff); + } + // costs.cong_cost_norm = 1/ costs.cong_cost; first_crit_exponent = placer_opts.td_place_exp_first; /*this will be modified when rlim starts to change */ num_connections = count_connections(); @@ -571,13 +577,16 @@ void try_place(const Netlist<>& net_list, /* Total cost is the same as wirelength cost normalized*/ if (cube_bb) { - costs.bb_cost = comp_bb_cost(e_cost_methods::NORMAL); + costs.bb_cost = comp_bb_cost(e_cost_methods::NORMAL, placer_opts.place_algorithm); } else { VTR_ASSERT_SAFE(!cube_bb); costs.bb_cost = comp_layer_bb_cost(e_cost_methods::NORMAL); } costs.bb_cost_norm = 1 / costs.bb_cost; - + if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + costs.cong_cost = get_cong_cost(placer_opts.congestion_tradeoff); + costs.cong_cost_norm = 1 / costs.cong_cost; + } /* Timing cost and normalization factors are not used */ costs.timing_cost = INVALID_COST; costs.timing_cost_norm = INVALID_COST; @@ -698,6 +707,9 @@ void try_place(const Netlist<>& net_list, device_ctx.grid.get_num_layers()); /* Update the starting temperature for placement annealing to a more appropriate value */ + if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + congestion_tradeoff = 1.0; + } state.t = starting_t(&state, &costs, annealing_sched, place_delay_model.get(), placer_criticalities.get(), placer_setup_slacks.get(), timing_info.get(), *move_generator, @@ -705,6 +717,10 @@ void try_place(const Netlist<>& net_list, blocks_affected, placer_opts, noc_opts, move_type_stat, swap_stats, placer_state); + if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + congestion_tradeoff = 0.1; + } + double starting_tempreture = state.t; if (!placer_opts.move_stats_file.empty()) { f_move_stats_file = std::unique_ptr( vtr::fopen(placer_opts.move_stats_file.c_str(), "w"), @@ -736,10 +752,17 @@ void try_place(const Netlist<>& net_list, if (!skip_anneal) { //Table header VTR_LOG("\n"); + bool congest_flag = false; print_place_status_header(noc_opts.noc); /* Outer loop of the simulated annealing begins */ do { + if (get_cong_cost(placer_opts.congestion_tradeoff) <= 20 && congest_flag == false && placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + congest_flag = true; + congestion_tradeoff = 1.0; + state.t = starting_tempreture; + // state.move_lim = state.move_lim_max; + } vtr::Timer temperature_timer; outer_loop_update_timing_info(placer_opts, noc_opts, &costs, num_connections, @@ -768,6 +791,8 @@ void try_place(const Netlist<>& net_list, agent_state, placer_opts, false, current_move_generator); //do a complete inner loop iteration + // VTR_LOG("cong_cost is:%5.5f\n",); + placement_inner_loop(&state, placer_opts, noc_opts, inner_recompute_limit, &stats, &costs, &moves_since_cost_recompute, @@ -1299,6 +1324,7 @@ static e_move_result try_swap(const t_annealing_state* state, double delta_c = 0; //Change in cost due to this swap. double bb_delta_c = 0; //Change in the bounding box (wiring) cost. double timing_delta_c = 0; //Change in the timing cost (delay * criticality). + double cong_delta_c = 0; // Determine whether we need to force swap two router blocks bool router_block_move = false; @@ -1320,10 +1346,8 @@ static e_move_result try_swap(const t_annealing_state* state, //When manual move toggle button is active, the manual move window asks the user for input. if (manual_move_enabled) { #ifndef NO_GRAPHICS - create_move_outcome = manual_move_display_and_propose(manual_move_generator, blocks_affected, - proposed_action.move_type, rlim, placer_opts, - criticalities); -#else //NO_GRAPHICS + create_move_outcome = manual_move_display_and_propose(manual_move_generator, blocks_affected, proposed_action.move_type, rlim, placer_opts, criticalities); +#else //NO_GRAPHICS \ //Cast to void to explicitly avoid warning. (void)manual_move_generator; #endif //NO_GRAPHICS @@ -1378,7 +1402,7 @@ static e_move_result try_swap(const t_annealing_state* state, // //Also find all the pins affected by the swap, and calculates new connection //delays and timing costs and store them in proposed_* data structures. - find_affected_nets_and_update_costs(place_algorithm, delay_model, criticalities, + find_affected_nets_and_update_costs(place_algorithm, delay_model, criticalities, blocks_affected, bb_delta_c, timing_delta_c); //For setup slack analysis, we first do a timing analysis to get the newest @@ -1422,7 +1446,12 @@ static e_move_result try_swap(const t_annealing_state* state, timing_delta_c, costs->timing_cost_norm); delta_c = (1 - timing_tradeoff) * bb_delta_c * costs->bb_cost_norm - + timing_tradeoff * timing_delta_c * costs->timing_cost_norm; + + timing_tradeoff * timing_delta_c + * costs->timing_cost_norm; + } else if (place_algorithm == CONGESTION_AWARE_PLACE) { + /* Take delta_c as a combination of timing and wiring cost. In + * addition to `timing_tradeoff`, we normalize the cost values */ + delta_c = (1 - congestion_tradeoff) * (cong_delta_c * costs->cong_cost_norm) + ((1 - timing_tradeoff) * bb_delta_c * costs->bb_cost_norm + timing_tradeoff * timing_delta_c * costs->timing_cost_norm); } else { VTR_ASSERT_SAFE(place_algorithm == BOUNDING_BOX_PLACE); VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug, @@ -1442,7 +1471,11 @@ static e_move_result try_swap(const t_annealing_state* state, } /* 1 -> move accepted, 0 -> rejected. */ - move_outcome = assess_swap(delta_c, state->t); + if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + move_outcome = assess_swap(delta_c, state->t, cong_delta_c, get_cong_cost(placer_opts.congestion_tradeoff), placer_opts); + } else { + move_outcome = assess_swap(delta_c, state->t, 0.0, 0.0, placer_opts); + } //Updates the manual_move_state members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. #ifndef NO_GRAPHICS @@ -1454,6 +1487,7 @@ static e_move_result try_swap(const t_annealing_state* state, if (move_outcome == ACCEPTED) { costs->cost += delta_c; costs->bb_cost += bb_delta_c; + costs->cong_cost += cong_delta_c; if (place_algorithm == SLACK_TIMING_PLACE) { /* Update the timing driven cost as usual */ @@ -1464,7 +1498,7 @@ static e_move_result try_swap(const t_annealing_state* state, commit_setup_slacks(setup_slacks, placer_state); } - if (place_algorithm == CRITICALITY_TIMING_PLACE) { + if (place_algorithm == CRITICALITY_TIMING_PLACE || place_algorithm == CONGESTION_AWARE_PLACE) { costs->timing_cost += timing_delta_c; /* Invalidates timing of modified connections for incremental * @@ -1530,7 +1564,7 @@ static e_move_result try_swap(const t_annealing_state* state, "The current setup slacks should be identical to the values before the try swap timing info update."); } - if (place_algorithm == CRITICALITY_TIMING_PLACE) { + if (place_algorithm == CRITICALITY_TIMING_PLACE || place_algorithm == CONGESTION_AWARE_PLACE) { /* Unstage the values stored in proposed_* data structures */ revert_td_cost(blocks_affected, placer_state.mutable_timing()); } @@ -1545,11 +1579,15 @@ static e_move_result try_swap(const t_annealing_state* state, } move_outcome_stats.delta_cost_norm = delta_c; - move_outcome_stats.delta_bb_cost_norm = bb_delta_c * costs->bb_cost_norm; - move_outcome_stats.delta_timing_cost_norm = timing_delta_c * costs->timing_cost_norm; + move_outcome_stats.delta_bb_cost_norm = bb_delta_c + * costs->bb_cost_norm; + move_outcome_stats.delta_timing_cost_norm = timing_delta_c + * costs->timing_cost_norm; + move_outcome_stats.delta_cong_cost_norm = cong_delta_c * costs->cong_cost_norm; move_outcome_stats.delta_bb_cost_abs = bb_delta_c; move_outcome_stats.delta_timing_cost_abs = timing_delta_c; + move_outcome_stats.delta_cong_cost_abs = cong_delta_c; LOG_MOVE_STATS_OUTCOME(delta_c, bb_delta_c, timing_delta_c, (move_outcome ? "ACCEPTED" : "REJECTED"), ""); } @@ -1656,6 +1694,9 @@ static double get_total_cost(t_placer_costs* costs, const t_placer_opts& placer_ if (placer_opts.place_algorithm == BOUNDING_BOX_PLACE) { // in bounding box mode we only care about wirelength total_cost = costs->bb_cost * costs->bb_cost_norm; + } else if (placer_opts.place_algorithm == CONGESTION_AWARE_PLACE) { + // in timing mode we include both wirelength and timing costs + total_cost = (1 - congestion_tradeoff) * (costs->cong_cost * costs->cong_cost_norm) + ((1 - placer_opts.timing_tradeoff) * (costs->bb_cost * costs->bb_cost_norm) + (placer_opts.timing_tradeoff) * (costs->timing_cost * costs->timing_cost_norm)); } else if (placer_opts.place_algorithm.is_timing_driven()) { // in timing mode we include both wirelength and timing costs total_cost = (1 - placer_opts.timing_tradeoff) * (costs->bb_cost * costs->bb_cost_norm) + (placer_opts.timing_tradeoff) * (costs->timing_cost * costs->timing_cost_norm); @@ -1728,11 +1769,10 @@ static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks, return 1; } -static e_move_result assess_swap(double delta_c, double t) { +static e_move_result assess_swap(double delta_c, double t, double cong_delta_c, double cost, const t_placer_opts& placer_opts) { /* Returns: 1 -> move accepted, 0 -> rejected. */ - VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug, "\tTemperature is: %e delta_c is %e\n", t, delta_c); - if (delta_c <= 0) { - VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug, "\t\tMove is accepted(delta_c < 0)\n"); + if (delta_c <= 0 && ((cong_delta_c <= 0) || (cost <= 20.0) || (placer_opts.place_algorithm != CONGESTION_AWARE_PLACE))) { + VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug, "\tTemperature is: %e delta_c is %e\n", t, delta_c); return ACCEPTED; } @@ -1743,7 +1783,8 @@ static e_move_result assess_swap(double delta_c, double t) { float fnum = vtr::frand(); float prob_fac = std::exp(-delta_c / t); - if (prob_fac > fnum) { + float prob_fac_cong = std::exp(-cong_delta_c / t); + if (prob_fac > fnum && (prob_fac_cong > fnum || placer_opts.place_algorithm != CONGESTION_AWARE_PLACE)) { VTR_LOGV_DEBUG(g_vpr_ctx.placement().f_placer_debug, "\t\tMove is accepted(hill climbing)\n"); return ACCEPTED; } @@ -1999,7 +2040,7 @@ static int check_placement_costs(const t_placer_costs& costs, const bool cube_bb = g_vpr_ctx.placement().cube_bb; if (cube_bb) { - bb_cost_check = comp_bb_cost(e_cost_methods::CHECK); + bb_cost_check = comp_bb_cost(e_cost_methods::CHECK, place_algorithm); } else { VTR_ASSERT_SAFE(!cube_bb); bb_cost_check = comp_layer_bb_cost(e_cost_methods::CHECK); @@ -2071,18 +2112,10 @@ static int check_block_placement_consistency(const BlkLocRegistry& blk_loc_regis auto& loc = block_locs[bnum].loc; if (loc.x != i || loc.y != j || loc.layer != layer_num - || !is_sub_tile_compatible(physical_tile, logical_block, - loc.sub_tile)) { + || !is_sub_tile_compatible(physical_tile, logical_block, loc.sub_tile)) { VTR_LOG_ERROR( "Block %zu's location is (%d,%d,%d) but found in grid at (%zu,%zu,%d,%d).\n", - size_t(bnum), - loc.x, - loc.y, - loc.sub_tile, - tile_loc.x, - tile_loc.y, - tile_loc.layer_num, - layer_num); + size_t(bnum), loc.x, loc.y, loc.sub_tile, tile_loc.x, tile_loc.y, tile_loc.layer_num, layer_num); error++; } ++usage_check; @@ -2241,11 +2274,11 @@ static void print_place_status(const t_annealing_state& state, "%4zu %6.1f %7.1e " "%7.3f %10.2f %-10.5g " "%7.3f % 10.3g % 8.3f " - "%7.3f %7.4f %6.1f %8.2f", + "%7.3f %7.4f %6.1f %8.2f %5.3f", state.num_temps, elapsed_sec, state.t, - stats.av_cost, stats.av_bb_cost, stats.av_timing_cost, - 1e9 * cpd, 1e9 * sTNS, 1e9 * sWNS, - stats.success_rate, stats.std_dev, state.rlim, state.crit_exponent); + stats.av_cost, stats.av_bb_cost, stats.av_timing_cost, 1e9 * cpd, + 1e9 * sTNS, 1e9 * sWNS, stats.success_rate, stats.std_dev, + state.rlim, state.crit_exponent, stats.av_cong_cost); pretty_print_uint(" ", tot_moves, 9, 3); @@ -2338,6 +2371,7 @@ static void print_placement_move_types_stats(const MoveTypeStat& move_type_stat) int count = 0; int num_of_avail_moves = move_type_stat.blk_type_moves.size() / device_ctx.logical_block_types.size(); + // VTR_LOG("\n\nPercentage of different move types and block types:\n"); //Print placement information for each block type for (const auto& itype : device_ctx.logical_block_types) { //Skip non-existing block types in the netlist diff --git a/vpr/src/place/place_util.cpp b/vpr/src/place/place_util.cpp index 3541ef01bf1..cca652be101 100644 --- a/vpr/src/place/place_util.cpp +++ b/vpr/src/place/place_util.cpp @@ -51,6 +51,7 @@ static GridBlock init_grid_blocks() { void t_placer_costs::update_norm_factors() { if (place_algorithm.is_timing_driven()) { bb_cost_norm = 1 / bb_cost; + if (cong_cost) cong_cost_norm = 1 / cong_cost; //Prevent the norm factor from going to infinity timing_cost_norm = std::min(1 / timing_cost, MAX_INV_TIMING_COST); } else { @@ -231,6 +232,7 @@ void t_placer_statistics::reset() { av_cost = 0.; av_bb_cost = 0.; av_timing_cost = 0.; + av_cong_cost = 0.; sum_of_squares = 0.; success_sum = 0; success_rate = 0.; @@ -243,6 +245,7 @@ void t_placer_statistics::single_swap_update(const t_placer_costs& costs) { av_cost += costs.cost; av_bb_cost += costs.bb_cost; av_timing_cost += costs.timing_cost; + av_cong_cost += costs.cong_cost; sum_of_squares += (costs.cost) * (costs.cost); } @@ -252,10 +255,12 @@ void t_placer_statistics::calc_iteration_stats(const t_placer_costs& costs, int av_cost = costs.cost; av_bb_cost = costs.bb_cost; av_timing_cost = costs.timing_cost; + av_cong_cost = costs.cong_cost; } else { av_cost /= success_sum; av_bb_cost /= success_sum; av_timing_cost /= success_sum; + av_cong_cost /= success_sum; } success_rate = success_sum / float(move_lim); std_dev = get_std_dev(success_sum, sum_of_squares, av_cost); diff --git a/vpr/src/place/place_util.h b/vpr/src/place/place_util.h index 934d2072251..38788d8012e 100644 --- a/vpr/src/place/place_util.h +++ b/vpr/src/place/place_util.h @@ -92,6 +92,8 @@ class t_placer_costs { double timing_cost = 0.; double bb_cost_norm = 0.; double timing_cost_norm = 0.; + double cong_cost = 0.; + double cong_cost_norm = 0.; NocCostTerms noc_cost_terms; NocCostTerms noc_cost_norm_factors; @@ -281,6 +283,7 @@ class t_placer_statistics { double av_cost; double av_bb_cost; double av_timing_cost; + double av_cong_cost; double sum_of_squares; int success_sum; float success_rate;