From 29f12e25e8a74fa46fe41e3e322651bb45ce5ffa Mon Sep 17 00:00:00 2001 From: Milad Ebrahimipour Date: Thu, 31 Aug 2023 01:37:05 -0400 Subject: [PATCH 1/2] Adding congestion-aware placement --- vpr/src/place/move_generator.h | 2 + vpr/src/place/place.cpp | 340 ++++++++++++++++++++++++++------- vpr/src/place/place_util.cpp | 5 + vpr/src/place/place_util.h | 3 + 4 files changed, 280 insertions(+), 70 deletions(-) diff --git a/vpr/src/place/move_generator.h b/vpr/src/place/move_generator.h index 378d86c8bf1..74ac8dfd00e 100644 --- a/vpr/src/place/move_generator.h +++ b/vpr/src/place/move_generator.h @@ -12,9 +12,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/place.cpp b/vpr/src/place/place.cpp index 1b9a6508010..b201705a69f 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -171,6 +171,11 @@ static const float cross_count[50] = {/* [0..49] */ 1.0, 1.0, 1.0, 1.0828, 2.5610, 2.5864, 2.6117, 2.6371, 2.6625, 2.6887, 2.7148, 2.7410, 2.7671, 2.7933}; +double cong_matrix[400][400]; +double cong_matrix_new[400][400]; + +float congestion_tradeoff = 1.0; + std::unique_ptr f_move_stats_file(nullptr, vtr::fclose); @@ -266,7 +271,7 @@ static void alloc_and_load_for_fast_cost_update(float place_cost_exp); static void free_fast_cost_update(); -static double comp_bb_cost(e_cost_methods method); +static double comp_bb_cost(e_cost_methods method,const t_place_algorithm& place_algorithm); static void update_move_nets(int num_nets_affected); static void reset_move_nets(int num_nets_affected); @@ -323,7 +328,7 @@ static bool driven_by_moved_block(const ClusterNetId net, static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks); -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 get_non_updateable_bb(ClusterNetId net_id, t_bb* bb_coord_new); @@ -335,7 +340,9 @@ static int find_affected_nets_and_update_costs( const PlacerCriticalities* criticalities, t_pl_blocks_to_be_moved& blocks_affected, double& bb_delta_c, - double& timing_delta_c); + double& timing_delta_c, + double& bb_cong_c, + const t_placer_opts& placer_opts); static void record_affected_net(const ClusterNetId net, int& num_affected_nets); @@ -356,6 +363,9 @@ static void update_placement_cost_normalization_factors(t_placer_costs* costs, c static double get_total_cost(t_placer_costs* costs, const t_placer_opts& placer_opts, const t_noc_opts& noc_opts); static double get_net_cost(ClusterNetId net_id, t_bb* bb_ptr); +static double get_cong_cost(double chan_width); +static void get_cong_matrix(ClusterNetId net_id, t_bb* bb_ptr); +static void update_cong_matrix(ClusterNetId net_id, t_bb* bb_ptr_old, t_bb* bb_ptr_new); static void get_bb_from_scratch(ClusterNetId net_id, t_bb* coords, t_bb* num_on_edges); @@ -448,7 +458,7 @@ void try_place(const Netlist<>& net_list, * width of the widest channel. Place_cost_exp says what exponent the * * width should be taken to when calculating costs. This allows a * * greater bias for anisotropic architectures. */ - + /* * Currently, the functions that require is_flat as their parameter and are called during placement should * receive is_flat as false. For example, if the RR graph of router lookahead is built here, it should be as @@ -574,8 +584,12 @@ void try_place(const Netlist<>& net_list, /* Gets initial cost and loads bounding boxes. */ if (placer_opts.place_algorithm.is_timing_driven()) { - costs.bb_cost = comp_bb_cost(NORMAL); + costs.bb_cost = comp_bb_cost(NORMAL,placer_opts.place_algorithm); + 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(); @@ -609,7 +623,7 @@ void try_place(const Netlist<>& net_list, placer_criticalities = std::make_unique( cluster_ctx.clb_nlist, netlist_pin_lookup); - pin_timing_invalidator = make_net_pin_timing_invalidator( + pin_timing_invalidator = make_net_pin_timing_invalidator( placer_opts.timing_update_type, net_list, netlist_pin_lookup, @@ -654,9 +668,12 @@ void try_place(const Netlist<>& net_list, VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); /* Total cost is the same as wirelength cost normalized*/ - costs.bb_cost = comp_bb_cost(NORMAL); + costs.bb_cost = comp_bb_cost(NORMAL,placer_opts.place_algorithm); 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; @@ -773,20 +790,27 @@ void try_place(const Netlist<>& net_list, /* Set the temperature low to ensure that initial placement quality will be preserved */ first_t = EPSILON; - t_annealing_state state(annealing_sched, - first_t, + t_annealing_state state(annealing_sched, + first_t, first_rlim, - first_move_lim, + first_move_lim, first_crit_exponent, 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, *manual_move_generator, pin_timing_invalidator.get(), blocks_affected, placer_opts, noc_opts, move_type_stat); - + + 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"), @@ -818,9 +842,16 @@ void try_place(const Netlist<>& net_list, //Table header VTR_LOG("\n"); print_place_status_header(); + bool congest_flag = false; /* 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, @@ -848,6 +879,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, @@ -1168,8 +1201,8 @@ static void placement_inner_loop(const t_annealing_state* state, #ifdef VERBOSE VTR_LOG("t = %g cost = %g bb_cost = %g timing_cost = %g move = %d\n", state->t, costs->cost, costs->bb_cost, costs->timing_cost, inner_iter); - if (fabs((costs->bb_cost) - comp_bb_cost(CHECK)) > (costs->bb_cost) * ERROR_TOL) - VPR_ERROR(VPR_ERROR_PLACE, "bb_cost is %g, comp_bb_cost is %g\n", costs->bb_cost, comp_bb_cost(CHECK)); + if (fabs((costs->bb_cost) - comp_bb_cost(CHECK,placer_opts.place_algorithm)) > (costs->bb_cost) * ERROR_TOL) + VPR_ERROR(VPR_ERROR_PLACE, "bb_cost is %g, comp_bb_cost is %g\n", costs->bb_cost, comp_bb_cost(CHECK,placer_opts.place_algorithm)); //"fabs((*bb_cost) - comp_bb_cost(CHECK)) > (*bb_cost) * ERROR_TOL"); #endif @@ -1212,6 +1245,10 @@ static void recompute_costs_from_scratch(const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities, t_placer_costs* costs) { 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); + } if (fabs(new_bb_cost - costs->bb_cost) > costs->bb_cost * ERROR_TOL) { std::string msg = vtr::string_fmt( "in recompute_costs_from_scratch: new_bb_cost = %g, old bb_cost = %g\n", @@ -1219,7 +1256,7 @@ static void recompute_costs_from_scratch(const t_placer_opts& placer_opts, VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); } 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.; comp_td_costs(delay_model, *criticalities, &new_timing_cost); @@ -1370,6 +1407,8 @@ static void update_move_nets(int num_nets_affected) { /* update net cost functions and reset flags. */ auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_move_ctx = g_placer_ctx.mutable_move(); + auto& device_ctx = g_vpr_ctx.device(); + for (int inet_affected = 0; inet_affected < num_nets_affected; inet_affected++) { @@ -1385,9 +1424,22 @@ static void update_move_nets(int num_nets_affected) { proposed_net_cost[net_id] = -1; bb_updated_before[net_id] = NOT_UPDATED_YET; } + + for(int i=0;ibb_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); delta_c = bb_delta_c * costs->bb_cost_norm; @@ -1581,7 +1640,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 @@ -1593,6 +1656,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 */ @@ -1603,7 +1667,7 @@ static e_move_result try_swap(const t_annealing_state* state, commit_setup_slacks(setup_slacks); } - 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 * @@ -1671,7 +1735,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); } @@ -1690,9 +1754,11 @@ static e_move_result try_swap(const t_annealing_state* state, * 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"), ""); @@ -1755,14 +1821,24 @@ static int find_affected_nets_and_update_costs( const PlacerCriticalities* criticalities, t_pl_blocks_to_be_moved& blocks_affected, double& bb_delta_c, - double& timing_delta_c) { + double& timing_delta_c, + double& bb_cong_c, + const t_placer_opts& placer_opts) { + VTR_ASSERT_SAFE(bb_delta_c == 0.); VTR_ASSERT_SAFE(timing_delta_c == 0.); auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_move_ctx = g_placer_ctx.mutable_move(); + + int num_affected_nets = 0; - /* Go through all the blocks moved. */ + double before_cost = 0.0; + + if(place_algorithm == CONGESTION_AWARE_PLACE){ + before_cost = get_cong_cost(placer_opts.congestion_tradeoff); + } for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { ClusterBlockId blk = blocks_affected.moved_blocks[iblk].block_num; @@ -1782,6 +1858,7 @@ static int find_affected_nets_and_update_costs( /* Update the net bounding boxes. */ update_net_bb(net_id, blocks_affected, iblk, blk, blk_pin); + if (place_algorithm.is_timing_driven()) { /* Determine the change in connection delay and timing cost. */ @@ -1797,11 +1874,21 @@ static int find_affected_nets_and_update_costs( inet_affected++) { ClusterNetId net_id = ts_nets_to_update[inet_affected]; + if(place_algorithm == CONGESTION_AWARE_PLACE){ + update_cong_matrix(net_id,&place_move_ctx.bb_coords[net_id],&ts_bb_coord_new[net_id]); + } + proposed_net_cost[net_id] = get_net_cost(net_id, &ts_bb_coord_new[net_id]); bb_delta_c += proposed_net_cost[net_id] - net_cost[net_id]; } + // bb_delta_c = get_cong_cost()-before_cost; + + if(place_algorithm == CONGESTION_AWARE_PLACE){ + bb_cong_c = get_cong_cost(placer_opts.congestion_tradeoff)-before_cost; + } + // VTR_LOG("cong cost is= %0.3f\n",bb_cong_c); return num_affected_nets; } @@ -1994,10 +2081,13 @@ 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); - } + } if (noc_opts.noc) { // in noc mode we include noc agggregate bandwidth and noc latency @@ -2065,9 +2155,9 @@ 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. */ - if (delta_c <= 0) { + if (delta_c <= 0 && ((cong_delta_c <= 0) || (cost <= 20.0) || (placer_opts.place_algorithm != CONGESTION_AWARE_PLACE))) { return ACCEPTED; } @@ -2077,7 +2167,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)) { return ACCEPTED; } @@ -2202,11 +2293,21 @@ static bool driven_by_moved_block(const ClusterNetId net, * are found via the non_updateable_bb routine, to provide a * * cost which can be used to check the correctness of the * * other routine. */ -static double comp_bb_cost(e_cost_methods method) { +static 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& place_move_ctx = g_placer_ctx.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. */ @@ -2221,6 +2322,10 @@ static double comp_bb_cost(e_cost_methods method) { &place_move_ctx.bb_coords[net_id]); } + if(place_algorithm == CONGESTION_AWARE_PLACE){ + get_cong_matrix(net_id,&place_move_ctx.bb_coords[net_id]); + } + net_cost[net_id] = get_net_cost(net_id, &place_move_ctx.bb_coords[net_id]); cost += net_cost[net_id]; @@ -2230,6 +2335,23 @@ static 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 50) { return 2.7933 + 0.02616 * (fanout - 50); } else { @@ -2503,6 +2625,83 @@ static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb* bbptr) { return (ncost); } +static void update_cong_matrix(ClusterNetId net_id, t_bb* bb_ptr_old, t_bb* bb_ptr_new){ + /* 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_ptr_old->xmin; i < bb_ptr_old->xmax; i++){ + for(int j = bb_ptr_old->ymin; j < bb_ptr_old->ymax; j++){ + cong_matrix_new[i][j] -= get_net_wirelength_estimate(net_id,bb_ptr_old)/double((bb_ptr_old->xmax - bb_ptr_old->xmin + 1)*(bb_ptr_old->ymax - bb_ptr_old->ymin + 1)); + } + } + for(int i = bb_ptr_new->xmin; i < bb_ptr_new->xmax; i++){ + for(int j = bb_ptr_new->ymin; j < bb_ptr_new->ymax; j++){ + cong_matrix_new[i][j] += get_net_wirelength_estimate(net_id,bb_ptr_new)/double((bb_ptr_new->xmax - bb_ptr_new->xmin + 1)*(bb_ptr_new->ymax - bb_ptr_new->ymin + 1)); + } + } +} + + +static void get_cong_matrix(ClusterNetId net_id, t_bb* bbptr) { + /* 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=bbptr->xmin;ixmax;i++){ + for(int j=bbptr->ymin;jymax;j++){ + cong_matrix[i][j] += get_net_wirelength_estimate(net_id,bbptr)/double((bbptr->xmax - bbptr->xmin + 1)*(bbptr->ymax - bbptr->ymin + 1)); + } + } +} + + +static 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;imax_width){ + avg+=cong_matrix_new[i][j]-max_width; + num+=1.0; + } + } + } + + for(int i=0;i costs.bb_cost * ERROR_TOL) { VTR_LOG_ERROR( "bb_cost_check: %g and bb_cost: %g differ in check_place.\n", @@ -2987,31 +3186,31 @@ static int check_block_placement_consistency() { VTR_LOG_ERROR( "%d blocks were placed at grid location (%d,%d,%d), but location capacity is %d.\n", place_ctx.grid_blocks.get_usage(tile_loc), i, j, layer_num, - type->capacity); + type->capacity); + error++; + } + int usage_check = 0; + for (int k = 0; k < type->capacity; k++) { + auto bnum = place_ctx.grid_blocks.block_at_location({i, j, k, layer_num}); + if (EMPTY_BLOCK_ID == bnum || INVALID_BLOCK_ID == bnum) + continue; + + auto logical_block = cluster_ctx.clb_nlist.block_type(bnum); + auto physical_tile = type; + + if (physical_tile_type(bnum) != physical_tile) { + VTR_LOG_ERROR( + "Block %zu type (%s) does not match grid location (%zu,%zu, %d) type (%s).\n", + size_t(bnum), logical_block->name, i, j, layer_num, physical_tile->name); error++; } - int usage_check = 0; - for (int k = 0; k < type->capacity; k++) { - auto bnum = place_ctx.grid_blocks.block_at_location({i, j, k, layer_num}); - if (EMPTY_BLOCK_ID == bnum || INVALID_BLOCK_ID == bnum) - continue; - - auto logical_block = cluster_ctx.clb_nlist.block_type(bnum); - auto physical_tile = type; - - if (physical_tile_type(bnum) != physical_tile) { - VTR_LOG_ERROR( - "Block %zu type (%s) does not match grid location (%zu,%zu, %d) type (%s).\n", - size_t(bnum), logical_block->name, i, j, layer_num, physical_tile->name); - error++; - } - - auto& loc = place_ctx.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)) { - VTR_LOG_ERROR( - "Block %zu's location is (%d,%d,%d) but found in grid at (%zu,%zu,%d,%d).\n", + + auto& loc = place_ctx.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)) { + 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, @@ -3020,23 +3219,23 @@ static int check_block_placement_consistency() { tile_loc.y, tile_loc.layer_num, layer_num); - error++; - } - ++usage_check; - bdone[bnum]++; + error++; } - if (usage_check != place_ctx.grid_blocks.get_usage(tile_loc)) { - VTR_LOG_ERROR( - "%d block(s) were placed at location (%d,%d,%d), but location contains %d block(s).\n", + ++usage_check; + bdone[bnum]++; + } + if (usage_check != place_ctx.grid_blocks.get_usage(tile_loc)) { + VTR_LOG_ERROR( + "%d block(s) were placed at location (%d,%d,%d), but location contains %d block(s).\n", place_ctx.grid_blocks.get_usage(tile_loc), tile_loc.x, tile_loc.y, tile_loc.layer_num, usage_check); - error++; - } + error++; } } + } } /* Check that every block exists in the device_ctx.grid and cluster_ctx.blocks arrays somewhere. */ @@ -3145,13 +3344,13 @@ static void update_screen_debug() { static void print_place_status_header() { VTR_LOG( - "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); + "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------ ---------------\n"); VTR_LOG( - "Tnum Time T Av Cost Av BB Cost Av TD Cost CPD sTNS sWNS Ac Rate Std Dev R lim Crit Exp Tot Moves Alpha\n"); + "Tnum Time T Av Cost Av BB Cost Av TD Cost CPD sTNS sWNS Ac Rate Std Dev R lim Crit Exp Tot Moves Alpha congestion_cost\n"); VTR_LOG( - " (sec) (ns) (ns) (ns) \n"); + " (sec) (ns) (ns) (ns) \n"); VTR_LOG( - "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); + "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------ ---------------\n"); } static void print_place_status(const t_annealing_state& state, @@ -3167,11 +3366,11 @@ static void print_place_status(const t_annealing_state& state, "%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); + state.rlim, state.crit_exponent, stats.av_cong_cost); pretty_print_uint(" ", tot_moves, 9, 3); @@ -3265,6 +3464,7 @@ static void print_placement_move_types_stats( int count = 0; int num_of_avail_moves = move_type_stat.blk_type_moves.size() / get_num_agent_types(); + // VTR_LOG("\n\nPercentage of different move types and block types:\n"); //Print placement information for each block type for (auto itype : device_ctx.logical_block_types) { //Skip non-existing block types in the netlist @@ -3321,10 +3521,10 @@ static void calculate_reward_and_process_outcome( } else if (reward_fun == WL_BIASED_RUNTIME_AWARE) { if (delta_c < 0) { float reward = -1 - * (move_outcome_stats.delta_cost_norm - + (0.5 - timing_bb_factor) + * (move_outcome_stats.delta_cost_norm + + (0.5 - timing_bb_factor) * move_outcome_stats.delta_timing_cost_norm - + timing_bb_factor + + timing_bb_factor * move_outcome_stats.delta_bb_cost_norm); move_generator.process_outcome(reward, reward_fun); } else { diff --git a/vpr/src/place/place_util.cpp b/vpr/src/place/place_util.cpp index 75ff2d2bf12..5ac864b49e7 100644 --- a/vpr/src/place/place_util.cpp +++ b/vpr/src/place/place_util.cpp @@ -65,6 +65,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; + 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 { @@ -289,6 +290,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.; @@ -301,6 +303,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); } @@ -310,10 +313,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 cc903cf4f71..d2ce7eca12f 100644 --- a/vpr/src/place/place_util.h +++ b/vpr/src/place/place_util.h @@ -51,6 +51,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.; double noc_aggregate_bandwidth_cost = 0.; double noc_aggregate_bandwidth_cost_norm = 0.; double noc_latency_cost = 0.; @@ -190,6 +192,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; From c30a95168dcfaebc021c55b389d5f407bb4981ee Mon Sep 17 00:00:00 2001 From: Milad Ebrahimipour Date: Thu, 31 Aug 2023 01:48:06 -0400 Subject: [PATCH 2/2] Adding congestion-aware placement --- vpr/src/base/SetupVPR.cpp | 1 + vpr/src/base/read_options.cpp | 26 +++++++++++++++++++++----- vpr/src/base/read_options.h | 1 + vpr/src/base/vpr_types.h | 6 ++++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index efef48ed4c1..8480591bcf4 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -641,6 +641,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; diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index ad935c44faa..e1048e82d1c 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -397,6 +397,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(), ", ") << ")"; @@ -418,6 +420,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"); @@ -426,7 +430,7 @@ struct ParsePlaceAlgorithm { } std::vector default_choices() { - return {"bounding_box", "criticality_timing", "slack_timing"}; + return {"bounding_box", "criticality_timing", "slack_timing", "congestion_aware"}; } }; @@ -1344,6 +1348,8 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg " 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" @@ -1928,9 +1934,10 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg "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") @@ -1940,9 +1947,10 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg "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") @@ -2130,6 +2138,14 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg " 0.0 focuses completely on wirelength, 1.0 completely on timing") .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("1.0") + .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") diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 97645367680..d94c0396ec6 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -155,6 +155,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 7b98cc2c0e0..363b8ef1c2d 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 }; /** @@ -1015,7 +1016,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. @@ -1147,6 +1148,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;