Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Router Lookahead Profiler #2683

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
739029b
Created lookahead profiler (restored changes from previous branch)
Jun 26, 2024
aa5570b
LookaheadProfiler now saves sink node info for efficiency
Jun 26, 2024
c88364a
Merge branch 'master' into feature_router_lookahead_verifier
Aug 12, 2024
d406c57
Refactor
Aug 12, 2024
c86ff7c
Added command-line option for profiler
Aug 12, 2024
ddf34eb
Commented LookaheadProfiler
Aug 12, 2024
0826ad7
More comments
Aug 12, 2024
e8ea974
Moved parse_lookahead_data.py
Aug 12, 2024
0b5a752
Moved, refactored, and commented parse_lookahead_data.py
Aug 12, 2024
cbe1334
Fixed multithreading in parsing script
Aug 13, 2024
80086ff
More refactoring, commenting
Aug 13, 2024
c747096
Fixed linting errors in python script
Aug 14, 2024
e753094
Refactored LookaheadProfiler
Aug 14, 2024
d9f4ee3
Eliminated profile_lookahead parameter in update_from_heap
Aug 14, 2024
dfab0a8
Allowed users to enter a file name for profiler output
Aug 14, 2024
c9801b7
Improved multiprocessing efficiency in script
Aug 14, 2024
7fe0b55
Cleaned a few function calls
Aug 15, 2024
c8b196e
LookaheadProfiler::clear() now uses vtr::release_memory()
Aug 15, 2024
ed4460d
Requirements for script added to requirements.txt
Aug 15, 2024
ab2c731
Updated some regtest seeds and golden results
Aug 15, 2024
2db5325
Merge branch 'master' into feature_router_lookahead_verifier
Aug 15, 2024
17ab565
#ifdef-ed extra heap data and added CI test
Aug 20, 2024
595af59
Merge branch 'master' into feature_router_lookahead_verifier
Aug 20, 2024
2f10ec5
Fixed compilation warnings
Aug 20, 2024
9bcad70
Fixed error in record()
Aug 20, 2024
c05e498
Updated golden results
Aug 21, 2024
643811b
Merge branch 'master' into feature_router_lookahead_verifier
Aug 22, 2024
1c9bb58
More updated golden results
Aug 23, 2024
deddc8a
Disabled RCV support for RouterLookahead, comments
Aug 28, 2024
971eebc
Merge branch 'master' into feature_router_lookahead_verifier
Aug 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -156,6 +156,11 @@ jobs:
params: '-DVTR_ASSERT_LEVEL=3 -DWITH_BLIFEXPLORER=on -DVPR_USE_EZGL=on -DVPR_USE_SERVER=off',
suite: 'vtr_reg_basic'
},
{
name: 'Basic with PROFILE_LOOKAHEAD',
params: '-DVTR_ASSERT_LEVEL=3 -DVPR_PROFILE_LOOKAHEAD=on',
suite: 'vtr_reg_basic'
},
{
name: 'Basic with CAPNPROTO disabled',
params: '-DCMAKE_COMPILE_WARNING_AS_ERROR=on -DVTR_ASSERT_LEVEL=3 -DWITH_BLIFEXPLORER=on -DVTR_ENABLE_CAPNPROTO=off',
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -42,6 +42,9 @@ option(VTR_ENABLE_CAPNPROTO "Enable capnproto binary serialization support in VP
#Allow the user to decide whether to compile the server module
option(VPR_USE_SERVER "Specify whether vpr enables the server mode" ON)

#Allow the user to decide whether to profile the router lookahead
option(VPR_PROFILE_LOOKAHEAD "Specify whether to enable the router LookaheadProfiler" OFF)

#Allow the user to enable/disable VPR analytic placement
#VPR option --enable_analytic_placer is also required for Analytic Placement
option(VPR_ANALYTIC_PLACE "Enable analytic placement in VPR." ON)
6 changes: 6 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
prettytable
lxml
psutil
scikit-learn
matplotlib
distinctipy
colour
seaborn
pandas
numpy
scipy

# Python linter and formatter
click==8.0.2 # Our version of black needs an older version of click (https://stackoverflow.com/questions/71673404/importerror-cannot-import-name-unicodefun-from-click)
black==21.4b0
9 changes: 8 additions & 1 deletion utils/route_diag/src/main.cpp
Original file line number Diff line number Diff line change
@@ -130,7 +130,14 @@ static void do_one_route(const Netlist<>& net_list,
VTR_ASSERT(cheapest.index == sink_node);

vtr::optional<const RouteTreeNode&> rt_node_of_sink;
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(&cheapest, OPEN, nullptr, router_opts.flat_routing);
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(/*htpr=*/&cheapest,
/*target_net_pin_index=*/OPEN,
/*spatial_rt_lookup=*/nullptr,
router_opts.flat_routing,
router.get_router_lookahead(),
cost_params,
net_list,
conn_params.net_id_);

//find delay
float net_delay = rt_node_of_sink.value().Tdel;
12 changes: 11 additions & 1 deletion vpr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -51,6 +51,16 @@ else()
message(STATUS "Server mode is disabled${SERVER_DISABILED_REASON}")
endif()

#Handle router lookahead profiler setup
set(ROUTER_DEFINES "")

if (VPR_PROFILE_LOOKAHEAD)
list(APPEND ROUTER_DEFINES "-DPROFILE_LOOKAHEAD")
message(STATUS "Router lookahead profiler enabled")
else ()
message(STATUS "Router lookahead profiler disabled")
endif ()

#
# Build Configuration
#
@@ -164,7 +174,7 @@ if (VPR_USE_EZGL STREQUAL "on")

endif()

target_compile_definitions(libvpr PUBLIC ${GRAPHICS_DEFINES} ${SERVER_DEFINES})
target_compile_definitions(libvpr PUBLIC ${GRAPHICS_DEFINES} ${SERVER_DEFINES} ${ROUTER_DEFINES})

if(${VTR_ENABLE_CAPNPROTO})
target_link_libraries(libvpr libvtrcapnproto)
2 changes: 2 additions & 0 deletions vpr/src/base/SetupVPR.cpp
Original file line number Diff line number Diff line change
@@ -486,6 +486,8 @@ static void SetupRouterOpts(const t_options& Options, t_router_opts* RouterOpts)
RouterOpts->write_intra_cluster_router_lookahead = Options.write_intra_cluster_router_lookahead;
RouterOpts->read_intra_cluster_router_lookahead = Options.read_intra_cluster_router_lookahead;

RouterOpts->lookahead_profiling_output = Options.lookahead_profiling_output;

RouterOpts->router_heap = Options.router_heap;
RouterOpts->exit_after_first_routing_iteration = Options.exit_after_first_routing_iteration;

8 changes: 8 additions & 0 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
@@ -1673,6 +1673,14 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help("Writes the intra-cluster lookahead data to the specified file.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.lookahead_profiling_output, "--profile_router_lookahead")
.help(
"For every routed sink, record the cost, delay, and congestion estimated by the router lookahead and the "
"actual cost, delay, and congestion, from every node along each route to the sink. These results, along with many "
"other attributes of the node, are recorded into the file name provided. Used to assist in debugging or validating "
"the router lookahead. File extension must be .csv.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.read_placement_delay_lookup, "--read_placement_delay_lookup")
.help(
"Reads the placement delay lookup from the specified file instead of computing it.")
2 changes: 2 additions & 0 deletions vpr/src/base/read_options.h
Original file line number Diff line number Diff line change
@@ -44,6 +44,8 @@ struct t_options {
argparse::ArgValue<std::string> write_intra_cluster_router_lookahead;
argparse::ArgValue<std::string> read_intra_cluster_router_lookahead;

argparse::ArgValue<std::string> lookahead_profiling_output;

argparse::ArgValue<std::string> write_block_usage;

/* Stage Options */
8 changes: 8 additions & 0 deletions vpr/src/base/vpr_context.h
Original file line number Diff line number Diff line change
@@ -46,6 +46,9 @@ class PostClusterDelayCalculator;

#endif /* NO_SERVER */

// Forward declaration
class LookaheadProfiler;

/**
* @brief A Context is collection of state relating to a particular part of VPR
*
@@ -515,6 +518,11 @@ struct RoutingContext : public Context {
* @brief User specified routing constraints
*/
UserRouteConstraints constraints;

/**
* @brief Writes out information used to profile the accuracy of the router lookahead.
*/
LookaheadProfiler lookahead_profiler;
};

/**
33 changes: 23 additions & 10 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
@@ -1400,6 +1400,10 @@ struct t_router_opts {
std::string write_intra_cluster_router_lookahead;
std::string read_intra_cluster_router_lookahead;

///@brief The name of the output .csv file when PROFILE_LOOKAHEAD and --profile_router_lookahead are used.
///If the string is empty, there will be no output.
std::string lookahead_profiling_output;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add doxygen comment for this (can use ///).
If it's an empty string does it not get printed? (If so, say that).


e_heap_type router_heap;
bool exit_after_first_routing_iteration;

@@ -1667,23 +1671,32 @@ constexpr bool is_src_sink(e_rr_type type) { return (type == SOURCE || type == S
* @brief Extra information about each rr_node needed only during routing
* (i.e. during the maze expansion).
*
* @param prev_edge ID of the edge (globally unique edge ID in the RR Graph)
* that was used to reach this node from the previous node.
* If there is no predecessor, prev_edge = NO_PREVIOUS.
* @param acc_cost Accumulated cost term from previous Pathfinder iterations.
* @param path_cost Total cost of the path up to and including this node +
* the expected cost to the target if the timing_driven router
* is being used.
* @param backward_path_cost Total cost of the path up to and including this
* node.
* @param occ The current occupancy of the associated rr node
* @param prev_edge ID of the edge (globally unique edge ID in the RR Graph)
* that was used to reach this node from the previous node.
* If there is no predecessor, prev_edge = NO_PREVIOUS.
* @param acc_cost Accumulated cost term from previous Pathfinder iterations.
* @param path_cost Total cost of the path up to and including this node +
* the expected cost to the target if the timing_driven router
* is being used.
* @param backward_path_cost Total cost of the path up to and including
* this node.
* @param occ The current occupancy of the associated rr node
*/
struct t_rr_node_route_inf {
RREdgeId prev_edge;

float acc_cost;
float path_cost;
float backward_path_cost;
#ifdef PROFILE_LOOKAHEAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a brief comment saying why this extra data is needed for PROFILE_LOOKAHEAD, and that we conditionally compile it because this is a hot and large data structure.

// This data is needed for the LookaheadProfiler, when enabled. It is only conditionally
// compiled since this struct is a hot and large data structure.

///@brief Total delay in the path up to and including this node.
float backward_path_delay;
///@brief Total congestion in the path up to and including this node.
float backward_path_congestion;
#endif

public: //Accessors
short occ() const { return occ_; }
20 changes: 18 additions & 2 deletions vpr/src/place/timing_place_lookup.cpp
Original file line number Diff line number Diff line change
@@ -110,6 +110,22 @@ static void generic_compute_matrix_iterative_astar(
const std::set<std::string>& allowed_types,
bool /***/);

/**
* @brief Compute delta delay matrix using Djikstra's algorithm to find shortest paths from a IPIN at the
* source location to OPINs within (start_x, start_y) to (end_x, end_y).
*
* @param route_profiler Only used to call get_net_list(), which is passed into
* calculate_all_path_delays_from_rr_node(), which is needed for the LookaheadProfiler.
* @param matrix The matrix to be filled.
* @param layer_num The layer of the source and sink nodes to be sampled.
* @param (source_x, source_y) The coordinates of the tile to sample an IPIN at.
* @param (start_x, start_y, end_x, end_y) The bounds within which OPINs should be sampled.
* @param router_opts
* @param measure_directconnect Whether to measure/include direct connects.
* @param allowed_types The allowed tile type names for the source location. If this vector is empty, all
* names are allowed. If the source tile type is not allowed, the matrix is filled with EMPTY_DELTA.
* @param is_flat Whether flat routing is being used.
*/
static void generic_compute_matrix_dijkstra_expansion(
RouterDelayProfiler& route_profiler,
vtr::Matrix<std::vector<float>>& matrix,
@@ -441,7 +457,7 @@ static void add_delay_to_matrix(
}

static void generic_compute_matrix_dijkstra_expansion(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add a doxygen comment for this, detailing what you know about the function and its arguments (and for sure what the route_profiler does).

RouterDelayProfiler& /*route_profiler*/,
RouterDelayProfiler& route_profiler,
vtr::Matrix<std::vector<float>>& matrix,
int layer_num,
int source_x,
@@ -489,7 +505,7 @@ static void generic_compute_matrix_dijkstra_expansion(
RRNodeId source_rr_node = device_ctx.rr_graph.node_lookup().find_node(layer_num, source_x, source_y, SOURCE, driver_ptc);

VTR_ASSERT(source_rr_node != RRNodeId::INVALID());
auto delays = calculate_all_path_delays_from_rr_node(source_rr_node, router_opts, is_flat);
auto delays = calculate_all_path_delays_from_rr_node(source_rr_node, router_opts, is_flat, route_profiler.get_net_list());

bool path_to_all_sinks = true;
for (int sink_x = start_x; sink_x <= end_x; sink_x++) {
49 changes: 45 additions & 4 deletions vpr/src/route/connection_router.cpp
Original file line number Diff line number Diff line change
@@ -239,7 +239,10 @@ t_heap* ConnectionRouter<Heap>::timing_driven_route_connection_from_heap(RRNodeI
// This is then placed into the traceback so that the correct path is returned
// TODO: This can be eliminated by modifying the actual traceback function in route_timing
if (rcv_path_manager.is_enabled()) {
rcv_path_manager.insert_backwards_path_into_traceback(cheapest->path_data, cheapest->cost, cheapest->backward_path_cost, route_ctx);
rcv_path_manager.insert_backwards_path_into_traceback(cheapest->path_data,
cheapest->cost,
cheapest->backward_path_cost,
route_ctx);
}
VTR_LOGV_DEBUG(router_debug_, " Found target %8d (%s)\n", inode, describe_rr_node(device_ctx.rr_graph, device_ctx.grid, device_ctx.rr_indexed_data, inode, is_flat_).c_str());
break;
@@ -552,6 +555,10 @@ void ConnectionRouter<Heap>::timing_driven_add_to_heap(const t_conn_cost_params&
// Costs initialized to current
next.cost = std::numeric_limits<float>::infinity(); //Not used directly
next.backward_path_cost = current->backward_path_cost;
#ifdef PROFILE_LOOKAHEAD
next.backward_path_delay = current->backward_path_delay;
next.backward_path_congestion = current->backward_path_congestion;
#endif

// path_data variables are initialized to current values
if (rcv_path_manager.is_enabled() && current->path_data) {
@@ -597,6 +604,10 @@ void ConnectionRouter<Heap>::timing_driven_add_to_heap(const t_conn_cost_params&
next_ptr->cost = next.cost;
next_ptr->R_upstream = next.R_upstream;
next_ptr->backward_path_cost = next.backward_path_cost;
#ifdef PROFILE_LOOKAHEAD
next_ptr->backward_path_delay = next.backward_path_delay;
next_ptr->backward_path_congestion = next.backward_path_congestion;
#endif
next_ptr->index = to_node;
next_ptr->set_prev_edge(from_edge);

@@ -784,6 +795,10 @@ void ConnectionRouter<Heap>::evaluate_timing_driven_node_costs(t_heap* to,
//Update the backward cost (upstream already included)
to->backward_path_cost += (1. - cost_params.criticality) * cong_cost; //Congestion cost
to->backward_path_cost += cost_params.criticality * Tdel; //Delay cost
#ifdef PROFILE_LOOKAHEAD
to->backward_path_delay += Tdel;
to->backward_path_congestion += cong_cost;
#endif

if (cost_params.bend_cost != 0.) {
t_rr_type from_type = rr_graph_->node_type(from_node);
@@ -832,6 +847,10 @@ void ConnectionRouter<Heap>::empty_heap_annotating_node_route_inf() {

rr_node_route_inf_[tmp->index].path_cost = tmp->cost;
rr_node_route_inf_[tmp->index].backward_path_cost = tmp->backward_path_cost;
#ifdef PROFILE_LOOKAHEAD
rr_node_route_inf_[tmp->index].backward_path_delay = tmp->backward_path_delay;
rr_node_route_inf_[tmp->index].backward_path_congestion = tmp->backward_path_congestion;
#endif
modified_rr_node_inf_.push_back(tmp->index);

rcv_path_manager.free_path_struct(tmp->path_data);
@@ -892,6 +911,10 @@ void ConnectionRouter<Heap>::add_route_tree_node_to_heap(
const auto& device_ctx = g_vpr_ctx.device();
const RRNodeId inode = rt_node.inode;
float backward_path_cost = cost_params.criticality * rt_node.Tdel;
#ifdef PROFILE_LOOKAHEAD
float backward_path_delay = rt_node.Tdel;
float backward_path_congestion = 0.0;
#endif
float R_upstream = rt_node.R_upstream;

/* Don't push to heap if not in bounding box: no-op for serial router, important for parallel router */
@@ -913,9 +936,27 @@ void ConnectionRouter<Heap>::add_route_tree_node_to_heap(
tot_cost,
describe_rr_node(device_ctx.rr_graph, device_ctx.grid, device_ctx.rr_indexed_data, inode, is_flat_).c_str());

push_back_node(&heap_, rr_node_route_inf_,
inode, tot_cost, RREdgeId::INVALID(),
backward_path_cost, R_upstream);
#ifndef PROFILE_LOOKAHEAD
push_back_node(&heap_,
rr_node_route_inf_,
inode,
tot_cost,
/*prev_edge=*/RREdgeId::INVALID(),
backward_path_cost,
/*backward_path_delay=*/0.f,
/*backward_path_congestion=*/0.f,
R_upstream);
#else
push_back_node(&heap_,
rr_node_route_inf_,
inode,
tot_cost,
/*prev_edge=*/RREdgeId::INVALID(),
backward_path_cost,
backward_path_delay,
backward_path_congestion,
R_upstream);
#endif
} else {
float expected_total_cost = compute_node_cost_using_rcv(cost_params, inode, target_node, rt_node.Tdel, 0, R_upstream);

10 changes: 10 additions & 0 deletions vpr/src/route/connection_router.h
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#define _CONNECTION_ROUTER_H

#include "connection_router_interface.h"
#include "lookahead_profiler.h"
#include "rr_graph_storage.h"
#include "route_common.h"
#include "router_lookahead.h"
@@ -127,6 +128,11 @@ class ConnectionRouter : public ConnectionRouterInterface {
// Ensure route budgets have been calculated before enabling this
void set_rcv_enabled(bool enable) final;

// Get a const reference to the router's lookahead
const RouterLookahead& get_router_lookahead() const {
return router_lookahead_;
}

private:
// Mark that data associated with rr_node "inode" has been modified, and
// needs to be reset in reset_path_costs.
@@ -148,6 +154,10 @@ class ConnectionRouter : public ConnectionRouterInterface {
route_inf->prev_edge = cheapest->prev_edge();
route_inf->path_cost = cheapest->cost;
route_inf->backward_path_cost = cheapest->backward_path_cost;
#ifdef PROFILE_LOOKAHEAD
route_inf->backward_path_delay = cheapest->backward_path_delay;
route_inf->backward_path_congestion = cheapest->backward_path_congestion;
#endif
}

/** Common logic from timing_driven_route_connection_from_route_tree and
4 changes: 4 additions & 0 deletions vpr/src/route/heap_type.cpp
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ HeapStorage::alloc() {
temp_ptr->set_next_heap_item(nullptr);
temp_ptr->cost = 0.;
temp_ptr->backward_path_cost = 0.;
#ifdef PROFILE_LOOKAHEAD
temp_ptr->backward_path_delay = 0.;
temp_ptr->backward_path_congestion = 0.;
#endif
temp_ptr->R_upstream = 0.;
temp_ptr->index = RRNodeId::INVALID();
temp_ptr->path_data = nullptr;
9 changes: 9 additions & 0 deletions vpr/src/route/heap_type.h
Original file line number Diff line number Diff line change
@@ -18,6 +18,15 @@ struct t_heap {
///@brief The "known" cost of the path up to and including this node. Used only by the timing-driven router. In this case, the
///.cost member contains not only the known backward cost but also an expected cost to the target.
float backward_path_cost = 0.;
#ifdef PROFILE_LOOKAHEAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest adding a comment saying the number of instances of this data structure can be large and it is in hot code, so extra data only needed to profile/verify the lookahead is #ifdef'd

// This data is needed for the LookaheadProfiler, when enabled. It is only conditionally
// compiled since there may be many instances of this struct and it is in hot code.

///@brief The "known" delay in the path up to and including this node. Recorded for LookaheadProfiler during routing.
float backward_path_delay = 0.;
///@brief The "known" congestion in the path up to and including this node. Recorded for LookaheadProfiler during routing.
float backward_path_congestion = 0.;
#endif
///@brief Used only by the timing-driven router. Stores the upstream resistance to ground from this node, including the resistance
/// of the node itself (device_ctx.rr_nodes[index].R).
float R_upstream = 0.;
199 changes: 199 additions & 0 deletions vpr/src/route/lookahead_profiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#include <sstream>

#include "globals.h"
#include "lookahead_profiler.h"
#include "re_cluster_util.h"
#include "router_lookahead_map_utils.h"
#include "vpr_utils.h"
#include "vtr_error.h"
#include "vtr_log.h"

void LookaheadProfiler::set_file_name(const std::string& file_name) {
enabled_ = !file_name.empty();
if (!enabled_)
return;

#ifdef PROFILE_LOOKAHEAD
lookahead_verifier_csv_.open(file_name, std::ios::out);

if (!lookahead_verifier_csv_.is_open()) {
throw vtr::VtrError("Could not open " + file_name, "lookahead_profiler.cpp", 21);
}

lookahead_verifier_csv_
<< "iteration no."
<< ",source node"
<< ",sink node"
<< ",sink block name"
<< ",sink atom block model"
<< ",sink cluster block type"
<< ",sink cluster tile height"
<< ",sink cluster tile width"
<< ",current node"
<< ",node type"
<< ",node length"
<< ",num. nodes from sink"
<< ",delta x"
<< ",delta y"
<< ",actual cost"
<< ",actual delay"
<< ",actual congestion"
<< ",predicted cost"
<< ",predicted delay"
<< ",predicted congestion"
<< ",criticality"
<< "\n";
#else
throw vtr::VtrError("Profiler enabled, but PROFILE_LOOKAHEAD not defined.", "lookahead_profiler.cpp", 47);
#endif
}

void LookaheadProfiler::record(int iteration,
int target_net_pin_index,
const t_conn_cost_params& cost_params,
const RouterLookahead& router_lookahead,
const ParentNetId& net_id,
const Netlist<>& net_list,
const std::vector<RRNodeId>& branch_inodes) {
/**
* This function records data into the output file created in set_file_name(). If that file name was
* an empty string, this function returns. If the output file is not open, VPR will throw an error.
*
* First, we get the RRNodeIds of the sink and source nodes (assumed to be the beginning and end of
* branch_inodes, respectively.
*
* Next, using net_id, net_list, and target_net_pin_index, we obtain the name of the atom block,
* the name of the type of atom block, the name of the type of cluster block, and the tile dimensions
* where the sink node is located.
*
* We then iterate through all other nodes in branch_inodes and calculate the expected and actual cost,
* congestion, and delay from the current node to the sink node, as well as the current node type and
* length, and the xy-deltas to the sink node.
*
* Finally, all this information is written to the output .csv file.
*/

if (!enabled_)
return;

#ifdef PROFILE_LOOKAHEAD
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();

if (!lookahead_verifier_csv_.is_open()) {
throw vtr::VtrError("Output file is not open.", "lookahead_profiler.cpp", 67);
}

// The default value in RouteTree::update_from_heap() is -1; only calls which descend from route_net()
// pass in an iteration value, which is the only context in which we want to profile.
if (iteration < 1)
return;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should have a comment giving an overview of how it works, unless that's already covered in the (to be added) lookahead_profiler.cpp file-scope comment that gives the high-level context.

RRNodeId source_inode = branch_inodes.back(); // Not necessarily a SOURCE node.
RRNodeId sink_inode = branch_inodes.front();

VTR_ASSERT(rr_graph.node_type(sink_inode) == SINK);
VTR_ASSERT(net_id != ParentNetId::INVALID());
VTR_ASSERT(target_net_pin_index != OPEN);

/* Get sink node attributes (atom block name, atom block model, cluster type, tile dimensions) */

if (net_pin_blocks_.find(sink_inode) == net_pin_blocks_.end()) {
net_pin_blocks_[sink_inode] = net_list.net_pin_block(net_id, target_net_pin_index);

AtomBlockId atom_block_id = g_vpr_ctx.atom().nlist.find_block(net_list.block_name(net_pin_blocks_[sink_inode]));
sink_atom_block_[sink_inode] = g_vpr_ctx.atom().nlist.block_model(atom_block_id);

ClusterBlockId cluster_block_id = atom_to_cluster(atom_block_id);
sink_cluster_block_[sink_inode] = g_vpr_ctx.clustering().clb_nlist.block_type(cluster_block_id);

tile_types_[sink_inode] = physical_tile_type(atom_block_id);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't private member variables initialization be done in the constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that I should initialize them as empty maps in the constructor?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I had in mind was initializing them with all sinks ids as key and proper values. However, this can't be done when LookaheadProfiler has a global instance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think storing multiple std::string values for each sink id is not memory efficient. For atom_block_models, cluster_block_types, and tile_dimensions, the number of unique values is very low. Even for atom_block_names where each unique value appears only a few times, you don't need to store multiple copies of each block name.

std::string_view, vtr::interned_string can be used to avoid unnecessary string copies.
It is also possible to store atom and cluster block ids and use global netlist objects to retrieve references to block/model names and tile sizes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to change these variables to store IDs and type pointers. Dereferencing the pointers may be less runtime-efficient, but to use std::string_view, I think I'd have to create a separate std::set which contains all the string_views encountered so far to see if we need to fetch the info for the current node, which seems less clean.


VTR_ASSERT_SAFE(sink_atom_block_.find(sink_inode) != sink_atom_block_.end());
VTR_ASSERT_SAFE(sink_cluster_block_.find(sink_inode) != sink_cluster_block_.end());
VTR_ASSERT_SAFE(tile_types_.find(sink_inode) != tile_types_.end());

const std::string& block_name = net_list.block_name(net_pin_blocks_[sink_inode]);
const std::string atom_block_model = sink_atom_block_[sink_inode]->name;
const std::string cluster_block_type = sink_cluster_block_[sink_inode]->name;
const std::string tile_width = std::to_string(tile_types_[sink_inode]->width);
const std::string tile_height = std::to_string(tile_types_[sink_inode]->height);

/* Iterate through the given path and record information for each node */
for (size_t nodes_from_sink = 2; nodes_from_sink < branch_inodes.size(); ++nodes_from_sink) { // Distance one node away is always 0. (IPIN->SINK)
RRNodeId curr_inode = branch_inodes[nodes_from_sink];

// Calculate the actual cost, delay, and congestion from the current node to the sink.
const t_rr_node_route_inf& curr_node_info = route_ctx.rr_node_route_inf[curr_inode];
const t_rr_node_route_inf& sink_node_info = route_ctx.rr_node_route_inf[sink_inode];

float actual_cost = sink_node_info.backward_path_cost - curr_node_info.backward_path_cost;
float actual_delay = sink_node_info.backward_path_delay - curr_node_info.backward_path_delay;
float actual_congestion = sink_node_info.backward_path_congestion - curr_node_info.backward_path_congestion;

// Get the cost, delay, and congestion estimates made by the lookahead.
// Note: lookahead_cost = lookahead_delay * criticality + lookahead_congestion * (1. - criticality)
float lookahead_cost = router_lookahead.get_expected_cost(curr_inode, sink_inode, cost_params, 0.0);
auto [lookahead_delay, lookahead_congestion] = router_lookahead.get_expected_delay_and_cong_ignore_criticality(curr_inode, sink_inode, cost_params, 0.0);

// Get the difference in the coordinates in the current and sink nodes.
// Note: we are not using util::get_xy_deltas() because this always gives positive values
// unless the current node is the source node. Using util::get_adjusted_rr_position therefore
// gives us more information.
auto [from_x, from_y] = util::get_adjusted_rr_position(curr_inode);
auto [to_x, to_y] = util::get_adjusted_rr_position(sink_inode);

int delta_x = to_x - from_x;
int delta_y = to_y - from_y;

// Get the current node's type and length
std::string node_type_str = rr_graph.node_type_string(curr_inode);
std::string node_length = (node_type_str == "CHANX" || node_type_str == "CHANY")
? std::to_string(rr_graph.node_length(curr_inode))
: "--";

/* Write out all info */

lookahead_verifier_csv_ << iteration << ","; // iteration no.
lookahead_verifier_csv_ << source_inode << ","; // source node
lookahead_verifier_csv_ << sink_inode << ","; // sink node
lookahead_verifier_csv_ << block_name << ","; // sink block name
lookahead_verifier_csv_ << atom_block_model << ","; // sink atom block model
lookahead_verifier_csv_ << cluster_block_type << ","; // sink cluster block type
lookahead_verifier_csv_ << tile_height << ","; // sink cluster tile height
lookahead_verifier_csv_ << tile_width << ","; // sink cluster tile width
lookahead_verifier_csv_ << curr_inode << ","; // current node
lookahead_verifier_csv_ << node_type_str << ","; // node type
lookahead_verifier_csv_ << node_length << ","; // node length
lookahead_verifier_csv_ << nodes_from_sink << ","; // num. nodes from sink
lookahead_verifier_csv_ << delta_x << ","; // delta x
lookahead_verifier_csv_ << delta_y << ","; // delta y
lookahead_verifier_csv_ << actual_cost << ","; // actual cost
lookahead_verifier_csv_ << actual_delay << ","; // actual delay
lookahead_verifier_csv_ << actual_congestion << ","; // actual congestion
lookahead_verifier_csv_ << lookahead_cost << ","; // predicted cost
lookahead_verifier_csv_ << lookahead_delay << ","; // predicted delay
lookahead_verifier_csv_ << lookahead_congestion << ","; // predicted congestion
lookahead_verifier_csv_ << cost_params.criticality; // criticality
lookahead_verifier_csv_ << "\n";
}
#else
throw vtr::VtrError("Profiler enabled, but PROFILE_LOOKAHEAD not defined.", "lookahead_profiler.cpp", 183);
(void)iteration;
(void)target_net_pin_index;
(void)cost_params;
(void)router_lookahead;
(void)net_id;
(void)net_list;
(void)branch_inodes;
#endif
}

void LookaheadProfiler::clear() {
vtr::release_memory(net_pin_blocks_);
vtr::release_memory(sink_atom_block_);
vtr::release_memory(sink_cluster_block_);
vtr::release_memory(tile_types_);
}
83 changes: 83 additions & 0 deletions vpr/src/route/lookahead_profiler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#ifndef VTR_LOOKAHEAD_PROFILER_H
#define VTR_LOOKAHEAD_PROFILER_H

#include <fstream>

#include "connection_router_interface.h"
#include "router_lookahead.h"
#include "rr_graph_fwd.h"

/**
* @brief A class which records information used to profile the router lookahead: most importantly,
* the actual cost (delay and congestion) from nodes to the sink to which they have been routed, as
* well as the lookahead's estimation of this cost.
*
* @warning
* To use the LookaheadProfiler, you must build VPR with CMAKE_PARAMS="-DVPR_PROFILE_LOOKAHEAD=on".
*/
class LookaheadProfiler {
public:
LookaheadProfiler()
: enabled_(false) {}

LookaheadProfiler(const LookaheadProfiler&) = delete;
LookaheadProfiler& operator=(const LookaheadProfiler&) = delete;

/**
* @brief Set the name of the output file.
*
* @note
* Passing in an empty string will disable the profiler.
*
* @param file_name The name of the output csv file.
*/
void set_file_name(const std::string& file_name);

/**
* @brief Record information on nodes on a path from a source to a sink.
*
* @param iteration The router iteration.
* @param target_net_pin_index Target pin of this sink in the net.
* @param cost_params Passed into router_lookahead's methods to obtain expected cost,
* delay, and congestion.
* @param router_lookahead Its methods are called to obtain the expected cost, delay,
* and congestion to the node represented by target_net_pin_index from all other nodes
* in branch_inodes.
* @param net_id Used to obtain atom and cluster block IDs.
* @param net_list Used to obtain atom and cluster block IDs.
* @param branch_inodes A backwards path of nodes, starting at a sink.
*
* @warning
* branch_inodes must be a backwards path, starting at a sink node.
*/
void record(int iteration,
int target_net_pin_index,
const t_conn_cost_params& cost_params,
const RouterLookahead& router_lookahead,
const ParentNetId& net_id,
const Netlist<>& net_list,
const std::vector<RRNodeId>& branch_inodes);

/**
* @brief Clear the profiler's private caches to free memory.
*/
void clear();

private:
///@brief Whether to record lookahead info.
bool enabled_;
///@brief The output filestream.
std::ofstream lookahead_verifier_csv_;
///@brief The output file name.
std::string file_name_;
///@brief A map from sink node IDs to their atom blocks' IDs.
std::unordered_map<RRNodeId, ParentBlockId> net_pin_blocks_;
///@brief A map from sink node IDs to a pointer to the model of their atom blocks.
std::unordered_map<RRNodeId, const t_model*> sink_atom_block_;
///@brief A map from sink node IDs to a pointer to their cluster blocks.
std::unordered_map<RRNodeId, t_logical_block_type_ptr> sink_cluster_block_;
///@brief A map from sink node IDs to a pointer to their tiles' types.
std::unordered_map<RRNodeId, t_physical_tile_type_ptr> tile_types_;
};

#endif //VTR_LOOKAHEAD_PROFILER_H
6 changes: 6 additions & 0 deletions vpr/src/route/route.cpp
Original file line number Diff line number Diff line change
@@ -221,6 +221,9 @@ bool route(const Netlist<>& net_list,
choking_spots,
is_flat);

// Enable lookahead profiling if command-line option used
route_ctx.lookahead_profiler.set_file_name(router_opts.lookahead_profiling_output);

RouterStats router_stats;
float prev_iter_cumm_time = 0;
vtr::Timer iteration_timer;
@@ -563,6 +566,9 @@ bool route(const Netlist<>& net_list,
// profiling::time_on_criticality_analysis();
}

// Clear data accumulated in LookaheadProfiler
route_ctx.lookahead_profiler.clear();

/* Write out partition tree logs (no-op if debug option not set) */
PartitionTreeDebug::write("partition_tree.log");

20 changes: 17 additions & 3 deletions vpr/src/route/route_common.cpp
Original file line number Diff line number Diff line change
@@ -289,6 +289,10 @@ void reset_path_costs(const std::vector<RRNodeId>& visited_rr_nodes) {
for (auto node : visited_rr_nodes) {
route_ctx.rr_node_route_inf[node].path_cost = std::numeric_limits<float>::infinity();
route_ctx.rr_node_route_inf[node].backward_path_cost = std::numeric_limits<float>::infinity();
#ifdef PROFILE_LOOKAHEAD
route_ctx.rr_node_route_inf[node].backward_path_delay = std::numeric_limits<float>::infinity();
route_ctx.rr_node_route_inf[node].backward_path_congestion = std::numeric_limits<float>::infinity();
#endif
route_ctx.rr_node_route_inf[node].prev_edge = RREdgeId::INVALID();
}
}
@@ -426,6 +430,10 @@ void reset_rr_node_route_structs() {
node_inf.acc_cost = 1.0;
node_inf.path_cost = std::numeric_limits<float>::infinity();
node_inf.backward_path_cost = std::numeric_limits<float>::infinity();
#ifdef PROFILE_LOOKAHEAD
node_inf.backward_path_delay = std::numeric_limits<float>::infinity();
node_inf.backward_path_congestion = std::numeric_limits<float>::infinity();
#endif
node_inf.set_occ(0);
}
}
@@ -838,9 +846,15 @@ void reserve_locally_used_opins(HeapInterface* heap, float pres_fac, float acc_f

//Add the OPIN to the heap according to it's congestion cost
cost = get_rr_cong_cost(to_node, pres_fac);
add_node_to_heap(heap, route_ctx.rr_node_route_inf,
to_node, cost, RREdgeId::INVALID(),
0., 0.);
add_node_to_heap(heap,
route_ctx.rr_node_route_inf,
to_node,
cost,
/*prev_edge=*/RREdgeId::INVALID(),
/*backward_path_cost=*/0.,
/*backward_path_delay=*/0.,
/*backward_path_congestion=*/0.,
/*R_upstream=*/0.);
}

for (ipin = 0; ipin < num_local_opin; ipin++) {
71 changes: 55 additions & 16 deletions vpr/src/route/route_common.h
Original file line number Diff line number Diff line change
@@ -145,14 +145,30 @@ float get_cost_from_lookahead(const RouterLookahead& router_lookahead,
const t_conn_cost_params cost_params,
bool is_flat);

/* Creates a new t_heap object to be placed on the heap, if the new cost *
* given is lower than the current path_cost to this channel segment. The *
* index of its predecessor is stored to make traceback easy. The index of *
* the edge used to get from its predecessor to it is also stored to make *
* timing analysis, etc. *
* *
* Returns t_heap suitable for adding to heap or nullptr if node is more *
* expensive than previously explored path. */
/**
* @brief Creates a new t_heap object to be placed on the heap, if the new cost
* given is lower than the current path_cost to this channel segment. The index
* of its predecessor is stored to make traceback easy. The index of the edge
* used to get from its predecessor to it is also stored to make timing analysis,
* etc.
*
* @tparam T
* @tparam RouteInf
* @param heap
* @param rr_node_route_inf
* @param inode
* @param total_cost
* @param prev_edge
* @param backward_path_cost
* @param backward_path_delay The known backward path delay used to calculate
* backward_path_cost. Only used for RouterLookahead, when enabled.
* @param backward_path_congestion The known backward path congestion used to
* calculate backward_path_cost. Only used for RouterLookahead, when enabled.
* @param R_upstream
*
* @return t_heap suitable for adding to heap or nullptr if node is more expensive
* than previously explored path.
*/
template<typename T, typename RouteInf>
t_heap* prepare_to_add_node_to_heap(
T* heap,
@@ -161,6 +177,8 @@ t_heap* prepare_to_add_node_to_heap(
float total_cost,
RREdgeId prev_edge,
float backward_path_cost,
float backward_path_delay,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the function-level comment above this to Doxygen and describe the variables only needed for the lookahead profiler.

float backward_path_congestion,
float R_upstream) {
if (total_cost >= rr_node_route_inf[inode].path_cost)
return nullptr;
@@ -171,6 +189,13 @@ t_heap* prepare_to_add_node_to_heap(
hptr->cost = total_cost;
hptr->set_prev_edge(prev_edge);
hptr->backward_path_cost = backward_path_cost;
#ifndef PROFILE_LOOKAHEAD
(void)backward_path_delay;
(void)backward_path_congestion;
#else
hptr->backward_path_delay = backward_path_delay;
hptr->backward_path_congestion = backward_path_congestion;
#endif
hptr->R_upstream = R_upstream;
return hptr;
}
@@ -184,11 +209,18 @@ void add_node_to_heap(
float total_cost,
RREdgeId prev_edge,
float backward_path_cost,
float backward_path_delay,
float backward_path_congestion,
float R_upstream) {
t_heap* hptr = prepare_to_add_node_to_heap(
heap,
rr_node_route_inf, inode, total_cost,
prev_edge, backward_path_cost, R_upstream);
t_heap* hptr = prepare_to_add_node_to_heap(heap,
rr_node_route_inf,
inode,
total_cost,
prev_edge,
backward_path_cost,
backward_path_delay,
backward_path_congestion,
R_upstream);
if (hptr) {
heap->add_to_heap(hptr);
}
@@ -205,11 +237,18 @@ void push_back_node(
float total_cost,
RREdgeId prev_edge,
float backward_path_cost,
float backward_path_delay,
float backward_path_congestion,
float R_upstream) {
t_heap* hptr = prepare_to_add_node_to_heap(
heap,
rr_node_route_inf, inode, total_cost, prev_edge,
backward_path_cost, R_upstream);
t_heap* hptr = prepare_to_add_node_to_heap(heap,
rr_node_route_inf,
inode,
total_cost,
prev_edge,
backward_path_cost,
backward_path_delay,
backward_path_congestion,
R_upstream);
if (hptr) {
heap->push_back(hptr);
}
32 changes: 26 additions & 6 deletions vpr/src/route/route_net.tpp
Original file line number Diff line number Diff line change
@@ -189,7 +189,8 @@ inline NetResultFlags route_net(ConnectionRouter& router,
tree,
spatial_route_tree_lookup,
router_stats,
is_flat);
is_flat,
itry);

if (flags.success == false)
return flags;
@@ -235,7 +236,8 @@ inline NetResultFlags route_net(ConnectionRouter& router,
routing_predictor,
choking_spots,
is_flat,
net_bb);
net_bb,
itry);

flags.retry_with_full_bb |= sink_flags.retry_with_full_bb;

@@ -295,7 +297,8 @@ inline NetResultFlags pre_route_to_clock_root(ConnectionRouter& router,
RouteTree& tree,
SpatialRouteTreeLookup& spatial_rt_lookup,
RouterStats& router_stats,
bool is_flat) {
bool is_flat,
int itry) {
const auto& device_ctx = g_vpr_ctx.device();
auto& route_ctx = g_vpr_ctx.mutable_routing();
auto& m_route_ctx = g_vpr_ctx.mutable_routing();
@@ -351,7 +354,15 @@ inline NetResultFlags pre_route_to_clock_root(ConnectionRouter& router,
* points. Therefore, we can set the net pin index of the sink node to *
* OPEN (meaning illegal) as it is not meaningful for this sink. */
vtr::optional<const RouteTreeNode&> new_branch, new_sink;
std::tie(new_branch, new_sink) = tree.update_from_heap(&cheapest, OPEN, ((high_fanout) ? &spatial_rt_lookup : nullptr), is_flat);
std::tie(new_branch, new_sink) = tree.update_from_heap(/*hptr=*/&cheapest,
/*target_net_pin_index=*/OPEN,
((high_fanout) ? &spatial_rt_lookup : nullptr),
is_flat,
router.get_router_lookahead(),
cost_params,
net_list,
conn_params.net_id_,
itry);

VTR_ASSERT_DEBUG(!high_fanout || validate_route_tree_spatial_lookup(tree.root(), spatial_rt_lookup));

@@ -414,7 +425,8 @@ inline NetResultFlags route_sink(ConnectionRouter& router,
const RoutingPredictor& routing_predictor,
const std::vector<std::unordered_map<RRNodeId, int>>& choking_spots,
bool is_flat,
const t_bb& net_bb) {
const t_bb& net_bb,
int itry) {
const auto& device_ctx = g_vpr_ctx.device();
auto& route_ctx = g_vpr_ctx.mutable_routing();

@@ -478,7 +490,15 @@ inline NetResultFlags route_sink(ConnectionRouter& router,
profiling::sink_criticality_end(cost_params.criticality);

vtr::optional<const RouteTreeNode&> new_branch, new_sink;
std::tie(new_branch, new_sink) = tree.update_from_heap(&cheapest, target_pin, ((high_fanout) ? &spatial_rt_lookup : nullptr), is_flat);
std::tie(new_branch, new_sink) = tree.update_from_heap(&cheapest,
target_pin,
((high_fanout) ? &spatial_rt_lookup : nullptr),
is_flat,
router.get_router_lookahead(),
cost_params,
net_list,
conn_params.net_id_,
itry);

VTR_ASSERT_DEBUG(!high_fanout || validate_route_tree_spatial_lookup(tree.root(), spatial_rt_lookup));

5 changes: 4 additions & 1 deletion vpr/src/route/route_path_manager.cpp
Original file line number Diff line number Diff line change
@@ -39,7 +39,10 @@ void PathManager::mark_node_visited(RRNodeId node) {
}
}

void PathManager::insert_backwards_path_into_traceback(t_heap_path* path_data, float cost, float backward_path_cost, RoutingContext& route_ctx) {
void PathManager::insert_backwards_path_into_traceback(t_heap_path* path_data,
float cost,
float backward_path_cost,
RoutingContext& route_ctx) {
if (!is_enabled_) return;

for (unsigned i = 1; i < path_data->edge.size() - 1; i++) {
5 changes: 4 additions & 1 deletion vpr/src/route/route_path_manager.h
Original file line number Diff line number Diff line change
@@ -74,7 +74,10 @@ class PathManager {
void set_enabled(bool enable);

// Insert the partial path data into the main route context traceback
void insert_backwards_path_into_traceback(t_heap_path* path_data, float cost, float backward_path_cost, RoutingContext& route_ctx);
void insert_backwards_path_into_traceback(t_heap_path* path_data,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment that some info is only passed in for lookahead profiling (if you want to allow lookahead profiling with RCV).

float cost,
float backward_path_cost,
RoutingContext& route_ctx);

// Dynamically create a t_heap_path structure to be used in the heap
// Will return unless RCV is enabled
36 changes: 33 additions & 3 deletions vpr/src/route/route_tree.cpp
Original file line number Diff line number Diff line change
@@ -486,13 +486,28 @@ void RouteTree::print(void) const {
* This routine returns a tuple: RouteTreeNode of the branch it adds to the route tree and
* RouteTreeNode of the SINK it adds to the routing. */
std::tuple<vtr::optional<const RouteTreeNode&>, vtr::optional<const RouteTreeNode&>>
RouteTree::update_from_heap(t_heap* hptr, int target_net_pin_index, SpatialRouteTreeLookup* spatial_rt_lookup, bool is_flat) {
RouteTree::update_from_heap(t_heap* hptr,
int target_net_pin_index,
SpatialRouteTreeLookup* spatial_rt_lookup,
bool is_flat,
const RouterLookahead& router_lookahead,
const t_conn_cost_params& cost_params,
const Netlist<>& net_list,
const ParentNetId& net_id,
const int itry) {
/* Lock the route tree for writing. At least on Linux this shouldn't have an impact on single-threaded code */
std::unique_lock<std::mutex> write_lock(_write_mutex);

//Create a new subtree from the target in hptr to existing routing
vtr::optional<RouteTreeNode&> start_of_new_subtree_rt_node, sink_rt_node;
std::tie(start_of_new_subtree_rt_node, sink_rt_node) = add_subtree_from_heap(hptr, target_net_pin_index, is_flat);
std::tie(start_of_new_subtree_rt_node, sink_rt_node) = add_subtree_from_heap(hptr,
target_net_pin_index,
is_flat,
router_lookahead,
cost_params,
itry,
net_list,
net_id);

if (!start_of_new_subtree_rt_node)
return {vtr::nullopt, *sink_rt_node};
@@ -515,7 +530,14 @@ RouteTree::update_from_heap(t_heap* hptr, int target_net_pin_index, SpatialRoute
* to the SINK indicated by hptr. Returns the first (most upstream) new rt_node,
* and the rt_node of the new SINK. Traverses up from SINK */
std::tuple<vtr::optional<RouteTreeNode&>, vtr::optional<RouteTreeNode&>>
RouteTree::add_subtree_from_heap(t_heap* hptr, int target_net_pin_index, bool is_flat) {
RouteTree::add_subtree_from_heap(t_heap* hptr,
int target_net_pin_index,
bool is_flat,
const RouterLookahead& router_lookahead,
const t_conn_cost_params& cost_params,
const int itry,
const Netlist<>& net_list,
const ParentNetId& net_id) {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();
@@ -549,6 +571,14 @@ RouteTree::add_subtree_from_heap(t_heap* hptr, int target_net_pin_index, bool is
}
new_branch_iswitches.push_back(new_iswitch);

g_vpr_ctx.mutable_routing().lookahead_profiler.record(itry,
target_net_pin_index,
cost_params,
router_lookahead,
net_id,
net_list,
new_branch_inodes);

/* Build the new tree branch starting from the existing node we found */
RouteTreeNode* last_node = _rr_node_to_rt_node[new_inode];
all_visited.insert(last_node->inode);
45 changes: 36 additions & 9 deletions vpr/src/route/route_tree.h
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@
#include <unordered_map>

#include "connection_based_routing_fwd.h"
#include "lookahead_profiler.h"
#include "route_tree_fwd.h"
#include "vtr_assert.h"
#include "spatial_route_tree_lookup.h"
@@ -349,15 +350,34 @@ class RouteTree {
free_list(_root);
}

/** Add the most recently finished wire segment to the routing tree, and
* update the Tdel, etc. numbers for the rest of the routing tree. hptr
* is the heap pointer of the SINK that was reached, and target_net_pin_index
* is the net pin index corresponding to the SINK that was reached. This routine
* returns a tuple: RouteTreeNode of the branch it adds to the route tree and
* RouteTreeNode of the SINK it adds to the routing.
* Locking operation: only one thread can update_from_heap() a RouteTree at a time. */
/**
* @brief Add the most recently finished wire segment to the routing tree, and update the
* Tdel, etc. numbers for the rest of the routing tree.
*
* @param hptr The heap pointer of the SINK that was reached.
* @param target_net_pin_index The net pin index corresponding to the SINK that was reached.
* @param spatial_rt_lookup
* @param is_flat
* @param router_lookahead Only needed for the LookaheadProfiler.
* @param cost_params Only needed for the LookaheadProfiler.
* @param net_list Only needed for the LookaheadProfiler.
* @param net_id Only needed for the LookaheadProfiler.
* @param itry Only needed for the LookaheadProfiler. If this function is called outside of
* the router loop, this argument does not need to be specified.
*
* @return A tuple: RouteTreeNode of the branch it adds to the route tree and RouteTreeNode
* of the SINK it adds to the routing.
*/
std::tuple<vtr::optional<const RouteTreeNode&>, vtr::optional<const RouteTreeNode&>>
update_from_heap(t_heap* hptr, int target_net_pin_index, SpatialRouteTreeLookup* spatial_rt_lookup, bool is_flat);
update_from_heap(t_heap* hptr,
int target_net_pin_index,
SpatialRouteTreeLookup* spatial_rt_lookup,
bool is_flat,
const RouterLookahead& router_lookahead,
const t_conn_cost_params& cost_params,
const Netlist<>& net_list,
const ParentNetId& net_id,
int itry = -1);

/** Reload timing values (R_upstream, C_downstream, Tdel).
* Can take a RouteTreeNode& to do an incremental update.
@@ -491,7 +511,14 @@ class RouteTree {

private:
std::tuple<vtr::optional<RouteTreeNode&>, vtr::optional<RouteTreeNode&>>
add_subtree_from_heap(t_heap* hptr, int target_net_pin_index, bool is_flat);
add_subtree_from_heap(t_heap* hptr,
int target_net_pin_index,
bool is_flat,
const RouterLookahead& router_lookahead,
const t_conn_cost_params& cost_params,
const int itry,
const Netlist<>& net_list,
const ParentNetId& net_id);

void add_non_configurable_nodes(RouteTreeNode* rt_node,
bool reached_by_non_configurable_edge,
26 changes: 22 additions & 4 deletions vpr/src/route/router_delay_profiling.cpp
Original file line number Diff line number Diff line change
@@ -121,7 +121,14 @@ bool RouterDelayProfiler::calculate_delay(RRNodeId source_node,
VTR_ASSERT(cheapest.index == sink_node);

vtr::optional<const RouteTreeNode&> rt_node_of_sink;
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(&cheapest, OPEN, nullptr, is_flat_);
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(/*hptr=*/&cheapest,
/*target_net_pin_index=*/OPEN,
/*spatial_rt_lookup=*/nullptr,
is_flat_,
router_.get_router_lookahead(),
cost_params,
net_list_,
conn_params.net_id_);

//find delay
*net_delay = rt_node_of_sink->Tdel;
@@ -143,10 +150,14 @@ float RouterDelayProfiler::get_min_delay(int physical_tile_type_idx, int from_la
return min_delays_[physical_tile_type_idx][from_layer][to_layer][dx][dy];
}

//Returns the shortest path delay from src_node to all RR nodes in the RR graph, or NaN if no path exists
const Netlist<>& RouterDelayProfiler::get_net_list() const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a blank line before the routine.

return net_list_;
}

vtr::vector<RRNodeId, float> calculate_all_path_delays_from_rr_node(RRNodeId src_rr_node,
const t_router_opts& router_opts,
bool is_flat) {
bool is_flat,
const Netlist<>& net_list) {
auto& device_ctx = g_vpr_ctx.device();
auto& route_ctx = g_vpr_ctx.mutable_routing();

@@ -207,7 +218,14 @@ vtr::vector<RRNodeId, float> calculate_all_path_delays_from_rr_node(RRNodeId src
//Build the routing tree to get the delay
tree = RouteTree(RRNodeId(src_rr_node));
vtr::optional<const RouteTreeNode&> rt_node_of_sink;
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(&shortest_paths[sink_rr_node], OPEN, nullptr, router_opts.flat_routing);
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(/*hptr=*/&shortest_paths[sink_rr_node],
/*target_net_pin_index=*/OPEN,
/*spatial_rt_lookup=*/nullptr,
router_opts.flat_routing,
router.get_router_lookahead(),
cost_params,
net_list,
conn_params.net_id_);

VTR_ASSERT(rt_node_of_sink->inode == RRNodeId(sink_rr_node));

11 changes: 10 additions & 1 deletion vpr/src/route/router_delay_profiling.h
Original file line number Diff line number Diff line change
@@ -43,6 +43,11 @@ class RouterDelayProfiler {
*/
float get_min_delay(int physical_tile_type_idx, int from_layer, int to_layer, int dx, int dy) const;

/**
* @brief Get a const reference to the netlist.
*/
const Netlist<>& get_net_list() const;

private:
const Netlist<>& net_list_;
RouterStats router_stats_;
@@ -51,9 +56,13 @@ class RouterDelayProfiler {
bool is_flat_;
};

/**
* @brief Returns the shortest path delay from src_node to all RR nodes in the RR graph, or NaN if no path exists.
*/
vtr::vector<RRNodeId, float> calculate_all_path_delays_from_rr_node(RRNodeId src_rr_node,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you know enough about this routine to write a doxygen comment it would be good to write one.

const t_router_opts& router_opts,
bool is_flat);
bool is_flat,
const Netlist<>& net_list);

void alloc_routing_structs(const t_chan_width& chan_width,
const t_router_opts& router_opts,
20 changes: 17 additions & 3 deletions vpr/src/route/router_lookahead.cpp
Original file line number Diff line number Diff line change
@@ -61,13 +61,27 @@ std::unique_ptr<RouterLookahead> make_router_lookahead(const t_det_routing_arch&
return router_lookahead;
}

void RouterLookahead::scale_delay_and_cong_by_criticality(float& delay, float& cong, const float criticality) const {
delay *= criticality;
cong *= 1.f - criticality;
}

std::pair<float, float> RouterLookahead::get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const {
auto [expected_delay, expected_congestion] = get_expected_delay_and_cong_ignore_criticality(node, target_node, params, R_upstream);
scale_delay_and_cong_by_criticality(expected_delay, expected_delay, params.criticality);
return {expected_delay, expected_congestion};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this member functon is always called after get_expected_delay_and_cong()?
In this case, I think it is better to replace this member function with another one that computes the scaled congestion and delay

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always except for the lookahead profiler. I moved the code in get_expected_delay_and_cong() into a new function get_expected_delay_and_cong_ignore_criticality(), and now get_expected_delay_and_cong() just calls that new function + the scaling function. So, all the previous calls to get_expected_delay_and_cong() remain unmodified and the profiler can call get_expected_delay_and_cong_ignore_criticality().


float ClassicLookahead::get_expected_cost(RRNodeId current_node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const {
auto [delay_cost, cong_cost] = get_expected_delay_and_cong(current_node, target_node, params, R_upstream);

return delay_cost + cong_cost;
}

std::pair<float, float> ClassicLookahead::get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const {
std::pair<float, float> ClassicLookahead::get_expected_delay_and_cong_ignore_criticality(RRNodeId node,
RRNodeId target_node,
const t_conn_cost_params& /*params*/,
float R_upstream) const {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

@@ -96,7 +110,7 @@ std::pair<float, float> ClassicLookahead::get_expected_delay_and_cong(RRNodeId n
+ R_upstream * (num_segs_same_dir * same_data.C_load + num_segs_ortho_dir * ortho_data.C_load)
+ ipin_data.T_linear;

return std::make_pair(params.criticality * Tdel, (1 - params.criticality) * cong_cost);
return std::make_pair(Tdel, cong_cost);
} else if (rr_type == IPIN) { /* Change if you're allowing route-throughs */
return std::make_pair(0., device_ctx.rr_indexed_data[RRIndexedDataId(SINK_COST_INDEX)].base_cost);

@@ -109,7 +123,7 @@ float NoOpLookahead::get_expected_cost(RRNodeId /*current_node*/, RRNodeId /*tar
return 0.;
}

std::pair<float, float> NoOpLookahead::get_expected_delay_and_cong(RRNodeId /*node*/, RRNodeId /*target_node*/, const t_conn_cost_params& /*params*/, float /*R_upstream*/) const {
std::pair<float, float> NoOpLookahead::get_expected_delay_and_cong_ignore_criticality(RRNodeId /*node*/, RRNodeId /*target_node*/, const t_conn_cost_params& /*params*/, float /*R_upstream*/) const {
return std::make_pair(0., 0.);
}

62 changes: 58 additions & 4 deletions vpr/src/route/router_lookahead.h
Original file line number Diff line number Diff line change
@@ -15,15 +15,66 @@ class RouterLookahead {
public:
/**
* @brief Get expected cost from node to target_node.
* @attention Either compute or read methods must be invoked before invoking get_expected_cost.
*
* @attention Either compute or read methods must be invoked (to set up the lookahead data structures) before invoking get_expected_cost.
*
* @param node The source node from which the cost to the target node is obtained.
* @param target_node The target node to which the cost is obtained.
* @param params Contain the router parameter such as connection criticality, etc. Used to calculate the cost based on the delay and congestion costs.
* @param R_upstream Upstream resistance to get to the "node".
*
* @return
*/
virtual float get_expected_cost(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const = 0;
virtual std::pair<float, float> get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const = 0;

/**
* @brief Get expected (delay, congestion) from node to target_node.
*
* @attention Either compute or read methods must be invoked (to set up the lookahead data structures) before invoking
* get_expected_delay_and_cong_ignore_criticality.
*
* @param node The source node from which the cost to the target node is obtained.
* @param target_node The target node to which the cost is obtained.
* @param params Contains the router parameter such as connection criticality, etc.
* @param R_upstream Upstream resistance to get to the "node".
*
* @return (delay, congestion)
*
* @warning (delay, congestion) are NOT multiplied by (params.criticality, 1. - params.criticality), respectively.
* scale_delay_and_cong_by_criticality should be called after this function before adding these to calculate the
* expected total cost.
*/
virtual std::pair<float, float> get_expected_delay_and_cong_ignore_criticality(RRNodeId node,
RRNodeId target_node,
const t_conn_cost_params& params,
float R_upstream) const
= 0;

/**
* @brief Multiply delay by params.criticality and cong by (1. - params.criticality). Used in conjunction with
* get_expected_delay_and_cong_ignore_criticality to calculate the total expected cost.
*
* @param delay
* @param cong
* @param criticality
*/
void scale_delay_and_cong_by_criticality(float& delay, float& cong, float criticality) const;

/**
* @brief Get expected (delay, congestion), scaled by congestion, from node to target_node.
*
* @note
* This function simply calls get_expected_delay_and_cong_ignore_criticality() followed by
* scale_delay_and_cong_by_criticality().
*
* @param node The source node from which the cost to the target node is obtained.
* @param target_node The target node to which the cost is obtained.
* @param params Contains the router parameter such as connection criticality, etc.
* @param R_upstream Upstream resistance to get to the "node".
*
* @return (delay, congestion)
*/
std::pair<float, float> get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const;

/**
* @brief Compute router lookahead (if needed)
@@ -123,7 +174,10 @@ const RouterLookahead* get_cached_router_lookahead(const t_det_routing_arch& det
class ClassicLookahead : public RouterLookahead {
public:
float get_expected_cost(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong_ignore_criticality(RRNodeId node,
RRNodeId target_node,
const t_conn_cost_params& params,
float R_upstream) const override;

void compute(const std::vector<t_segment_inf>& /*segment_inf*/) override {
}
@@ -159,7 +213,7 @@ class ClassicLookahead : public RouterLookahead {
class NoOpLookahead : public RouterLookahead {
protected:
float get_expected_cost(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong_ignore_criticality(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;

void compute(const std::vector<t_segment_inf>& /*segment_inf*/) override {
}
14 changes: 4 additions & 10 deletions vpr/src/route/router_lookahead_compressed_map.cpp
Original file line number Diff line number Diff line change
@@ -421,10 +421,10 @@ float CompressedMapLookahead::get_expected_cost(RRNodeId current_node, RRNodeId
}
}

std::pair<float, float> CompressedMapLookahead::get_expected_delay_and_cong(RRNodeId from_node,
RRNodeId to_node,
const t_conn_cost_params& params,
float /* R_upstream */) const {
std::pair<float, float> CompressedMapLookahead::get_expected_delay_and_cong_ignore_criticality(RRNodeId from_node,
RRNodeId to_node,
const t_conn_cost_params& /*params*/,
float /*R_upstream*/) const {
auto& device_ctx = g_vpr_ctx.device();
auto& rr_graph = device_ctx.rr_graph;

@@ -458,9 +458,6 @@ std::pair<float, float> CompressedMapLookahead::get_expected_delay_and_cong(RRNo
to_layer_num,
get_wire_cost_entry_compressed_lookahead);

expected_delay_cost *= params.criticality;
expected_cong_cost *= (1 - params.criticality);

VTR_ASSERT_SAFE_MSG(std::isfinite(expected_delay_cost),
vtr::string_fmt("Lookahead failed to estimate cost from %s: %s",
rr_node_arch_name(from_node, is_flat_).c_str(),
@@ -471,7 +468,6 @@ std::pair<float, float> CompressedMapLookahead::get_expected_delay_and_cong(RRNo
is_flat_)
.c_str())
.c_str());

} else if (from_type == CHANX || from_type == CHANY) {
//When estimating costs from a wire, we directly look-up the result in the wire lookahead (f_wire_cost_map)

@@ -500,8 +496,6 @@ std::pair<float, float> CompressedMapLookahead::get_expected_delay_and_cong(RRNo
is_flat_)
.c_str())
.c_str());
expected_delay_cost = cost_entry.delay * params.criticality;
expected_cong_cost = cost_entry.congestion * (1 - params.criticality);
} else if (from_type == IPIN) { /* Change if you're allowing route-throughs */
return std::make_pair(0., device_ctx.rr_indexed_data[RRIndexedDataId(SINK_COST_INDEX)].base_cost);
} else { /* Change this if you want to investigate route-throughs */
8 changes: 4 additions & 4 deletions vpr/src/route/router_lookahead_compressed_map.h
Original file line number Diff line number Diff line change
@@ -27,10 +27,10 @@ class CompressedMapLookahead : public RouterLookahead {
protected:
float get_expected_cost(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;

std::pair<float, float> get_expected_delay_and_cong(RRNodeId from_node,
RRNodeId to_node,
const t_conn_cost_params& params,
float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong_ignore_criticality(RRNodeId from_node,
RRNodeId to_node,
const t_conn_cost_params& params,
float R_upstream) const override;

void compute(const std::vector<t_segment_inf>& segment_inf) override;

9 changes: 6 additions & 3 deletions vpr/src/route/router_lookahead_extended_map.cpp
Original file line number Diff line number Diff line change
@@ -181,7 +181,10 @@ float ExtendedMapLookahead::get_chan_ipin_delays(RRNodeId to_node) const {
//
// The from_node can be of one of the following types: CHANX, CHANY, SOURCE, OPIN
// The to_node is always a SINK
std::pair<float, float> ExtendedMapLookahead::get_expected_delay_and_cong(RRNodeId from_node, RRNodeId to_node, const t_conn_cost_params& params, float /*R_upstream*/) const {
std::pair<float, float> ExtendedMapLookahead::get_expected_delay_and_cong_ignore_criticality(RRNodeId from_node,
RRNodeId to_node,
const t_conn_cost_params& params,
float /*R_upstream*/) const {
if (from_node == to_node) {
return std::make_pair(0., 0.);
}
@@ -238,7 +241,7 @@ std::pair<float, float> ExtendedMapLookahead::get_expected_delay_and_cong(RRNode
expected_delay += site_pin_delay;

float expected_delay_cost = params.criticality * expected_delay;
float expected_cong_cost = (1.0 - params.criticality) * expected_congestion;
float expected_cong_cost = (1.f - params.criticality) * expected_congestion;

float expected_cost = expected_delay_cost + expected_cong_cost;

@@ -263,7 +266,7 @@ std::pair<float, float> ExtendedMapLookahead::get_expected_delay_and_cong(RRNode
VTR_ASSERT(0);
}

return std::make_pair(expected_delay_cost, expected_cong_cost);
return std::make_pair(expected_delay, expected_congestion);
}

// Adds a best cost routing path from start_node_ind to node_ind to routing costs
5 changes: 4 additions & 1 deletion vpr/src/route/router_lookahead_extended_map.h
Original file line number Diff line number Diff line change
@@ -69,7 +69,10 @@ class ExtendedMapLookahead : public RouterLookahead {
/**
* @brief Returns a pair of expected delay and congestion
*/
std::pair<float, float> get_expected_delay_and_cong(RRNodeId inode, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong_ignore_criticality(RRNodeId inode,
RRNodeId target_node,
const t_conn_cost_params& params,
float R_upstream) const override;

/**
* @brief Computes the extended lookahead map
122 changes: 61 additions & 61 deletions vpr/src/route/router_lookahead_map.cpp

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions vpr/src/route/router_lookahead_map.h
Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@ class MapLookahead : public RouterLookahead {
explicit MapLookahead(const t_det_routing_arch& det_routing_arch, bool is_flat);

private:
float get_expected_cost_flat_router(RRNodeId current_node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const;
std::pair<float, float> get_expected_delay_and_cong_flat_router(RRNodeId current_node, RRNodeId target_node) const;
std::pair<float, float> get_expected_delay_and_cong_default(RRNodeId current_node, RRNodeId target_node) const;
//Look-up table from SOURCE/OPIN to CHANX/CHANY of various types
util::t_src_opin_delays src_opin_delays;
// Lookup table from a tile pins to the primitive classes inside that tile
@@ -30,7 +31,10 @@ class MapLookahead : public RouterLookahead {

protected:
float get_expected_cost(RRNodeId current_node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong(RRNodeId from_node, RRNodeId to_node, const t_conn_cost_params& params, float R_upstream) const override;
std::pair<float, float> get_expected_delay_and_cong_ignore_criticality(RRNodeId from_node,
RRNodeId to_node,
const t_conn_cost_params& params,
float R_upstream) const override;

void compute(const std::vector<t_segment_inf>& segment_inf) override;
void compute_intra_tile() override;
42 changes: 16 additions & 26 deletions vpr/src/route/router_lookahead_map_utils.cpp
Original file line number Diff line number Diff line change
@@ -58,16 +58,6 @@ static void expand_dijkstra_neighbours(util::PQ_Entry parent_entry,
vtr::vector<RRNodeId, bool>& node_expanded,
std::priority_queue<util::PQ_Entry>& pq);


/**
* @brief Computes the adjusted position of an RR graph node.
* This function does not modify the position of the given node.
* It only returns the computed adjusted position.
* @param rr The ID of the node whose adjusted position is desired.
* @return The adjusted position (x, y).
*/
static std::pair<int, int> get_adjusted_rr_position(RRNodeId rr);

/**
* @brief Computes the adjusted location of a pin to match the position of
* the channel it can reach based on which side of the block it is at.
@@ -679,6 +669,22 @@ std::pair<int, int> get_xy_deltas(RRNodeId from_node, RRNodeId to_node) {
return {delta_x, delta_y};
}

std::pair<int, int> get_adjusted_rr_position(const RRNodeId rr) {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

e_rr_type rr_type = rr_graph.node_type(rr);

if (is_chan(rr_type)) {
return get_adjusted_rr_wire_position(rr);
} else if (is_pin(rr_type)) {
return get_adjusted_rr_pin_position(rr);
} else {
VTR_ASSERT_SAFE(is_src_sink(rr_type));
return get_adjusted_rr_src_sink_position(rr);
}
}

t_routing_cost_map get_routing_cost_map(int longest_seg_length,
int from_layer_num,
const e_rr_type& chan_type,
@@ -1410,22 +1416,6 @@ static void expand_dijkstra_neighbours(util::PQ_Entry parent_entry,
}
}

static std::pair<int, int> get_adjusted_rr_position(const RRNodeId rr) {
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

e_rr_type rr_type = rr_graph.node_type(rr);

if (is_chan(rr_type)) {
return get_adjusted_rr_wire_position(rr);
} else if (is_pin(rr_type)) {
return get_adjusted_rr_pin_position(rr);
} else {
VTR_ASSERT_SAFE(is_src_sink(rr_type));
return get_adjusted_rr_src_sink_position(rr);
}
}

static std::pair<int, int> get_adjusted_rr_pin_position(const RRNodeId rr) {
/*
* VPR uses a co-ordinate system where wires above and to the right of a block
9 changes: 9 additions & 0 deletions vpr/src/route/router_lookahead_map_utils.h
Original file line number Diff line number Diff line change
@@ -337,6 +337,15 @@ RRNodeId get_start_node(int layer, int start_x, int start_y, int target_x, int t
*/
std::pair<int, int> get_xy_deltas(RRNodeId from_node, RRNodeId to_node);

/**
* @brief Computes the adjusted position of an RR graph node.
* This function does not modify the position of the given node.
* It only returns the computed adjusted position.
* @param rr The ID of the node whose adjusted position is desired.
* @return The adjusted position (x, y).
*/
std::pair<int, int> get_adjusted_rr_position(RRNodeId rr);

t_routing_cost_map get_routing_cost_map(int longest_seg_length,
int from_layer_num,
const e_rr_type& chan_type,
9 changes: 8 additions & 1 deletion vpr/test/test_connection_router.cpp
Original file line number Diff line number Diff line change
@@ -87,7 +87,14 @@ static float do_one_route(RRNodeId source_node,

// Get the delay
vtr::optional<const RouteTreeNode&> rt_node_of_sink;
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(&cheapest, OPEN, nullptr, router_opts.flat_routing);
std::tie(std::ignore, rt_node_of_sink) = tree.update_from_heap(/*hptr=*/&cheapest,
/*target_net_pin_index=*/OPEN,
/*spatial_rt_lookup=*/nullptr,
router_opts.flat_routing,
router.get_router_lookahead(),
cost_params,
net_list,
conn_params.net_id_);
delay = rt_node_of_sink.value().Tdel;
}

1,400 changes: 1,400 additions & 0 deletions vtr_flow/scripts/profiling_utils/parse_lookahead_data.py

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -47,5 +47,5 @@ pass_requirements_file=pass_requirements.txt
#We increase the critical path router iterations beyond the default 50, to avoid
#spurrious routing failures at relaxed channel width (since we know they should
#be routable via the minimum channel width search)
script_params=-starting_stage vpr -track_memory_usage -crit_path_router_iterations 60 --seed 250
script_params=-starting_stage vpr -track_memory_usage -crit_path_router_iterations 60

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -24,6 +24,6 @@ qor_parse_file=qor_standard.txt
pass_requirements_file=pass_requirements_fixed_chan_width.txt

# Script parameters
script_params_common = -starting_stage vpr --route_chan_width 70
script_params_common = -starting_stage vpr --route_chan_width 70 --seed 3
script_params_list_add = --router_update_lower_bound_delays off
script_params_list_add = --router_update_lower_bound_delays on
Original file line number Diff line number Diff line change
@@ -26,4 +26,4 @@ qor_parse_file=qor_standard.txt
pass_requirements_file=pass_requirements.txt

# Script parameters
script_params_common = -start odin --route_type global
script_params_common = -start odin --route_type global --seed 3
Original file line number Diff line number Diff line change
@@ -24,6 +24,6 @@ qor_parse_file=qor_standard.txt
pass_requirements_file=pass_requirements_fixed_chan_width.txt

# Script parameters
script_params_common = -starting_stage vpr --route_chan_width 70
script_params_common = -starting_stage vpr --route_chan_width 70 --seed 3
script_params_list_add = --router_update_lower_bound_delays off
script_params_list_add = --router_update_lower_bound_delays on