|
| 1 | +#include "router_lookahead_extended_map.h" |
| 2 | + |
| 3 | +#include <vector> |
| 4 | +#include <queue> |
| 5 | + |
| 6 | +#include "rr_node.h" |
| 7 | +#include "router_lookahead_map_utils.h" |
| 8 | +#include "router_lookahead_sampling.h" |
| 9 | +#include "globals.h" |
| 10 | +#include "vtr_math.h" |
| 11 | +#include "vtr_time.h" |
| 12 | +#include "echo_files.h" |
| 13 | +#include "rr_graph.h" |
| 14 | + |
| 15 | +#include "route_timing.h" |
| 16 | +#include "route_common.h" |
| 17 | + |
| 18 | +#if defined(VPR_USE_TBB) |
| 19 | +# include <tbb/parallel_for_each.h> |
| 20 | +# include <tbb/mutex.h> |
| 21 | +#endif |
| 22 | + |
| 23 | +/* we're profiling routing cost over many tracks for each wire type, so we'll |
| 24 | + * have many cost entries at each |dx|,|dy| offset. There are many ways to |
| 25 | + * "boil down" the many costs at each offset to a single entry for a given |
| 26 | + * (wire type, chan_type) combination we can take the smallest cost, the |
| 27 | + * average, median, etc. This define selects the method we use. |
| 28 | + * |
| 29 | + * NOTE: Currently, only SMALLEST is supported. |
| 30 | + * |
| 31 | + * See e_representative_entry_method */ |
| 32 | +#define REPRESENTATIVE_ENTRY_METHOD util::SMALLEST |
| 33 | + |
| 34 | +#define LOOKAHEAD_EXTENDED_MAP_PRINT_COST_MAPS |
| 35 | + |
| 36 | +// Don't continue storing a path after hitting a lower-or-same cost entry. |
| 37 | +static constexpr bool BREAK_ON_MISS = false; |
| 38 | + |
| 39 | +static constexpr int MIN_PATH_COUNT = 1000; |
| 40 | + |
| 41 | +// compute the cost maps for lookahead |
| 42 | +void ExtendedMapLookahead::compute(const std::vector<t_segment_inf>& segment_inf) { |
| 43 | + this->compute_router_src_opin_lookahead(); |
| 44 | + this->compute_router_chan_ipin_lookahead(); |
| 45 | + |
| 46 | + vtr::ScopedStartFinishTimer timer("Computing connection box lookahead map"); |
| 47 | + |
| 48 | + // Initialize rr_node_route_inf if not already |
| 49 | + alloc_and_load_rr_node_route_structs(); |
| 50 | + |
| 51 | + size_t num_segments = segment_inf.size(); |
| 52 | + std::vector<SampleRegion> sample_regions = find_sample_regions(num_segments); |
| 53 | + |
| 54 | + /* free previous delay map and allocate new one */ |
| 55 | + auto& device_ctx = g_vpr_ctx.device(); |
| 56 | + cost_map_.set_counts(segment_inf.size()); |
| 57 | + cost_map_.build_segment_map(); |
| 58 | + |
| 59 | + VTR_ASSERT(REPRESENTATIVE_ENTRY_METHOD == util::SMALLEST); |
| 60 | + util::RoutingCosts all_delay_costs; |
| 61 | + util::RoutingCosts all_base_costs; |
| 62 | + |
| 63 | + /* run Dijkstra's algorithm for each segment type & channel type combination */ |
| 64 | +#if defined(VPR_USE_TBB) |
| 65 | + tbb::mutex all_costs_mutex; |
| 66 | + tbb::parallel_for_each(sample_regions, [&](const SampleRegion& region) { |
| 67 | +#else |
| 68 | + for (const auto& region : sample_regions) { |
| 69 | +#endif |
| 70 | + // holds the cost entries for a run |
| 71 | + util::RoutingCosts delay_costs; |
| 72 | + util::RoutingCosts base_costs; |
| 73 | + int total_path_count = 0; |
| 74 | + std::vector<bool> node_expanded(device_ctx.rr_nodes.size()); |
| 75 | + std::vector<util::Search_Path> paths(device_ctx.rr_nodes.size()); |
| 76 | + |
| 77 | + for (auto& point : region.points) { |
| 78 | + // statistics |
| 79 | + vtr::Timer run_timer; |
| 80 | + float max_delay_cost = 0.f; |
| 81 | + float max_base_cost = 0.f; |
| 82 | + int path_count = 0; |
| 83 | + for (auto node_ind : point.nodes) { |
| 84 | + { |
| 85 | + auto result = run_dijkstra<util::PQ_Entry_Delay>(node_ind, &node_expanded, &paths, &delay_costs); |
| 86 | + max_delay_cost = std::max(max_delay_cost, result.first); |
| 87 | + path_count += result.second; |
| 88 | + } |
| 89 | + { |
| 90 | + auto result = run_dijkstra<util::PQ_Entry_Base_Cost>(node_ind, &node_expanded, &paths, &base_costs); |
| 91 | + max_base_cost = std::max(max_base_cost, result.first); |
| 92 | + path_count += result.second; |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + if (path_count > 0) { |
| 97 | + VTR_LOG("Expanded %d paths of segment type %s(%d) starting at (%d, %d) from %d segments, max_cost %e %e (%g paths/sec)\n", |
| 98 | + path_count, segment_inf[region.segment_type].name.c_str(), region.segment_type, |
| 99 | + point.location.x(), point.location.y(), |
| 100 | + (int)point.nodes.size(), |
| 101 | + max_delay_cost, max_base_cost, |
| 102 | + path_count / run_timer.elapsed_sec()); |
| 103 | + } |
| 104 | + |
| 105 | + total_path_count += path_count; |
| 106 | + if (total_path_count > MIN_PATH_COUNT) { |
| 107 | + break; |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | +#if defined(VPR_USE_TBB) |
| 112 | + all_costs_mutex.lock(); |
| 113 | +#endif |
| 114 | + |
| 115 | + if (total_path_count == 0) { |
| 116 | + VTR_LOG_WARN("No paths found for sample region %s(%d, %d)\n", |
| 117 | + segment_inf[region.segment_type].name.c_str(), region.grid_location.x(), region.grid_location.y()); |
| 118 | + } |
| 119 | + |
| 120 | + // combine the cost map from this run with the final cost maps for each segment |
| 121 | + for (const auto& cost : delay_costs) { |
| 122 | + const auto& val = cost.second; |
| 123 | + auto result = all_delay_costs.insert(std::make_pair(cost.first, val)); |
| 124 | + if (!result.second) { |
| 125 | + // implements REPRESENTATIVE_ENTRY_METHOD == SMALLEST |
| 126 | + result.first->second = std::min(result.first->second, val); |
| 127 | + } |
| 128 | + } |
| 129 | + for (const auto& cost : base_costs) { |
| 130 | + const auto& val = cost.second; |
| 131 | + auto result = all_base_costs.insert(std::make_pair(cost.first, val)); |
| 132 | + if (!result.second) { |
| 133 | + // implements REPRESENTATIVE_ENTRY_METHOD == SMALLEST |
| 134 | + result.first->second = std::min(result.first->second, val); |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | +#if defined(VPR_USE_TBB) |
| 139 | + all_costs_mutex.unlock(); |
| 140 | + }); |
| 141 | +#else |
| 142 | + } |
| 143 | +#endif |
| 144 | + |
| 145 | + VTR_LOG("Combining results\n"); |
| 146 | + /* boil down the cost list in routing_cost_map at each coordinate to a |
| 147 | + * representative cost entry and store it in the lookahead cost map */ |
| 148 | + cost_map_.set_cost_map(all_delay_costs, all_base_costs); |
| 149 | + |
| 150 | +// diagnostics |
| 151 | +#if defined(LOOKAHEAD_EXTENDED_MAP_PRINT_COST_ENTRIES) |
| 152 | + for (auto& cost : all_costs) { |
| 153 | + const auto& key = cost.first; |
| 154 | + const auto& val = cost.second; |
| 155 | + VTR_LOG("%d -> %d (%d, %d): %g, %g\n", |
| 156 | + val.from_node, val.to_node, |
| 157 | + key.delta.x(), key.delta.y(), |
| 158 | + val.cost_entry.delay, val.cost_entry.congestion); |
| 159 | + } |
| 160 | +#endif |
| 161 | + |
| 162 | +#if defined(LOOKAHEAD_EXTENDED_MAP_PRINT_COST_MAPS) |
| 163 | + for (int iseg = 0; iseg < (ssize_t)num_segments; iseg++) { |
| 164 | + VTR_LOG("cost map for %s(%d)\n", |
| 165 | + segment_inf[iseg].name.c_str(), iseg); |
| 166 | + cost_map_.print(iseg); |
| 167 | + } |
| 168 | +#endif |
| 169 | + |
| 170 | +#if defined(LOOKAHEAD_EXTENDED_MAP_PRINT_EMPTY_MAPS) |
| 171 | + for (std::pair<int, int> p : cost_map_.list_empty()) { |
| 172 | + int ichan, iseg; |
| 173 | + std::tie(ichan, iseg) = p; |
| 174 | + VTR_LOG("cost map for %s(%d), chan %d EMPTY\n", |
| 175 | + segment_inf[iseg].name.c_str(), iseg, box_id); |
| 176 | + } |
| 177 | +#endif |
| 178 | +} |
| 179 | + |
| 180 | +std::pair<int, int> ExtendedMapLookahead::get_xy_deltas(const RRNodeId from_node, const RRNodeId to_node) const { |
| 181 | + auto& device_ctx = g_vpr_ctx.device(); |
| 182 | + auto& rr_graph = device_ctx.rr_nodes; |
| 183 | + |
| 184 | + int from_x = vtr::nint((rr_graph.node_xlow(from_node) + rr_graph.node_xhigh(from_node)) / 2.); |
| 185 | + int from_y = vtr::nint((rr_graph.node_ylow(from_node) + rr_graph.node_yhigh(from_node)) / 2.); |
| 186 | + |
| 187 | + int to_x = vtr::nint((rr_graph.node_xlow(to_node) + rr_graph.node_xhigh(to_node)) / 2.); |
| 188 | + int to_y = vtr::nint((rr_graph.node_ylow(to_node) + rr_graph.node_yhigh(to_node)) / 2.); |
| 189 | + |
| 190 | + int dx, dy; |
| 191 | + dx = to_x - from_x; |
| 192 | + dy = to_y - from_y; |
| 193 | + |
| 194 | + return std::make_pair(dx, dy); |
| 195 | +} |
0 commit comments