From e826f57b27df591f83a2845a638636875713f938 Mon Sep 17 00:00:00 2001 From: kmurray Date: Wed, 20 Nov 2019 15:16:05 -0500 Subject: [PATCH 01/58] infra: Update Travis Status Icon URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77b5e6ea4a9..3a3836a4752 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Verilog to Routing (VTR) -[![Build Status](https://travis-ci.org/verilog-to-routing/vtr-verilog-to-routing.svg?branch=master)](https://travis-ci.org/verilog-to-routing/vtr-verilog-to-routing) [![Documentation Status](https://readthedocs.org/projects/vtr/badge/?version=latest)](http://docs.verilogtorouting.org/en/latest/?badge=latest) +[![Build Status](https://travis-ci.com/verilog-to-routing/vtr-verilog-to-routing.svg?branch=master)](https://travis-ci.org/verilog-to-routing/vtr-verilog-to-routing) [![Documentation Status](https://readthedocs.org/projects/vtr/badge/?version=latest)](http://docs.verilogtorouting.org/en/latest/?badge=latest) ## Introduction The Verilog-to-Routing (VTR) project is a world-wide collaborative effort to provide a open-source framework for conducting FPGA architecture and CAD research and development. From 62ede3ac1a9d0bec4d8de893da41295754a74b31 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 15 Nov 2019 12:14:45 -0700 Subject: [PATCH 02/58] add create rr_graph_obj function which loads rr_nodes to the object --- libs/libvtrutil/src/vtr_geometry.h | 1 + libs/libvtrutil/src/vtr_geometry.tpp | 10 ++ vpr/src/base/vpr_context.h | 4 + vpr/src/device/check_rr_graph_obj.cpp | 19 ++- vpr/src/device/create_rr_graph.cpp | 149 +++++++++++++++++++++++ vpr/src/device/create_rr_graph.h | 17 +++ vpr/src/device/rr_graph_obj.cpp | 14 +-- vpr/src/route/rr_graph.cpp | 4 + vpr/src/util/rr_graph_obj_util.cpp | 30 +++++ vpr/src/util/rr_graph_obj_util.h | 14 +++ vpr/src/util/rr_graph_obj_utils.h | 165 ++++++++++++++++++++++++++ 11 files changed, 407 insertions(+), 20 deletions(-) create mode 100644 vpr/src/device/create_rr_graph.cpp create mode 100644 vpr/src/device/create_rr_graph.h create mode 100644 vpr/src/util/rr_graph_obj_util.cpp create mode 100644 vpr/src/util/rr_graph_obj_util.h create mode 100644 vpr/src/util/rr_graph_obj_utils.h diff --git a/libs/libvtrutil/src/vtr_geometry.h b/libs/libvtrutil/src/vtr_geometry.h index 65c53ecea65..cc8be19c139 100644 --- a/libs/libvtrutil/src/vtr_geometry.h +++ b/libs/libvtrutil/src/vtr_geometry.h @@ -48,6 +48,7 @@ template class Point { public: //Constructors Point(T x_val, T y_val) noexcept; + Point(); public: //Accessors //Coordinates diff --git a/libs/libvtrutil/src/vtr_geometry.tpp b/libs/libvtrutil/src/vtr_geometry.tpp index a1a852850c1..1517bcfc699 100644 --- a/libs/libvtrutil/src/vtr_geometry.tpp +++ b/libs/libvtrutil/src/vtr_geometry.tpp @@ -10,6 +10,11 @@ Point::Point(T x_val, T y_val) noexcept //pass } +template +Point::Point() { + //pass +} + template T Point::x() const { return x_; @@ -74,6 +79,11 @@ Rect::Rect(Point bottom_left_val, Point top_right_val) //pass } +template +Rect::Rect() { + //pass +} + template T Rect::xmin() const { return bottom_left_.x(); diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index 40a81bb41b5..00811f29496 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -21,6 +21,7 @@ #include "router_lookahead.h" #include "place_macro.h" #include "compressed_grid.h" +#include "rr_graph_obj.h" //A Context is collection of state relating to a particular part of VPR // @@ -136,6 +137,9 @@ struct DeviceContext : public Context { /* chan_width is for x|y-directed channels; i.e. between rows */ t_chan_width chan_width; + /* Object to define routing resources */ + RRGraph rr_graph; + /* Structures to define the routing architecture of the FPGA. */ std::vector rr_nodes; /* autogenerated in build_rr_graph */ diff --git a/vpr/src/device/check_rr_graph_obj.cpp b/vpr/src/device/check_rr_graph_obj.cpp index 253092fb730..69c772fcbf7 100644 --- a/vpr/src/device/check_rr_graph_obj.cpp +++ b/vpr/src/device/check_rr_graph_obj.cpp @@ -107,7 +107,7 @@ static bool check_rr_graph_source_nodes(const RRGraph& rr_graph) { } } - return invalid_sources; + return !invalid_sources; } /*********************************************************************** @@ -136,7 +136,7 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { } } - return invalid_sinks; + return !invalid_sinks; } /*********************************************************************** @@ -153,48 +153,43 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { * will work properly. **********************************************************************/ bool check_rr_graph(const RRGraph& rr_graph) { - bool check_flag = true; size_t num_err = 0; if (false == check_rr_graph_duplicated_edges(rr_graph)) { VTR_LOG_WARN("Fail in checking duplicated edges !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_dangling_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking dangling nodes !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp new file mode 100644 index 00000000000..e57c536ce2c --- /dev/null +++ b/vpr/src/device/create_rr_graph.cpp @@ -0,0 +1,149 @@ +/* Standard header files required go first */ +#include + +/* EXTERNAL library header files go second*/ +#include "vtr_assert.h" +#include "vtr_time.h" + +/* VPR header files go then */ +#include "vpr_types.h" +#include "rr_graph_obj.h" +#include "check_rr_graph_obj.h" +#include "create_rr_graph.h" + +/* Finally we include global variables */ +#include "globals.h" + +/******************************************************************** + * TODO: remove when this conversion (from traditional to new data structure) + * is no longer needed + * This function will convert an existing rr_graph in device_ctx to the RRGraph + *object + * This function is used to test our RRGraph if it is acceptable in downstream + *routers + ********************************************************************/ +void convert_rr_graph(std::vector& vpr_segments) { + vtr::ScopedStartFinishTimer timer("Build routing resource graph object"); + + /* IMPORTANT: to build clock tree, + * vpr added segments to the original arch segments + * This is why to use vpr_segments as an inputs!!! + */ + auto& device_ctx = g_vpr_ctx.mutable_device(); + + /* make sure we have a clean empty rr_graph */ + device_ctx.rr_graph.clear(); + + /* The number of switches are in general small, + * reserve switches may not bring significant memory efficiency + * So, we just use create_switch to push_back each time + */ + device_ctx.rr_graph.reserve_switches(device_ctx.rr_switch_inf.size()); + // Create the switches + for (size_t iswitch = 0; iswitch < device_ctx.rr_switch_inf.size(); ++iswitch) { + device_ctx.rr_graph.create_switch(device_ctx.rr_switch_inf[iswitch]); + } + + /* The number of segments are in general small, reserve segments may not bring + * significant memory efficiency */ + device_ctx.rr_graph.reserve_segments(vpr_segments.size()); + // Create the segments + for (size_t iseg = 0; iseg < vpr_segments.size(); ++iseg) { + device_ctx.rr_graph.create_segment(vpr_segments[iseg]); + } + + /* Reserve list of nodes to be memory efficient */ + device_ctx.rr_graph.reserve_nodes(device_ctx.rr_nodes.size()); + + // Create the nodes + std::map old_to_new_rr_node; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + auto& node = device_ctx.rr_nodes[inode]; + RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); + + device_ctx.rr_graph.set_node_xlow(rr_node, node.xlow()); + device_ctx.rr_graph.set_node_ylow(rr_node, node.ylow()); + device_ctx.rr_graph.set_node_xhigh(rr_node, node.xhigh()); + device_ctx.rr_graph.set_node_yhigh(rr_node, node.yhigh()); + + device_ctx.rr_graph.set_node_capacity(rr_node, node.capacity()); + + device_ctx.rr_graph.set_node_ptc_num(rr_node, node.ptc_num()); + + device_ctx.rr_graph.set_node_cost_index(rr_node, node.cost_index()); + + if (CHANX == node.type() || CHANY == node.type()) { + device_ctx.rr_graph.set_node_direction(rr_node, node.direction()); + } + if (IPIN == node.type() || OPIN == node.type()) { + device_ctx.rr_graph.set_node_side(rr_node, node.side()); + } + device_ctx.rr_graph.set_node_R(rr_node, node.R()); + device_ctx.rr_graph.set_node_C(rr_node, node.C()); + + /* Set up segment id */ + short irc_data = node.cost_index(); + short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; + device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); + + VTR_ASSERT(!old_to_new_rr_node.count(inode)); + old_to_new_rr_node[inode] = rr_node; + } + + /* Reserve list of edges to be memory efficient */ + { + int num_edges_to_reserve = 0; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + num_edges_to_reserve += node.num_edges(); + } + device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); + } + + // Create the edges + std::map, RREdgeId> old_to_new_rr_edge; // Key: + // {inode,iedge} + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + for (int iedge = 0; iedge < node.num_edges(); ++iedge) { + int isink_node = node.edge_sink_node(iedge); + int iswitch = node.edge_switch(iedge); + + VTR_ASSERT(old_to_new_rr_node.count(inode)); + VTR_ASSERT(old_to_new_rr_node.count(isink_node)); + + RREdgeId rr_edge = device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], + old_to_new_rr_node[isink_node], + RRSwitchId(iswitch)); + + auto key = std::make_pair(inode, iedge); + VTR_ASSERT(!old_to_new_rr_edge.count(key)); + old_to_new_rr_edge[key] = rr_edge; + } + } + + /* Partition edges to be two class: configurable (1st part) and + * non-configurable (2nd part) + * See how the router will use the edges and determine the strategy + * if we want to partition the edges first or depends on the routing needs + */ + device_ctx.rr_graph.partition_edges(); + + /* Essential check for rr_graph, build look-up and */ + if (false == device_ctx.rr_graph.validate()) { + /* Error out if built-in validator of rr_graph fails */ + vpr_throw(VPR_ERROR_ROUTE, + __FILE__, + __LINE__, + "Fundamental errors occurred when validating rr_graph object!\n"); + } + + /* Error out if advanced checker of rr_graph fails */ + if (false == check_rr_graph(device_ctx.rr_graph)) { + vpr_throw(VPR_ERROR_ROUTE, + __FILE__, + __LINE__, + "Advanced checking rr_graph object fails! Routing may still work " + "but not smooth\n"); + } +} diff --git a/vpr/src/device/create_rr_graph.h b/vpr/src/device/create_rr_graph.h new file mode 100644 index 00000000000..5cc57ec924a --- /dev/null +++ b/vpr/src/device/create_rr_graph.h @@ -0,0 +1,17 @@ +#ifndef CREATE_RR_GRAPH_H +#define CREATE_RR_GRAPH_H + +/* + * Notes in include header files in a head file + * Only include the neccessary header files + * that is required by the data types in the function/class declarations! + */ +#include "rr_graph_obj.h" + +/* IMPORTANT: to build clock tree, + * vpr added segments to the original arch segments + * This is why to use vpr_segments as an inputs!!! + */ +void convert_rr_graph(std::vector& vpr_segments); + +#endif diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 0cd9c49e83f..53066e89aff 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -714,7 +714,6 @@ bool RRGraph::validate_edge_sink_nodes() const { * Warnings are thrown if optional checking fails */ bool RRGraph::validate() const { - bool check_flag = true; size_t num_err = 0; initialize_fast_node_lookup(); @@ -724,34 +723,32 @@ bool RRGraph::validate() const { */ if (false == validate_sizes()) { VTR_LOG_WARN("Fail in validating node- and edge-related vector sizes!\n"); - check_flag = false; num_err++; } /* Fundamental check */ if (false == validate_nodes_edges()) { VTR_LOG_WARN("Fail in validating edges connected to each node!\n"); - check_flag = false; num_err++; } if (false == validate_node_segments()) { VTR_LOG_WARN("Fail in validating segment IDs of nodes !\n"); - check_flag = false; num_err++; } if (false == validate_edge_switches()) { VTR_LOG_WARN("Fail in validating switch IDs of edges !\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } bool RRGraph::is_dirty() const { @@ -827,6 +824,7 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_sides_.push_back(NUM_SIDES); node_Rs_.push_back(0.); node_Cs_.push_back(0.); + node_segments_.push_back(RRSegmentId::INVALID()); node_in_edges_.emplace_back(); //Initially empty node_out_edges_.emplace_back(); //Initially empty diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 3aa6afd94a9..733ac6e41a4 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -33,6 +33,7 @@ #include "rr_graph_reader.h" #include "router_lookahead_map.h" #include "rr_graph_clock.h" +#include "create_rr_graph.h" #include "rr_types.h" @@ -375,6 +376,9 @@ void create_rr_graph(const t_graph_type graph_type, print_rr_graph_stats(); + /* Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); + //Write out rr graph file if needed if (!det_routing_arch->write_rr_graph_filename.empty()) { write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf); diff --git a/vpr/src/util/rr_graph_obj_util.cpp b/vpr/src/util/rr_graph_obj_util.cpp new file mode 100644 index 00000000000..d7f824421d0 --- /dev/null +++ b/vpr/src/util/rr_graph_obj_util.cpp @@ -0,0 +1,30 @@ +/**************************************************************************** + * This file include most-utilized functions that manipulate on the + * RRGraph object + ***************************************************************************/ +#include +#include "rr_graph_obj_util.h" + +/**************************************************************************** + * Find the switches interconnecting two nodes + * Return a vector of switch ids + ***************************************************************************/ +std::vector find_rr_graph_switches(const RRGraph& rr_graph, + const RRNodeId& from_node, + const RRNodeId& to_node) { + std::vector switches; + std::vector edges = rr_graph.find_edges(from_node, to_node); + if (true == edges.empty()) { + /* edge is open, we return an empty vector of switches */ + return switches; + } + + /* Reach here, edge list is not empty, find switch id one by one + * and update the switch list + */ + for (auto edge : edges) { + switches.push_back(rr_graph.edge_switch(edge)); + } + + return switches; +} diff --git a/vpr/src/util/rr_graph_obj_util.h b/vpr/src/util/rr_graph_obj_util.h new file mode 100644 index 00000000000..cade12c22ad --- /dev/null +++ b/vpr/src/util/rr_graph_obj_util.h @@ -0,0 +1,14 @@ +#ifndef RR_GRAPH_OBJ_UTIL_H +#define RR_GRAPH_OBJ_UTIL_H + +/* Include header files which include data structures used by + * the function declaration + */ +#include "rr_graph_obj.h" + +/* Get node-to-node switches in a RRGraph */ +std::vector find_rr_graph_switches(const RRGraph& rr_graph, + const RRNodeId& from_node, + const RRNodeId& to_node); + +#endif diff --git a/vpr/src/util/rr_graph_obj_utils.h b/vpr/src/util/rr_graph_obj_utils.h new file mode 100644 index 00000000000..910b0ce3acd --- /dev/null +++ b/vpr/src/util/rr_graph_obj_utils.h @@ -0,0 +1,165 @@ +#ifndef RR_GRAPH_OBJ_UTILS_H +#define RR_GRAPH_OBJ_UTILS_H + +/* Include header files which include data structures used by + * the function declaration + */ +#include +#include "vtr_vector_map.h" + +/* + * + * Templated utility functions for cleaning and reordering IdMaps + * + */ + +//Returns true if all elements are contiguously ascending values (i.e. equal to their index) +template +bool are_contiguous(const Container& values) { + using T = typename Container::value_type; + size_t i = 0; + for (T val : values) { + if (val != T(i)) { + return false; + } + ++i; + } + return true; +} + +//Returns true if all elements in the vector 'values' evaluate true +template +bool all_valid(const Container& values) { + for (auto val : values) { + if (!val) { + return false; + } + } + return true; +} + +//Builds a mapping from old to new ids by skipping values marked invalid +template +Container compress_ids(const Container& ids) { + using Id = typename Container::value_type; + Container id_map(ids.size()); + size_t i = 0; + for (auto id : ids) { + if (id) { + //Valid + id_map[id] = Id(i); + ++i; + } + } + + return id_map; +} + +//Returns a vector based on 'values', which has had entries dropped & re-ordered according according to 'id_map'. +//Each entry in id_map corresponds to the assoicated element in 'values'. +//The value of the id_map entry is the new ID of the entry in values. +// +//If it is an invalid ID, the element in values is dropped. +//Otherwise the element is moved to the new ID location. +template +ValueContainer clean_and_reorder_values(const ValueContainer& values, const IdContainer& id_map) { + using Id = typename IdContainer::value_type; + VTR_ASSERT(values.size() == id_map.size()); + + //Allocate space for the values that will not be dropped + ValueContainer result(values.size()); + + //Move over the valid entries to their new locations + size_t new_count = 0; + for (size_t cur_idx = 0; cur_idx < values.size(); ++cur_idx) { + Id old_id = Id(cur_idx); + + Id new_id = id_map[old_id]; + if (new_id) { + //There is a valid mapping + result[new_id] = std::move(values[old_id]); + ++new_count; + } + } + + result.resize(new_count); + + return result; +} + +//Returns the set of new valid Ids defined by 'id_map' +//TODO: merge with clean_and_reorder_values +template +Container clean_and_reorder_ids(const Container& id_map) { + //For IDs, the values are the new id's stored in the map + using Id = typename Container::value_type; + + //Allocate a new vector to store the values that have been not dropped + Container result(id_map.size()); + + //Move over the valid entries to their new locations + size_t new_count = 0; + for (size_t cur_idx = 0; cur_idx < id_map.size(); ++cur_idx) { + Id old_id = Id(cur_idx); + + Id new_id = id_map[old_id]; + if (new_id) { + result[new_id] = new_id; + ++new_count; + } + } + + result.resize(new_count); + + return result; +} + +//Count how many of the Id's referenced in 'range' have a valid +//new mapping in 'id_map' +template +size_t count_valid_refs(R range, const vtr::vector_map& id_map) { + size_t valid_count = 0; + + for (Id old_id : range) { + if (id_map[old_id]) { + ++valid_count; + } + } + + return valid_count; +} + +//Updates the Ids in 'values' based on id_map, even if the original or new mapping is not valid +template +Container update_all_refs(const Container& values, const vtr::vector_map& id_map) { + Container updated; + + for (ValId orig_val : values) { + //The original item was valid + ValId new_val = id_map[orig_val]; + //The original item exists in the new mapping + updated.emplace_back(new_val); + } + + return updated; +} + +template +ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer& id_map) { + ValueContainer updated; + + for (auto orig_val : values) { + if (orig_val) { + //Original item valid + + auto new_val = id_map[orig_val]; + if (new_val) { + //The original item exists in the new mapping + updated.emplace_back(new_val); + } + } + } + return updated; +} + +#endif From 60de1d6661cc9d64f82ebea0194404e4a44665d1 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 17:35:34 -0700 Subject: [PATCH 03/58] add in/out edge reserve methods for RRGraph object --- vpr/src/device/create_rr_graph.cpp | 10 ++++++++++ vpr/src/device/rr_graph_obj.cpp | 16 ++++++++++++++++ vpr/src/device/rr_graph_obj.h | 16 ++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index e57c536ce2c..e538156e806 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -103,6 +103,16 @@ void convert_rr_graph(std::vector& vpr_segments) { // Create the edges std::map, RREdgeId> old_to_new_rr_edge; // Key: // {inode,iedge} + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + /* Reserve input and output edges for the node: + * this is very important to avoid memory fragments!!! + */ + device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.fan_in()); + device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.num_edges()); + } + + /* Add edges for each node */ for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; for (int iedge = 0; iedge < node.num_edges(); ++iedge) { diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 53066e89aff..33aef97ec26 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -806,6 +806,22 @@ void RRGraph::reserve_segments(const int& num_segments) { this->segments_.reserve(num_segments); } +/* Reserve the input edges for a node */ +void RRGraph::reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges) { + /* Validate the node id */ + VTR_ASSERT_SAFE(true == valid_node_id(node)); + /* Reserve the input edge list */ + this->node_in_edges_[node].reserve(num_in_edges); +} + +/* Reserve the input edges for a node */ +void RRGraph::reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges) { + /* Validate the node id */ + VTR_ASSERT_SAFE(true == valid_node_id(node)); + /* Reserve the input edge list */ + this->node_out_edges_[node].reserve(num_out_edges); +} + /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { //Allocate an ID diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f34b1116205..5b6ae1bdcf7 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -588,6 +588,22 @@ class RRGraph { void reserve_switches(const int& num_switches); void reserve_segments(const int& num_segments); + /* Reserve the lists of input/output edges for a RR node to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * + * For example: + * RRGraph rr_graph; + * // Add 1 source node to the RRGraph object + * RRNodeId src_node = rr_graph.create_node(SOURCE); + * // Reserve the output edges for the source node + * rr_graph.reserve_node_out_edges(src_node, 5); + * // Add your edges + */ + void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); + void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); + /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type * Detailed node-level information should be added using the set_node_* functions From dc06c98dfe738cce21abb406e7014fdd60b888e4 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 17:42:21 -0700 Subject: [PATCH 04/58] remove redundant files from util about RRGraph object --- vpr/src/util/rr_graph_obj_util.cpp | 30 ------ vpr/src/util/rr_graph_obj_util.h | 14 --- vpr/src/util/rr_graph_obj_utils.h | 165 ----------------------------- 3 files changed, 209 deletions(-) delete mode 100644 vpr/src/util/rr_graph_obj_util.cpp delete mode 100644 vpr/src/util/rr_graph_obj_util.h delete mode 100644 vpr/src/util/rr_graph_obj_utils.h diff --git a/vpr/src/util/rr_graph_obj_util.cpp b/vpr/src/util/rr_graph_obj_util.cpp deleted file mode 100644 index d7f824421d0..00000000000 --- a/vpr/src/util/rr_graph_obj_util.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** - * This file include most-utilized functions that manipulate on the - * RRGraph object - ***************************************************************************/ -#include -#include "rr_graph_obj_util.h" - -/**************************************************************************** - * Find the switches interconnecting two nodes - * Return a vector of switch ids - ***************************************************************************/ -std::vector find_rr_graph_switches(const RRGraph& rr_graph, - const RRNodeId& from_node, - const RRNodeId& to_node) { - std::vector switches; - std::vector edges = rr_graph.find_edges(from_node, to_node); - if (true == edges.empty()) { - /* edge is open, we return an empty vector of switches */ - return switches; - } - - /* Reach here, edge list is not empty, find switch id one by one - * and update the switch list - */ - for (auto edge : edges) { - switches.push_back(rr_graph.edge_switch(edge)); - } - - return switches; -} diff --git a/vpr/src/util/rr_graph_obj_util.h b/vpr/src/util/rr_graph_obj_util.h deleted file mode 100644 index cade12c22ad..00000000000 --- a/vpr/src/util/rr_graph_obj_util.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef RR_GRAPH_OBJ_UTIL_H -#define RR_GRAPH_OBJ_UTIL_H - -/* Include header files which include data structures used by - * the function declaration - */ -#include "rr_graph_obj.h" - -/* Get node-to-node switches in a RRGraph */ -std::vector find_rr_graph_switches(const RRGraph& rr_graph, - const RRNodeId& from_node, - const RRNodeId& to_node); - -#endif diff --git a/vpr/src/util/rr_graph_obj_utils.h b/vpr/src/util/rr_graph_obj_utils.h deleted file mode 100644 index 910b0ce3acd..00000000000 --- a/vpr/src/util/rr_graph_obj_utils.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef RR_GRAPH_OBJ_UTILS_H -#define RR_GRAPH_OBJ_UTILS_H - -/* Include header files which include data structures used by - * the function declaration - */ -#include -#include "vtr_vector_map.h" - -/* - * - * Templated utility functions for cleaning and reordering IdMaps - * - */ - -//Returns true if all elements are contiguously ascending values (i.e. equal to their index) -template -bool are_contiguous(const Container& values) { - using T = typename Container::value_type; - size_t i = 0; - for (T val : values) { - if (val != T(i)) { - return false; - } - ++i; - } - return true; -} - -//Returns true if all elements in the vector 'values' evaluate true -template -bool all_valid(const Container& values) { - for (auto val : values) { - if (!val) { - return false; - } - } - return true; -} - -//Builds a mapping from old to new ids by skipping values marked invalid -template -Container compress_ids(const Container& ids) { - using Id = typename Container::value_type; - Container id_map(ids.size()); - size_t i = 0; - for (auto id : ids) { - if (id) { - //Valid - id_map[id] = Id(i); - ++i; - } - } - - return id_map; -} - -//Returns a vector based on 'values', which has had entries dropped & re-ordered according according to 'id_map'. -//Each entry in id_map corresponds to the assoicated element in 'values'. -//The value of the id_map entry is the new ID of the entry in values. -// -//If it is an invalid ID, the element in values is dropped. -//Otherwise the element is moved to the new ID location. -template -ValueContainer clean_and_reorder_values(const ValueContainer& values, const IdContainer& id_map) { - using Id = typename IdContainer::value_type; - VTR_ASSERT(values.size() == id_map.size()); - - //Allocate space for the values that will not be dropped - ValueContainer result(values.size()); - - //Move over the valid entries to their new locations - size_t new_count = 0; - for (size_t cur_idx = 0; cur_idx < values.size(); ++cur_idx) { - Id old_id = Id(cur_idx); - - Id new_id = id_map[old_id]; - if (new_id) { - //There is a valid mapping - result[new_id] = std::move(values[old_id]); - ++new_count; - } - } - - result.resize(new_count); - - return result; -} - -//Returns the set of new valid Ids defined by 'id_map' -//TODO: merge with clean_and_reorder_values -template -Container clean_and_reorder_ids(const Container& id_map) { - //For IDs, the values are the new id's stored in the map - using Id = typename Container::value_type; - - //Allocate a new vector to store the values that have been not dropped - Container result(id_map.size()); - - //Move over the valid entries to their new locations - size_t new_count = 0; - for (size_t cur_idx = 0; cur_idx < id_map.size(); ++cur_idx) { - Id old_id = Id(cur_idx); - - Id new_id = id_map[old_id]; - if (new_id) { - result[new_id] = new_id; - ++new_count; - } - } - - result.resize(new_count); - - return result; -} - -//Count how many of the Id's referenced in 'range' have a valid -//new mapping in 'id_map' -template -size_t count_valid_refs(R range, const vtr::vector_map& id_map) { - size_t valid_count = 0; - - for (Id old_id : range) { - if (id_map[old_id]) { - ++valid_count; - } - } - - return valid_count; -} - -//Updates the Ids in 'values' based on id_map, even if the original or new mapping is not valid -template -Container update_all_refs(const Container& values, const vtr::vector_map& id_map) { - Container updated; - - for (ValId orig_val : values) { - //The original item was valid - ValId new_val = id_map[orig_val]; - //The original item exists in the new mapping - updated.emplace_back(new_val); - } - - return updated; -} - -template -ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer& id_map) { - ValueContainer updated; - - for (auto orig_val : values) { - if (orig_val) { - //Original item valid - - auto new_val = id_map[orig_val]; - if (new_val) { - //The original item exists in the new mapping - updated.emplace_back(new_val); - } - } - } - return updated; -} - -#endif From d48dc31ea27cb1b457ee1ddb9d59bfd3ee688bde Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 18:16:46 -0700 Subject: [PATCH 05/58] fix bugs in reserving in/out_edges for RRGraph object --- vpr/src/device/create_rr_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index e538156e806..9227ede96fa 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -109,7 +109,7 @@ void convert_rr_graph(std::vector& vpr_segments) { * this is very important to avoid memory fragments!!! */ device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.fan_in()); - device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.num_edges()); + device_ctx.rr_graph.reserve_node_out_edges(old_to_new_rr_node[inode], node.num_edges()); } /* Add edges for each node */ From b0048c0cd26e2b6c0bb3095b2ee3a81493c521a6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 23:28:41 -0700 Subject: [PATCH 06/58] optimizing memory footprints by removing unused vectors and maps --- vpr/src/device/create_rr_graph.cpp | 39 +- vpr/src/device/rr_graph_obj.cpp | 10 +- vpr/src/device/rr_graph_obj.h | 948 ++++++++++++++++------------- 3 files changed, 553 insertions(+), 444 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 9227ede96fa..99ccd5aab8c 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -53,10 +53,10 @@ void convert_rr_graph(std::vector& vpr_segments) { } /* Reserve list of nodes to be memory efficient */ - device_ctx.rr_graph.reserve_nodes(device_ctx.rr_nodes.size()); + device_ctx.rr_graph.reserve_nodes((unsigned long)device_ctx.rr_nodes.size()); // Create the nodes - std::map old_to_new_rr_node; + std::vector old_to_new_rr_node(device_ctx.rr_nodes.size(), RRNodeId::INVALID()); for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { auto& node = device_ctx.rr_nodes[inode]; RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); @@ -86,23 +86,19 @@ void convert_rr_graph(std::vector& vpr_segments) { short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); - VTR_ASSERT(!old_to_new_rr_node.count(inode)); + VTR_ASSERT(inode < old_to_new_rr_node.size()); old_to_new_rr_node[inode] = rr_node; } /* Reserve list of edges to be memory efficient */ - { - int num_edges_to_reserve = 0; - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - const auto& node = device_ctx.rr_nodes[inode]; - num_edges_to_reserve += node.num_edges(); - } - device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); + unsigned long num_edges_to_reserve = 0; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + num_edges_to_reserve += node.num_edges(); } + device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); // Create the edges - std::map, RREdgeId> old_to_new_rr_edge; // Key: - // {inode,iedge} for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; /* Reserve input and output edges for the node: @@ -116,22 +112,21 @@ void convert_rr_graph(std::vector& vpr_segments) { for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; for (int iedge = 0; iedge < node.num_edges(); ++iedge) { - int isink_node = node.edge_sink_node(iedge); + size_t isink_node = node.edge_sink_node(iedge); int iswitch = node.edge_switch(iedge); - VTR_ASSERT(old_to_new_rr_node.count(inode)); - VTR_ASSERT(old_to_new_rr_node.count(isink_node)); + VTR_ASSERT(inode < old_to_new_rr_node.size()); + VTR_ASSERT(isink_node < old_to_new_rr_node.size()); - RREdgeId rr_edge = device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], - old_to_new_rr_node[isink_node], - RRSwitchId(iswitch)); - - auto key = std::make_pair(inode, iedge); - VTR_ASSERT(!old_to_new_rr_edge.count(key)); - old_to_new_rr_edge[key] = rr_edge; + device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], + old_to_new_rr_node[isink_node], + RRSwitchId(iswitch)); } } + /* Ensure that we reserved what we want */ + VTR_ASSERT(num_edges_to_reserve == (unsigned long)device_ctx.rr_graph.edges().size()); + /* Partition edges to be two class: configurable (1st part) and * non-configurable (2nd part) * See how the router will use the edges and determine the strategy diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 33aef97ec26..2a93c588ad8 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -7,6 +7,7 @@ #include #include +#include "vtr_geometry.h" #include "vtr_vector_map.h" #include "vtr_log.h" #include "vtr_util.h" @@ -764,7 +765,7 @@ void RRGraph::clear_dirty() { } /* Reserve a list of nodes */ -void RRGraph::reserve_nodes(const int& num_nodes) { +void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ this->node_ids_.reserve(num_nodes); @@ -786,7 +787,7 @@ void RRGraph::reserve_nodes(const int& num_nodes) { } /* Reserve a list of edges */ -void RRGraph::reserve_edges(const int& num_edges) { +void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ this->edge_ids_.reserve(num_edges); this->edge_src_nodes_.reserve(num_edges); @@ -795,13 +796,13 @@ void RRGraph::reserve_edges(const int& num_edges) { } /* Reserve a list of switches */ -void RRGraph::reserve_switches(const int& num_switches) { +void RRGraph::reserve_switches(const size_t& num_switches) { this->switch_ids_.reserve(num_switches); this->switches_.reserve(num_switches); } /* Reserve a list of segments */ -void RRGraph::reserve_segments(const int& num_segments) { +void RRGraph::reserve_segments(const size_t& num_segments) { this->segment_ids_.reserve(num_segments); this->segments_.reserve(num_segments); } @@ -1132,6 +1133,7 @@ void RRGraph::partition_edges() { } void RRGraph::build_fast_node_lookup() const { + /* Free the current fast node look-up, we will rebuild a new one here */ invalidate_fast_node_lookup(); for (auto node : nodes()) { diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 5b6ae1bdcf7..57f7130636a 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -1,25 +1,28 @@ /************************************************************************ - * This file introduces a class to model a Routing Resource Graph (RRGraph or RRG) + * This file introduces a class to model a Routing Resource Graph (RRGraph or + *RRG) * which is widely used by placers, routers, analyzers etc. * * Overview * ======== * RRGraph aims to describe in a general way how routing resources are connected * in a FPGA fabric. - * It includes device-level information for routing resources, - * such as the physical location of nodes, - * routing segment information of each routing resource + * It includes device-level information for routing resources, + * such as the physical location of nodes, + * routing segment information of each routing resource * switch information of each routing resource. - * - * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many cycles), + * + * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many + *cycles), * which consists of a number of nodes and edges. * * Node * ---- - * Each node represents a routing resource, which could be - * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) - * 2. an input or an output of a logic block (IPIN or OPIN) - * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending points of routing trees. + * Each node represents a routing resource, which could be + * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) + * 2. an input or an output of a logic block (IPIN or OPIN) + * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending + *points of routing trees. * * Edge * ---- @@ -34,42 +37,47 @@ * * The switch information are categorized in the rr_switch_inf of RRGraph class. * rr_switch_inf is created to minimize memory footprint of RRGraph classs - * While the RRG could contain millions (even much larger) of edges, there are only + * While the RRG could contain millions (even much larger) of edges, there are + *only * a limited number of types of switches. - * Hence, we use a flyweight pattern to store switch-related information that differs + * Hence, we use a flyweight pattern to store switch-related information that + *differs * only for types of switches (switch type, drive strength, R, C, etc.). - * Each edge stores the ids of the switch that implements it so this additional information + * Each edge stores the ids of the switch that implements it so this additional + *information * can be easily looked up. * - * Note: All the switch-related information, such as R, C, should be placed in rr_switch_inf - * but NOT directly in the edge-related data of RRGraph. - * If you wish to create a new data structure to represent switches between routing resources, + * Note: All the switch-related information, such as R, C, should be placed in + *rr_switch_inf + * but NOT directly in the edge-related data of RRGraph. + * If you wish to create a new data structure to represent switches between + *routing resources, * please follow the flyweight pattern by linking your switch ids to edges only! * - * Guidlines on using the RRGraph data structure + * Guidlines on using the RRGraph data structure * ============================================= * * For those want to access data from RRGraph * ------------------------------------------ * Some examples for most frequent data query: - * + * * // Strongly suggest to use a read-only rr_graph object * const RRGraph& rr_graph; * * // Access type of a node with a given node id - * // Get the unique node id that you may get - * // from other data structures or functions - * RRNodeId node_id; + * // Get the unique node id that you may get + * // from other data structures or functions + * RRNodeId node_id; * t_rr_type node_type = rr_graph.node_type(node_id); * - * // Access all the fan-out edges from a given node + * // Access all the fan-out edges from a given node * for (const RREdgeId& out_edge_id : rr_graph.node_out_edges(node_id)) { * // Do something with out_edge * } * // If you only want to learn the number of fan-out edges * size_t num_out_edges = rr_graph.node_fan_out(node_id); * - * // Access all the switches connected to a given node + * // Access all the switches connected to a given node * for (const RREdgeId& in_edge_id : rr_graph.node_in_edges(node_id)) { * RRSwitchId edge_switch_id = rr_graph.edge_switch(in_edge_id); * // Do something with the switch @@ -84,56 +92,75 @@ * We suggest developers to create builders in separated C/C++ source files * outside the rr_graph header and source files * - * After build/modify a RRGraph, please do run a fundamental check, a public accessor. - * to ensure that your RRGraph does not include invalid nodes/edges/switches/segements + * After build/modify a RRGraph, please do run a fundamental check, a public + *accessor. + * to ensure that your RRGraph does not include invalid + *nodes/edges/switches/segements * as well as connections. - * The validate() function gurantees the consistency between internal data structures, + * The validate() function gurantees the consistency between internal data + *structures, * such as the id cross-reference between nodes and edges etc., * so failing it indicates a fatal bug! - * This is a must-do check! + * This is a must-do check! * - * Example: + * Example: * RRGraph rr_graph; * ... // Building RRGraph - * rr_graph.validate(); + * rr_graph.validate(); * - * Optionally, we strongly recommend developers to run an advance check in check_rr_graph() + * Optionally, we strongly recommend developers to run an advance check in + *check_rr_graph() * This guarantees legal and routable RRGraph for VPR routers. * - * This checks for connectivity or other information in the RRGraph that is unexpected - * or unusual in an FPGA, and likely indicates a problem in your graph generation. - * However, if you are intentionally creating an RRGraph with this unusual, - * buts still technically legal, behaviour, you can write your own check_rr_graph() with weaker assumptions. + * This checks for connectivity or other information in the RRGraph that is + *unexpected + * or unusual in an FPGA, and likely indicates a problem in your graph + *generation. + * However, if you are intentionally creating an RRGraph with this unusual, + * buts still technically legal, behaviour, you can write your own + *check_rr_graph() with weaker assumptions. * - * Note: Do NOT modify the coordinate system for nodes, they are designed for downstream drawers and routers + * Note: Do NOT modify the coordinate system for nodes, they are designed for + *downstream drawers and routers * * For those want to extend RRGraph data structure * -------------------------------------------------------------------------- * Please avoid modifying any existing public/private accessors/mutators * in order to keep a stable RRGraph object in the framework - * Developers may add more internal data to RRGraph as well as associate accessors/mutators - * Please update and comment on the added features properly to keep this data structure friendly to be extended. + * Developers may add more internal data to RRGraph as well as associate + *accessors/mutators + * Please update and comment on the added features properly to keep this data + *structure friendly to be extended. * - * Try to keep your extension within only graph-related internal data to RRGraph. - * In other words, extension is necessary when the new node/edge attributes are needed. - * RRGraph should NOT include other data which are shared by other data structures outside. + * Try to keep your extension within only graph-related internal data to + *RRGraph. + * In other words, extension is necessary when the new node/edge attributes are + *needed. + * RRGraph should NOT include other data which are shared by other data + *structures outside. * The rr-graph is the single largest data structure in VPR, - * so avoid adding unnecessary information per node or per edge to it, as it will impact memory footprint. - * Instead, using indices to point to the outside data source instead of embedding to RRGraph - * For example: - * For any placement/routing cost related information, try to extend t_rr_indexed_data, but not RRGraph - * For any placement/routing results, try to extend PlaceContext and RoutingContext, but not RRGraph - * + * so avoid adding unnecessary information per node or per edge to it, as it + *will impact memory footprint. + * Instead, using indices to point to the outside data source instead of + *embedding to RRGraph + * For example: + * For any placement/routing cost related information, try to extend + *t_rr_indexed_data, but not RRGraph + * For any placement/routing results, try to extend PlaceContext and + *RoutingContext, but not RRGraph + * * For those want to develop placers or routers * -------------------------------------------------------------------------- * The RRGraph is designed to be a read-only database/graph, once created. * Placement and routing should NOT change any attributes of RRGraph. - * Any placement and routing results should be stored in other data structures, such as PlaceContext and RoutingContext. + * Any placement and routing results should be stored in other data structures, + *such as PlaceContext and RoutingContext. * - * Tracing Cross-Reference + * Tracing Cross-Reference * ======================= * RRGraph is designed to a self-contained data structure as much as possible. - * It includes the switch information (rr_switch) and segment_information (rr_segment) + * It includes the switch information (rr_switch) and segment_information + *(rr_segment) * which are necessary to build-up any external data structures. * * Internal cross-reference @@ -163,13 +190,14 @@ * The only cross-reference to outside data structures is the cost_index * corresponding to the data structure t_rr_index_data * Details can be found in the definition of t_rr_index_data - * This allows rapid look up by the router of additional information it needs for this node, using a flyweight pattern. + * This allows rapid look up by the router of additional information it needs + *for this node, using a flyweight pattern. * * +---------+ cost_index +------------------------------+ - * | RRGraph |-------------->| cost_index_data[cost_index] | + * | RRGraph |-------------->| cost_index_data[cost_index] | * +---------+ +------------------------------+ * - * Note: if you wish to use a customized routing-cost data structure, + * Note: if you wish to use a customized routing-cost data structure, * please use the flyweigth pattern as we do for t_rr_index_data! * * Access to a node/edge/switch/segment, please use the StrongId created @@ -180,18 +208,19 @@ * For segment, use RRSegmentId * * These are the unique identifier for each data type. - * To check if your id is valid or not, use the INVALID() function of StrongId class. + * To check if your id is valid or not, use the INVALID() function of + *StrongId class. * Example: * if (node_id == RRNodeId::INVALID()) { - * } + * } * ***********************************************************************/ #ifndef RR_GRAPH_OBJ_H #define RR_GRAPH_OBJ_H /* - * Notes in include header files in a head file - * Only include the neccessary header files + * Notes in include header files in a head file + * Only include the neccessary header files * that is required by the data types in the function/class declarations! */ /* Header files should be included in a sequence */ @@ -211,11 +240,13 @@ class RRGraph { public: /* Types */ - /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ + /* Iterators used to create iterator-based loop for + * nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; - typedef vtr::vector::const_iterator segment_iterator; + typedef vtr::vector::const_iterator + segment_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; @@ -225,213 +256,234 @@ class RRGraph { public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments - * To iterate over the nodes/edges/switches/segments in a RRGraph, - * using a range-based loop is suggested. - * ----------------------------------------------------------------- - * Example: iterate over all the nodes - * // Strongly suggest to use a read-only rr_graph object - * const RRGraph& rr_graph; - * for (const RRNodeId& node : rr_graph.nodes()) { - * // Do something with each node - * } - * - * for (const RREdgeId& edge : rr_graph.edges()) { - * // Do something with each edge - * } - * - * for (const RRSwitchId& switch : rr_graph.switches()) { - * // Do something with each switch - * } - * - * for (const RRSegmentId& segment : rr_graph.segments()) { - * // Do something with each segment - * } - */ + * To iterate over the nodes/edges/switches/segments in a RRGraph, + * using a range-based loop is suggested. + * ----------------------------------------------------------------- + * Example: iterate over all the nodes + * // Strongly suggest to use a read-only rr_graph object + * const RRGraph& rr_graph; + * for (const RRNodeId& node : rr_graph.nodes()) { + * // Do something with each node + * } + * + * for (const RREdgeId& edge : rr_graph.edges()) { + * // Do something with each edge + * } + * + * for (const RRSwitchId& switch : rr_graph.switches()) { + * // Do something with each switch + * } + * + * for (const RRSegmentId& segment : rr_graph.segments()) { + * // Do something with each segment + * } + */ node_range nodes() const; edge_range edges() const; switch_range switches() const; segment_range segments() const; /* Node-level attributes */ - size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this accessor as outside functions should use RRNodeId */ - - /* get the type of a RRGraph node : types of each node, can be channel wires (CHANX or CHANY) or - * logic block pins(OPIN or IPIN) or virtual nodes (SOURCE or SINK) - * see t_rr_type definition for more details - */ + size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this + accessor as outside + functions should use + RRNodeId */ + + /* get the type of a RRGraph node : types of each node, can be channel wires + * (CHANX or CHANY) or + * logic block pins(OPIN or IPIN) or virtual + * nodes (SOURCE or SINK) + * see t_rr_type definition for more details + */ t_rr_type node_type(const RRNodeId& node) const; /* Get coordinate of a node. (xlow, xhigh, ylow, yhigh): - * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh - * This is still the case when a logic block has a height > 1 - * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent - * where the routing segment starts and ends. - * Note that our convention alway keeps - * xlow <= xhigh and ylow <= yhigh - * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in INC_DIRECTION - * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION - * - * Note: there is only a single drive point for each routing segment (track) - * in the context of uni-directional wires - * - * Example : - * CHANX in INC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * ----------------------------> - * - * CHANX in DEC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * <---------------------------- - * - * CHANY in INC_DIRECTION - * - * /|\ <-------(xhigh, yhigh) - * | - * | <-------(xlow, ylow) - * - * CHANY in DEC_DIRECTION - * - * | <-------(xhigh, yhigh) - * | - * \|/ <-------(xlow, ylow) - */ + * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh + * This is still the case when a logic block has a height > 1 + * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent + * where the routing segment starts and ends. + * Note that our convention alway keeps + * xlow <= xhigh and ylow <= yhigh + * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in + *INC_DIRECTION + * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION + * + * Note: there is only a single drive point for each routing segment (track) + * in the context of uni-directional wires + * + * Example : + * CHANX in INC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * ----------------------------> + * + * CHANX in DEC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * <---------------------------- + * + * CHANY in INC_DIRECTION + * + * /|\ <-------(xhigh, yhigh) + * | + * | <-------(xlow, ylow) + * + * CHANY in DEC_DIRECTION + * + * | <-------(xhigh, yhigh) + * | + * \|/ <-------(xlow, ylow) + */ short node_xlow(const RRNodeId& node) const; short node_ylow(const RRNodeId& node) const; short node_xhigh(const RRNodeId& node) const; short node_yhigh(const RRNodeId& node) const; - /* Get the length of a routing track. - * Note that it is ONLY meaningful for CHANX and CHANY, which represents the number of logic blocks that a routing track spans - * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be always 0 - */ + /* Get the length of a routing track. + * Note that it is ONLY meaningful for CHANX and CHANY, which represents the + * number of logic blocks that a routing track spans + * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be + * always 0 + */ short node_length(const RRNodeId& node) const; /* A short-cut function to get coordinates of a node, - * where xmin of vtr::Rect = xlow, - * ymin of vtr::Rect = ylow, - * xmax of vtr::Rect = xhigh, - * ymax of vtr::Rect = yhigh. - */ + * where xmin of vtr::Rect = xlow, + * ymin of vtr::Rect = ylow, + * xmax of vtr::Rect = xhigh, + * ymax of vtr::Rect = yhigh. + */ vtr::Rect node_bounding_box(const RRNodeId& node) const; - /* Get node starting and ending points in routing channels. - * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and node_yhigh() - * For routing tracks in INC_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * For routing tracks in DEC_DIRECTION: - * node_start_coordinate() returns (xhigh, yhigh) as the starting point - * node_end_coordinate() returns (xlow, ylow) as the ending point - * - * For routing tracks in BI_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * Applicable to routing track nodes only!!! - * This function will requires the types of node to be either CHANX or CHANY - */ + /* Get node starting and ending points in routing channels. + * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and + *node_yhigh() + * For routing tracks in INC_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * For routing tracks in DEC_DIRECTION: + * node_start_coordinate() returns (xhigh, yhigh) as the starting point + * node_end_coordinate() returns (xlow, ylow) as the ending point + * + * For routing tracks in BI_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * Applicable to routing track nodes only!!! + * This function will requires the types of node to be either CHANX or CHANY + */ vtr::Point node_start_coordinate(const RRNodeId& node) const; vtr::Point node_end_coordinate(const RRNodeId& node) const; - /* Get the capacity of a node. - * Literally, how many nets can be mapped to the node. - * Typically, each node has a capacity of 1 but special nodes (SOURCE and SINK) will have a - * large number due to logic equivalent pins - * See Vaughn Betz's book for more details - */ + /* Get the capacity of a node. + * Literally, how many nets can be mapped to the node. + * Typically, each node has a capacity of 1 but special nodes (SOURCE and + * SINK) will have a + * large number due to logic equivalent pins + * See Vaughn Betz's book for more details + */ short node_capacity(const RRNodeId& node) const; /* Get the number of edges that drives a given node - * Note that each edge is typically driven by a node - * (true in VPR RRG that is currently supported, may not be true in customized RRG) - * This can also represent the number of drive nodes - * An example where fan-in of a node C is 2 - * - * edge A - * node A -------->+ - * | - * |-->node C - * edgeB | - * node B -------->+ - * - */ + * Note that each edge is typically driven by a node + * (true in VPR RRG that is currently supported, may not be true in customized + *RRG) + * This can also represent the number of drive nodes + * An example where fan-in of a node C is 2 + * + * edge A + * node A -------->+ + * | + * |-->node C + * edgeB | + * node B -------->+ + * + */ short node_fan_in(const RRNodeId& node) const; /* Get the number of edges that are driven a given node - * Note that each edge typically drives by a node - * (true in VPR RRG that is currently supported, may not be true in customized RRG) - * This can also represent the number of fan-out nodes - * An example where fan-out of a node A is 2 - * - * edge A - * node A -+--------> node B - * | - * | - * | edgeB - * +--------> node C - * - */ + * Note that each edge typically drives by a node + * (true in VPR RRG that is currently supported, may not be true in customized + *RRG) + * This can also represent the number of fan-out nodes + * An example where fan-out of a node A is 2 + * + * edge A + * node A -+--------> node B + * | + * | + * | edgeB + * +--------> node C + * + */ short node_fan_out(const RRNodeId& node) const; /* Get the ptc_num of a node - * The ptc (pin, track, or class) number is an integer - * that allows you to differentiate between wires, pins or sources/sinks with overlapping x,y coordinates or extent. - * This is useful for drawing rr-graphs nicely. - * For example, all the CHANX rr_nodes that have the same y coordinate and x-coordinates - * that overlap will have different ptc numbers, by convention starting at 0. - * This allows them to be drawn without overlapping, as the ptc num can be used as a track identifier. - * The main routing code does not care about ptc num. - * - * The ptc_num carries different meanings for different node types - * (true in VPR RRG that is currently supported, may not be true in customized RRG) - * CHANX or CHANY: the track id in routing channels - * OPIN or IPIN: the index of pins in the logic block data structure - * SOURCE and SINK: the class id of a pin (indicating logic equivalence of pins) in the logic block data structure - * - * To ease the access to ptc_num for different types of nodes: - * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes - * node_track_num() is designed for routing tracks, which are CHANX and CHANY nodes - * node_class_num() is designed for routing source and sinks, which are SOURCE and SINK nodes - * - * Due to a useful identifier, ptc_num is used in building fast look-up - */ + * The ptc (pin, track, or class) number is an integer + * that allows you to differentiate between wires, pins or sources/sinks with + *overlapping x,y coordinates or extent. + * This is useful for drawing rr-graphs nicely. + * For example, all the CHANX rr_nodes that have the same y coordinate and + *x-coordinates + * that overlap will have different ptc numbers, by convention starting at 0. + * This allows them to be drawn without overlapping, as the ptc num can be + *used as a track identifier. + * The main routing code does not care about ptc num. + * + * The ptc_num carries different meanings for different node types + * (true in VPR RRG that is currently supported, may not be true in customized + *RRG) + * CHANX or CHANY: the track id in routing channels + * OPIN or IPIN: the index of pins in the logic block data structure + * SOURCE and SINK: the class id of a pin (indicating logic equivalence of + *pins) in the logic block data structure + * + * To ease the access to ptc_num for different types of nodes: + * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes + * node_track_num() is designed for routing tracks, which are CHANX and CHANY + *nodes + * node_class_num() is designed for routing source and sinks, which are SOURCE + *and SINK nodes + * + * Due to a useful identifier, ptc_num is used in building fast look-up + */ short node_ptc_num(const RRNodeId& node) const; short node_pin_num(const RRNodeId& node) const; short node_track_num(const RRNodeId& node) const; short node_class_num(const RRNodeId& node) const; /* Get the index of cost data in the list of cost_indexed_data data structure - * It contains the routing cost for different nodes in the RRGraph - * when used in evaluate different routing paths - * See cross-reference section in this header file for more details - */ + * It contains the routing cost for different nodes in the RRGraph + * when used in evaluate different routing paths + * See cross-reference section in this header file for more details + */ short node_cost_index(const RRNodeId& node) const; /* Get the directionality of a node - * see node coordinate for details - * only matters the routing track nodes (CHANX and CHANY) - */ + * see node coordinate for details + * only matters the routing track nodes (CHANX and CHANY) + */ e_direction node_direction(const RRNodeId& node) const; - /* Get the side where the node physically locates on a logic block. - * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of logic block - * The side should be consistent to definition in architecture XML - * - * TOP - * +-----------+ - * | | - * LEFT | Logic | RIGHT - * | Block | - * | | - * +-----------+ - * BOTTOM - * - */ + /* Get the side where the node physically locates on a logic block. + * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of + *logic block + * The side should be consistent to definition in architecture + *XML + * + * TOP + * +-----------+ + * | | + * LEFT | Logic | RIGHT + * | Block | + * | | + * +-----------+ + * BOTTOM + * + */ e_side node_side(const RRNodeId& node) const; /* Get resistance of a node, used to built RC tree for timing analysis */ @@ -441,8 +493,9 @@ class RRGraph { float node_C(const RRNodeId& node) const; /* Get segment id of a node, containing the information of the routing - * segment that the node represents. See more details in the data structure t_segment_inf - */ + * segment that the node represents. See more details in the data structure + * t_segment_inf + */ RRSegmentId node_segment(const RRNodeId& node) const; /* Get the number of non-configurable incoming edges to a node */ @@ -469,99 +522,120 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; - /* Edge-related attributes - * An example to explain the terminology used in RRGraph - * edgeA - * nodeA --------> nodeB - * | edgeB - * +-------> nodeC - * - * +----------+----------------+----------------+ - * | Edge Id | edge_src_node | edge_sink_node | - * +----------+----------------+----------------+ - * | edgeA | nodeA | nodeB | - * +----------+----------------+----------------+ - * | edgeB | nodeA | nodeC | - * +----------+----------------+----------------+ - * - */ - size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this accessor as outside functions should use RREdgeId */ + /* Edge-related attributes + * An example to explain the terminology used in RRGraph + * edgeA + * nodeA --------> nodeB + * | edgeB + * +-------> nodeC + * + * +----------+----------------+----------------+ + * | Edge Id | edge_src_node | edge_sink_node | + * +----------+----------------+----------------+ + * | edgeA | nodeA | nodeB | + * +----------+----------------+----------------+ + * | edgeB | nodeA | nodeC | + * +----------+----------------+----------------+ + * + */ + size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this + accessor as outside + functions should use + RREdgeId */ /* Get the source node which drives a edge */ RRNodeId edge_src_node(const RREdgeId& edge) const; /* Get the sink node which a edge ends to */ RRNodeId edge_sink_node(const RREdgeId& edge) const; /* Get the switch id which a edge represents - * using switch id, timing and other information can be found - * for any node-to-node connection - */ + * using switch id, timing and other information can be found + * for any node-to-node connection + */ RRSwitchId edge_switch(const RREdgeId& edge) const; - /* Judge if a edge is configurable or not. - * A configurable edge is controlled by a programmable memory bit - * while a non-configurable edge is typically a hard-wired connection - */ + /* Judge if a edge is configurable or not. + * A configurable edge is controlled by a programmable memory bit + * while a non-configurable edge is typically a hard-wired connection + */ bool edge_is_configurable(const RREdgeId& edge) const; bool edge_is_non_configurable(const RREdgeId& edge) const; /* Switch Info */ - size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate this accessor as outside functions should use RRSwitchId */ + size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate + this accessor as + outside functions + should use + RRSwitchId */ /* Get the switch info of a switch used in this RRGraph */ const t_rr_switch_inf& get_switch(const RRSwitchId& switch_id) const; /* Segment Info */ - size_t segment_index(const RRSegmentId& segment_id) const; /* TODO: deprecate this accessor as outside functions should use RRSegmentId */ + size_t segment_index(const RRSegmentId& segment_id) + const; /* TODO: deprecate this accessor as outside functions should use + RRSegmentId */ /* Get the segment info of a routing segment used in this RRGraph */ const t_segment_inf& get_segment(const RRSegmentId& segment_id) const; /* Utilities */ /* Find the edges connecting two nodes */ - std::vector find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const; + std::vector find_edges(const RRNodeId& src_node, + const RRNodeId& sink_node) const; /* Find a node with given features from internal fast look-up */ - RRNodeId find_node(const short& x, const short& y, const t_rr_type& type, const int& ptc, const e_side& side = NUM_SIDES) const; - /* Find the number of routing tracks in a routing channel with a given coordinate */ - short chan_num_tracks(const short& x, const short& y, const t_rr_type& type) const; - - /* This flag is raised when the RRgraph contains invalid nodes/edges etc. - * Invalid nodes/edges exist when users remove nodes/edges from RRGraph - * RRGraph object will not immediately remove the nodes and edges but - * will mark them with invalid ids. - * Afterwards the is_dirty flag is raised as an indicator, to tell users - * that a clean-up process (invoked by compress() function)is required. - * After executing compress(), the is_dirty will be reset to false - * - * Example: - * RRGraph rr_graph; - * RRNodeId node_id; // Node id to be removed - * rr_graph.remove_node(node_id); - * // RRGraph is now dirty (rr_graph.is_dirty() == true) - * ... - * // During this period, when you perform data query, - * // You may encounter invalid nodes and edges - * // It may happen that - * // 1. their ids are invalid - * // 2. the cross-reference between nodes and edge, i.e., - * // node_in_edges(), node_out_edges() - * // 3. invalid node returned from find_node(), which use fast look-up - * ... - * rr_graph.compress(); - * // RRGraph is now clean (rr_graph.is_dirty() == false) - */ + RRNodeId find_node(const short& x, + const short& y, + const t_rr_type& type, + const int& ptc, + const e_side& side = NUM_SIDES) const; + /* Find the number of routing tracks in a routing channel with a given + * coordinate */ + short chan_num_tracks(const short& x, + const short& y, + const t_rr_type& type) const; + + /* This flag is raised when the RRgraph contains invalid nodes/edges etc. + * Invalid nodes/edges exist when users remove nodes/edges from RRGraph + * RRGraph object will not immediately remove the nodes and edges but + * will mark them with invalid ids. + * Afterwards the is_dirty flag is raised as an indicator, to tell users + * that a clean-up process (invoked by compress() function)is required. + * After executing compress(), the is_dirty will be reset to false + * + * Example: + * RRGraph rr_graph; + * RRNodeId node_id; // Node id to be removed + * rr_graph.remove_node(node_id); + * // RRGraph is now dirty (rr_graph.is_dirty() == true) + * ... + * // During this period, when you perform data query, + * // You may encounter invalid nodes and edges + * // It may happen that + * // 1. their ids are invalid + * // 2. the cross-reference between nodes and edge, i.e., + * // node_in_edges(), node_out_edges() + * // 3. invalid node returned from find_node(), which use fast look-up + * ... + * rr_graph.compress(); + * // RRGraph is now clean (rr_graph.is_dirty() == false) + */ bool is_dirty() const; - public: /* Echos */ - void print_node(const RRNodeId& node) const; /* Print the detailed information of a node */ + public: /* Echos */ + void print_node(const RRNodeId& node) + const; /* Print the detailed information of a node */ public: /* Public Validators */ - /* Check data structure for internal consistency - * This function will - * 1. re-build fast look-up for nodes - * 2. check all the edges and nodes are connected - * Literally, no invalid ids in fan-in/fan-out of edges/nodes - * 3. check that all the nodes representing routing tracks have valid id linked to its segment-related data structure - * 4. check that all the edges have valid id linked to its switch-related data structure - * - * Any valid and non-dirty RRGraph should pass this check - * It is highly recommended to run this function after building any RRGraph object - */ + /* Check data structure for internal consistency + * This function will + * 1. re-build fast look-up for nodes + * 2. check all the edges and nodes are connected + * Literally, no invalid ids in fan-in/fan-out of edges/nodes + * 3. check that all the nodes representing routing tracks have valid id + *linked to its segment-related data structure + * 4. check that all the edges have valid id linked to its switch-related data + *structure + * + * Any valid and non-dirty RRGraph should pass this check + * It is highly recommended to run this function after building any RRGraph + *object + */ bool validate() const; /* Validate is the node id does exist in the RRGraph */ @@ -571,78 +645,87 @@ class RRGraph { bool valid_edge_id(const RREdgeId& edge) const; public: /* Mutators */ - /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * For example: - * RRGraph rr_graph; - * // Add 1000 CHANX nodes to the RRGraph object - * rr_graph.reserve_nodes(1000); - * for (size_t i = 0; i < 1000; ++i) { - * rr_graph.create_node(CHANX); - * } - */ - void reserve_nodes(const int& num_nodes); - void reserve_edges(const int& num_edges); - void reserve_switches(const int& num_switches); - void reserve_segments(const int& num_segments); - - /* Reserve the lists of input/output edges for a RR node to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * - * For example: - * RRGraph rr_graph; - * // Add 1 source node to the RRGraph object - * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the output edges for the source node - * rr_graph.reserve_node_out_edges(src_node, 5); - * // Add your edges - */ + /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * For example: + * RRGraph rr_graph; + * // Add 1000 CHANX nodes to the RRGraph object + * rr_graph.reserve_nodes(1000); + * for (size_t i = 0; i < 1000; ++i) { + * rr_graph.create_node(CHANX); + * } + */ + void reserve_nodes(const unsigned long& num_nodes); + /* We use long data type for edges because the number of edges is very large + */ + void reserve_edges(const unsigned long& num_edges); + void reserve_switches(const size_t& num_switches); + void reserve_segments(const size_t& num_segments); + + /* Reserve the lists of input/output edges for a RR node to be memory + *efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * + * For example: + * RRGraph rr_graph; + * // Add 1 source node to the RRGraph object + * RRNodeId src_node = rr_graph.create_node(SOURCE); + * // Reserve the output edges for the source node + * rr_graph.reserve_node_out_edges(src_node, 5); + * // Add your edges + */ void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); - void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); + void reserve_node_out_edges(const RRNodeId& node, + const size_t& num_out_edges); /* Add new elements (node, edge, switch, etc.) to RRGraph */ - /* Add a node to the RRGraph with a deposited type - * Detailed node-level information should be added using the set_node_* functions - * For example: - * RRNodeId node = create_node(); - * set_node_xlow(node, 0); - */ + /* Add a node to the RRGraph with a deposited type + * Detailed node-level information should be added using the set_node_* + * functions + * For example: + * RRNodeId node = create_node(); + * set_node_xlow(node, 0); + */ RRNodeId create_node(const t_rr_type& type); - /* Add a edge to the RRGraph, by providing the source and sink node - * This function will automatically create a node and - * configure the nodes and edges in connection - */ - RREdgeId create_edge(const RRNodeId& source, const RRNodeId& sink, const RRSwitchId& switch_id); + /* Add a edge to the RRGraph, by providing the source and sink node + * This function will automatically create a node and + * configure the nodes and edges in connection + */ + RREdgeId create_edge(const RRNodeId& source, + const RRNodeId& sink, + const RRSwitchId& switch_id); RRSwitchId create_switch(const t_rr_switch_inf& switch_info); RRSegmentId create_segment(const t_segment_inf& segment_info); /* Remove elements from RRGraph - * This function just turn the nodes and edges to an invalid id without deletion - * This will cause the RRGraph to be marked as dirty (is_dirty(): false => true) - * To thoroughly remove the edges and nodes as well as clear the dirty flag, - * use compress() after the remove functions - * Example: - * RRGraph rr_graph; - * rr_graph.remove_node() - * .. // remove more nodes - * rr_graph.remove_edge() - * .. // remove more nodes - * // rr_graph.is_dirty() == true - * // If you want to access any node or edge - * // Check codes for ids should be intensively used - * // Such as, - * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { - * // if (RREdgeId::INVALID() != in_edge) { - * // ... - * // } - * // } - * rr_graph.compress() - * // rr_graph.is_dirty() == false - */ + * This function just turn the nodes and edges to an invalid id without + * deletion + * This will cause the RRGraph to be marked as dirty (is_dirty(): false => + * true) + * To thoroughly remove the edges and nodes as well as clear the dirty flag, + * use compress() after the remove functions + * Example: + * RRGraph rr_graph; + * rr_graph.remove_node() + * .. // remove more nodes + * rr_graph.remove_edge() + * .. // remove more nodes + * // rr_graph.is_dirty() == true + * // If you want to access any node or edge + * // Check codes for ids should be intensively used + * // Such as, + * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { + * // if (RREdgeId::INVALID() != in_edge) { + * // ... + * // } + * // } + * rr_graph.compress() + * // rr_graph.is_dirty() == false + */ void remove_node(const RRNodeId& node); void remove_edge(const RREdgeId& edge); @@ -653,9 +736,9 @@ class RRGraph { void set_node_yhigh(const RRNodeId& node, const short& yhigh); /* This is a short-cut function, set xlow/xhigh/ylow/yhigh for a node - * Please respect the following to configure the bb object: - * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; - */ + * Please respect the following to configure the bb object: + * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; + */ void set_node_bounding_box(const RRNodeId& node, const vtr::Rect& bb); void set_node_capacity(const RRNodeId& node, const short& capacity); @@ -663,30 +746,34 @@ class RRGraph { /* A generic function to set the ptc_num for a node */ void set_node_ptc_num(const RRNodeId& node, const short& ptc); - /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the pin id in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the + * pin id in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_pin_num(const RRNodeId& node, const short& pin_id); - /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is the track id in a routing channel, - * Routing channel is a group of routing tracks, each of which has a unique index - * An example - * Routing Channel - * +------------------+ - * | | - * ---|----------------->|----> track_id: 0 - * | | - * ... More tracks ... - * | | - * ---|----------------->|----> track_id: 1 - * | | - * +------------------+ - */ + /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is + * the track id in a routing channel, + * Routing channel is a group of routing tracks, each of which has a unique + * index + * An example + * Routing Channel + * +------------------+ + * | | + * ---|----------------->|----> track_id: 0 + * | | + * ... More tracks ... + * | | + * ---|----------------->|----> track_id: 1 + * | | + * +------------------+ + */ void set_node_track_num(const RRNodeId& node, const short& track_id); - /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is the class number in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is + * the class number in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_class_num(const RRNodeId& node, const short& class_id); /* Set the routing cost index for node, see node_cost_index() for details */ @@ -703,38 +790,47 @@ class RRGraph { void set_node_R(const RRNodeId& node, const float& R); void set_node_C(const RRNodeId& node, const float& C); - /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ + /* Set the routing segment linked to a node, only applicable to CHANX and + * CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in one vector, - * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) - */ + /* Edge partitioning is performed for efficiency, + * so we can store configurable and non-configurable edge lists for a node in + * one vector, + * and efficiently iterate over all edges, or only the configurable or + * non-configurable subsets. + * This function will re-organize the incoming and outgoing edges of each + * node, + * i.e., node_in_edges() and node_out_edges(): + * 1. configurable edges (1st part of the vectors) + * 2. non-configurable edges (2nd part of the vectors) + */ void partition_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. - * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set - */ + * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if + * it was set + */ void compress(); /* top-level function to free, should be called when to delete a RRGraph */ void clear(); private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_node_in_edges(const RRNodeId& node); - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_node_out_edges(const RRNodeId& node); - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_in_edges(); - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_out_edges(); private: /* Internal free functions */ @@ -780,8 +876,10 @@ class RRGraph { bool validate_node_edges(const RRNodeId& node) const; /* Edge-level checking */ - bool validate_node_is_edge_src(const RRNodeId& node, const RREdgeId& edge) const; - bool validate_node_is_edge_sink(const RRNodeId& node, const RREdgeId& edge) const; + bool validate_node_is_edge_src(const RRNodeId& node, + const RREdgeId& edge) const; + bool validate_node_is_edge_sink(const RRNodeId& node, + const RREdgeId& edge) const; bool validate_edge_switch(const RREdgeId& edge) const; bool validate_edge_src_node(const RREdgeId& edge) const; bool validate_edge_sink_node(const RREdgeId& edge) const; @@ -803,10 +901,11 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector node_ids_; /* Unique identifiers for the nodes */ + vtr::vector + node_ids_; /* Unique identifiers for the nodes */ vtr::vector node_types_; - vtr::vector> node_bounding_boxes_; + vtr::vector > node_bounding_boxes_; vtr::vector node_capacities_; vtr::vector node_ptc_nums_; @@ -815,13 +914,15 @@ class RRGraph { vtr::vector node_sides_; vtr::vector node_Rs_; vtr::vector node_Cs_; - vtr::vector node_segments_; /* Segment ids for each node */ - /* Record the dividing point between configurable and non-configurable edges for each node */ + vtr::vector node_segments_; /* Segment ids for each + node */ + /* Record the dividing point between configurable and non-configurable edges + * for each node */ vtr::vector node_num_non_configurable_in_edges_; vtr::vector node_num_non_configurable_out_edges_; - vtr::vector> node_in_edges_; - vtr::vector> node_out_edges_; + vtr::vector > node_in_edges_; + vtr::vector > node_out_edges_; /* Edge related data */ vtr::vector edge_ids_; /* unique identifiers for edges */ @@ -830,29 +931,40 @@ class RRGraph { vtr::vector edge_switches_; /* Switch related data - * Note that so far there has been no need to remove - * switches, so no such facility exists - */ + * Note that so far there has been no need to remove + * switches, so no such facility exists + */ /* Unique identifiers for switches which are used in the RRGraph */ vtr::vector switch_ids_; /* Detailed information about the switches, which are used in the RRGraph */ vtr::vector switches_; - /* Segment relatex data - * Segment info should be corrected annotated for each rr_node - * whose type is CHANX and CHANY - */ - vtr::vector segment_ids_; /* unique identifiers for routing segments which are used in the RRGraph */ - vtr::vector segments_; /* detailed information about the segments, which are used in the RRGraph */ + /* Segment relatex data + * Segment info should be corrected annotated for each rr_node + * whose type is CHANX and CHANY + */ + vtr::vector + segment_ids_; /* unique identifiers for routing + segments which are used in the + RRGraph */ + vtr::vector segments_; /* detailed information + about the segments, + which are used in the + RRGraph */ /* Misc. */ - /* A flag to indicate if the graph contains invalid elements (nodes/edges etc.) */ + /* A flag to indicate if the graph contains invalid elements (nodes/edges + * etc.) */ bool dirty_ = false; - /* Fast look-up to search a node by its type, coordinator and ptc_num - * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] - */ - typedef std::vector>>>> NodeLookup; + /* Fast look-up to search a node by its type, coordinator and ptc_num + * Indexing of fast look-up: + * [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] + */ + typedef std::vector > > > > + NodeLookup; mutable NodeLookup node_lookup_; }; From b814fbf02889dfab6e194025822feadd17fb6796 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 23:46:11 -0700 Subject: [PATCH 07/58] fix broken code format --- vpr/src/device/rr_graph_obj.h | 938 +++++++++++++++------------------- 1 file changed, 413 insertions(+), 525 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 57f7130636a..f5611ce9b61 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -1,28 +1,25 @@ /************************************************************************ - * This file introduces a class to model a Routing Resource Graph (RRGraph or - *RRG) + * This file introduces a class to model a Routing Resource Graph (RRGraph or RRG) * which is widely used by placers, routers, analyzers etc. * * Overview * ======== * RRGraph aims to describe in a general way how routing resources are connected * in a FPGA fabric. - * It includes device-level information for routing resources, - * such as the physical location of nodes, - * routing segment information of each routing resource + * It includes device-level information for routing resources, + * such as the physical location of nodes, + * routing segment information of each routing resource * switch information of each routing resource. - * - * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many - *cycles), + * + * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many cycles), * which consists of a number of nodes and edges. * * Node * ---- - * Each node represents a routing resource, which could be - * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) - * 2. an input or an output of a logic block (IPIN or OPIN) - * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending - *points of routing trees. + * Each node represents a routing resource, which could be + * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) + * 2. an input or an output of a logic block (IPIN or OPIN) + * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending points of routing trees. * * Edge * ---- @@ -37,47 +34,42 @@ * * The switch information are categorized in the rr_switch_inf of RRGraph class. * rr_switch_inf is created to minimize memory footprint of RRGraph classs - * While the RRG could contain millions (even much larger) of edges, there are - *only + * While the RRG could contain millions (even much larger) of edges, there are only * a limited number of types of switches. - * Hence, we use a flyweight pattern to store switch-related information that - *differs + * Hence, we use a flyweight pattern to store switch-related information that differs * only for types of switches (switch type, drive strength, R, C, etc.). - * Each edge stores the ids of the switch that implements it so this additional - *information + * Each edge stores the ids of the switch that implements it so this additional information * can be easily looked up. * - * Note: All the switch-related information, such as R, C, should be placed in - *rr_switch_inf - * but NOT directly in the edge-related data of RRGraph. - * If you wish to create a new data structure to represent switches between - *routing resources, + * Note: All the switch-related information, such as R, C, should be placed in rr_switch_inf + * but NOT directly in the edge-related data of RRGraph. + * If you wish to create a new data structure to represent switches between routing resources, * please follow the flyweight pattern by linking your switch ids to edges only! * - * Guidlines on using the RRGraph data structure + * Guidlines on using the RRGraph data structure * ============================================= * * For those want to access data from RRGraph * ------------------------------------------ * Some examples for most frequent data query: - * + * * // Strongly suggest to use a read-only rr_graph object * const RRGraph& rr_graph; * * // Access type of a node with a given node id - * // Get the unique node id that you may get - * // from other data structures or functions - * RRNodeId node_id; + * // Get the unique node id that you may get + * // from other data structures or functions + * RRNodeId node_id; * t_rr_type node_type = rr_graph.node_type(node_id); * - * // Access all the fan-out edges from a given node + * // Access all the fan-out edges from a given node * for (const RREdgeId& out_edge_id : rr_graph.node_out_edges(node_id)) { * // Do something with out_edge * } * // If you only want to learn the number of fan-out edges * size_t num_out_edges = rr_graph.node_fan_out(node_id); * - * // Access all the switches connected to a given node + * // Access all the switches connected to a given node * for (const RREdgeId& in_edge_id : rr_graph.node_in_edges(node_id)) { * RRSwitchId edge_switch_id = rr_graph.edge_switch(in_edge_id); * // Do something with the switch @@ -92,75 +84,56 @@ * We suggest developers to create builders in separated C/C++ source files * outside the rr_graph header and source files * - * After build/modify a RRGraph, please do run a fundamental check, a public - *accessor. - * to ensure that your RRGraph does not include invalid - *nodes/edges/switches/segements + * After build/modify a RRGraph, please do run a fundamental check, a public accessor. + * to ensure that your RRGraph does not include invalid nodes/edges/switches/segements * as well as connections. - * The validate() function gurantees the consistency between internal data - *structures, + * The validate() function gurantees the consistency between internal data structures, * such as the id cross-reference between nodes and edges etc., * so failing it indicates a fatal bug! - * This is a must-do check! + * This is a must-do check! * - * Example: + * Example: * RRGraph rr_graph; * ... // Building RRGraph - * rr_graph.validate(); + * rr_graph.validate(); * - * Optionally, we strongly recommend developers to run an advance check in - *check_rr_graph() + * Optionally, we strongly recommend developers to run an advance check in check_rr_graph() * This guarantees legal and routable RRGraph for VPR routers. * - * This checks for connectivity or other information in the RRGraph that is - *unexpected - * or unusual in an FPGA, and likely indicates a problem in your graph - *generation. - * However, if you are intentionally creating an RRGraph with this unusual, - * buts still technically legal, behaviour, you can write your own - *check_rr_graph() with weaker assumptions. + * This checks for connectivity or other information in the RRGraph that is unexpected + * or unusual in an FPGA, and likely indicates a problem in your graph generation. + * However, if you are intentionally creating an RRGraph with this unusual, + * buts still technically legal, behaviour, you can write your own check_rr_graph() with weaker assumptions. * - * Note: Do NOT modify the coordinate system for nodes, they are designed for - *downstream drawers and routers + * Note: Do NOT modify the coordinate system for nodes, they are designed for downstream drawers and routers * * For those want to extend RRGraph data structure * -------------------------------------------------------------------------- * Please avoid modifying any existing public/private accessors/mutators * in order to keep a stable RRGraph object in the framework - * Developers may add more internal data to RRGraph as well as associate - *accessors/mutators - * Please update and comment on the added features properly to keep this data - *structure friendly to be extended. + * Developers may add more internal data to RRGraph as well as associate accessors/mutators + * Please update and comment on the added features properly to keep this data structure friendly to be extended. * - * Try to keep your extension within only graph-related internal data to - *RRGraph. - * In other words, extension is necessary when the new node/edge attributes are - *needed. - * RRGraph should NOT include other data which are shared by other data - *structures outside. + * Try to keep your extension within only graph-related internal data to RRGraph. + * In other words, extension is necessary when the new node/edge attributes are needed. + * RRGraph should NOT include other data which are shared by other data structures outside. * The rr-graph is the single largest data structure in VPR, - * so avoid adding unnecessary information per node or per edge to it, as it - *will impact memory footprint. - * Instead, using indices to point to the outside data source instead of - *embedding to RRGraph - * For example: - * For any placement/routing cost related information, try to extend - *t_rr_indexed_data, but not RRGraph - * For any placement/routing results, try to extend PlaceContext and - *RoutingContext, but not RRGraph - * + * so avoid adding unnecessary information per node or per edge to it, as it will impact memory footprint. + * Instead, using indices to point to the outside data source instead of embedding to RRGraph + * For example: + * For any placement/routing cost related information, try to extend t_rr_indexed_data, but not RRGraph + * For any placement/routing results, try to extend PlaceContext and RoutingContext, but not RRGraph + * * For those want to develop placers or routers * -------------------------------------------------------------------------- * The RRGraph is designed to be a read-only database/graph, once created. * Placement and routing should NOT change any attributes of RRGraph. - * Any placement and routing results should be stored in other data structures, - *such as PlaceContext and RoutingContext. + * Any placement and routing results should be stored in other data structures, such as PlaceContext and RoutingContext. * - * Tracing Cross-Reference + * Tracing Cross-Reference * ======================= * RRGraph is designed to a self-contained data structure as much as possible. - * It includes the switch information (rr_switch) and segment_information - *(rr_segment) + * It includes the switch information (rr_switch) and segment_information (rr_segment) * which are necessary to build-up any external data structures. * * Internal cross-reference @@ -190,14 +163,13 @@ * The only cross-reference to outside data structures is the cost_index * corresponding to the data structure t_rr_index_data * Details can be found in the definition of t_rr_index_data - * This allows rapid look up by the router of additional information it needs - *for this node, using a flyweight pattern. + * This allows rapid look up by the router of additional information it needs for this node, using a flyweight pattern. * * +---------+ cost_index +------------------------------+ - * | RRGraph |-------------->| cost_index_data[cost_index] | + * | RRGraph |-------------->| cost_index_data[cost_index] | * +---------+ +------------------------------+ * - * Note: if you wish to use a customized routing-cost data structure, + * Note: if you wish to use a customized routing-cost data structure, * please use the flyweigth pattern as we do for t_rr_index_data! * * Access to a node/edge/switch/segment, please use the StrongId created @@ -208,19 +180,18 @@ * For segment, use RRSegmentId * * These are the unique identifier for each data type. - * To check if your id is valid or not, use the INVALID() function of - *StrongId class. + * To check if your id is valid or not, use the INVALID() function of StrongId class. * Example: * if (node_id == RRNodeId::INVALID()) { - * } + * } * ***********************************************************************/ #ifndef RR_GRAPH_OBJ_H #define RR_GRAPH_OBJ_H /* - * Notes in include header files in a head file - * Only include the neccessary header files + * Notes in include header files in a head file + * Only include the neccessary header files * that is required by the data types in the function/class declarations! */ /* Header files should be included in a sequence */ @@ -240,13 +211,11 @@ class RRGraph { public: /* Types */ - /* Iterators used to create iterator-based loop for - * nodes/edges/switches/segments */ + /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; - typedef vtr::vector::const_iterator - segment_iterator; + typedef vtr::vector::const_iterator segment_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; @@ -256,234 +225,213 @@ class RRGraph { public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments - * To iterate over the nodes/edges/switches/segments in a RRGraph, - * using a range-based loop is suggested. - * ----------------------------------------------------------------- - * Example: iterate over all the nodes - * // Strongly suggest to use a read-only rr_graph object - * const RRGraph& rr_graph; - * for (const RRNodeId& node : rr_graph.nodes()) { - * // Do something with each node - * } - * - * for (const RREdgeId& edge : rr_graph.edges()) { - * // Do something with each edge - * } - * - * for (const RRSwitchId& switch : rr_graph.switches()) { - * // Do something with each switch - * } - * - * for (const RRSegmentId& segment : rr_graph.segments()) { - * // Do something with each segment - * } - */ + * To iterate over the nodes/edges/switches/segments in a RRGraph, + * using a range-based loop is suggested. + * ----------------------------------------------------------------- + * Example: iterate over all the nodes + * // Strongly suggest to use a read-only rr_graph object + * const RRGraph& rr_graph; + * for (const RRNodeId& node : rr_graph.nodes()) { + * // Do something with each node + * } + * + * for (const RREdgeId& edge : rr_graph.edges()) { + * // Do something with each edge + * } + * + * for (const RRSwitchId& switch : rr_graph.switches()) { + * // Do something with each switch + * } + * + * for (const RRSegmentId& segment : rr_graph.segments()) { + * // Do something with each segment + * } + */ node_range nodes() const; edge_range edges() const; switch_range switches() const; segment_range segments() const; /* Node-level attributes */ - size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this - accessor as outside - functions should use - RRNodeId */ - - /* get the type of a RRGraph node : types of each node, can be channel wires - * (CHANX or CHANY) or - * logic block pins(OPIN or IPIN) or virtual - * nodes (SOURCE or SINK) - * see t_rr_type definition for more details - */ + size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this accessor as outside functions should use RRNodeId */ + + /* get the type of a RRGraph node : types of each node, can be channel wires (CHANX or CHANY) or + * logic block pins(OPIN or IPIN) or virtual nodes (SOURCE or SINK) + * see t_rr_type definition for more details + */ t_rr_type node_type(const RRNodeId& node) const; /* Get coordinate of a node. (xlow, xhigh, ylow, yhigh): - * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh - * This is still the case when a logic block has a height > 1 - * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent - * where the routing segment starts and ends. - * Note that our convention alway keeps - * xlow <= xhigh and ylow <= yhigh - * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in - *INC_DIRECTION - * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION - * - * Note: there is only a single drive point for each routing segment (track) - * in the context of uni-directional wires - * - * Example : - * CHANX in INC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * ----------------------------> - * - * CHANX in DEC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * <---------------------------- - * - * CHANY in INC_DIRECTION - * - * /|\ <-------(xhigh, yhigh) - * | - * | <-------(xlow, ylow) - * - * CHANY in DEC_DIRECTION - * - * | <-------(xhigh, yhigh) - * | - * \|/ <-------(xlow, ylow) - */ + * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh + * This is still the case when a logic block has a height > 1 + * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent + * where the routing segment starts and ends. + * Note that our convention alway keeps + * xlow <= xhigh and ylow <= yhigh + * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in INC_DIRECTION + * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION + * + * Note: there is only a single drive point for each routing segment (track) + * in the context of uni-directional wires + * + * Example : + * CHANX in INC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * ----------------------------> + * + * CHANX in DEC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * <---------------------------- + * + * CHANY in INC_DIRECTION + * + * /|\ <-------(xhigh, yhigh) + * | + * | <-------(xlow, ylow) + * + * CHANY in DEC_DIRECTION + * + * | <-------(xhigh, yhigh) + * | + * \|/ <-------(xlow, ylow) + */ short node_xlow(const RRNodeId& node) const; short node_ylow(const RRNodeId& node) const; short node_xhigh(const RRNodeId& node) const; short node_yhigh(const RRNodeId& node) const; - /* Get the length of a routing track. - * Note that it is ONLY meaningful for CHANX and CHANY, which represents the - * number of logic blocks that a routing track spans - * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be - * always 0 - */ + /* Get the length of a routing track. + * Note that it is ONLY meaningful for CHANX and CHANY, which represents the number of logic blocks that a routing track spans + * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be always 0 + */ short node_length(const RRNodeId& node) const; /* A short-cut function to get coordinates of a node, - * where xmin of vtr::Rect = xlow, - * ymin of vtr::Rect = ylow, - * xmax of vtr::Rect = xhigh, - * ymax of vtr::Rect = yhigh. - */ + * where xmin of vtr::Rect = xlow, + * ymin of vtr::Rect = ylow, + * xmax of vtr::Rect = xhigh, + * ymax of vtr::Rect = yhigh. + */ vtr::Rect node_bounding_box(const RRNodeId& node) const; - /* Get node starting and ending points in routing channels. - * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and - *node_yhigh() - * For routing tracks in INC_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * For routing tracks in DEC_DIRECTION: - * node_start_coordinate() returns (xhigh, yhigh) as the starting point - * node_end_coordinate() returns (xlow, ylow) as the ending point - * - * For routing tracks in BI_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * Applicable to routing track nodes only!!! - * This function will requires the types of node to be either CHANX or CHANY - */ + /* Get node starting and ending points in routing channels. + * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and node_yhigh() + * For routing tracks in INC_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * For routing tracks in DEC_DIRECTION: + * node_start_coordinate() returns (xhigh, yhigh) as the starting point + * node_end_coordinate() returns (xlow, ylow) as the ending point + * + * For routing tracks in BI_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * Applicable to routing track nodes only!!! + * This function will requires the types of node to be either CHANX or CHANY + */ vtr::Point node_start_coordinate(const RRNodeId& node) const; vtr::Point node_end_coordinate(const RRNodeId& node) const; - /* Get the capacity of a node. - * Literally, how many nets can be mapped to the node. - * Typically, each node has a capacity of 1 but special nodes (SOURCE and - * SINK) will have a - * large number due to logic equivalent pins - * See Vaughn Betz's book for more details - */ + /* Get the capacity of a node. + * Literally, how many nets can be mapped to the node. + * Typically, each node has a capacity of 1 but special nodes (SOURCE and SINK) will have a + * large number due to logic equivalent pins + * See Vaughn Betz's book for more details + */ short node_capacity(const RRNodeId& node) const; /* Get the number of edges that drives a given node - * Note that each edge is typically driven by a node - * (true in VPR RRG that is currently supported, may not be true in customized - *RRG) - * This can also represent the number of drive nodes - * An example where fan-in of a node C is 2 - * - * edge A - * node A -------->+ - * | - * |-->node C - * edgeB | - * node B -------->+ - * - */ + * Note that each edge is typically driven by a node + * (true in VPR RRG that is currently supported, may not be true in customized RRG) + * This can also represent the number of drive nodes + * An example where fan-in of a node C is 2 + * + * edge A + * node A -------->+ + * | + * |-->node C + * edgeB | + * node B -------->+ + * + */ short node_fan_in(const RRNodeId& node) const; /* Get the number of edges that are driven a given node - * Note that each edge typically drives by a node - * (true in VPR RRG that is currently supported, may not be true in customized - *RRG) - * This can also represent the number of fan-out nodes - * An example where fan-out of a node A is 2 - * - * edge A - * node A -+--------> node B - * | - * | - * | edgeB - * +--------> node C - * - */ + * Note that each edge typically drives by a node + * (true in VPR RRG that is currently supported, may not be true in customized RRG) + * This can also represent the number of fan-out nodes + * An example where fan-out of a node A is 2 + * + * edge A + * node A -+--------> node B + * | + * | + * | edgeB + * +--------> node C + * + */ short node_fan_out(const RRNodeId& node) const; /* Get the ptc_num of a node - * The ptc (pin, track, or class) number is an integer - * that allows you to differentiate between wires, pins or sources/sinks with - *overlapping x,y coordinates or extent. - * This is useful for drawing rr-graphs nicely. - * For example, all the CHANX rr_nodes that have the same y coordinate and - *x-coordinates - * that overlap will have different ptc numbers, by convention starting at 0. - * This allows them to be drawn without overlapping, as the ptc num can be - *used as a track identifier. - * The main routing code does not care about ptc num. - * - * The ptc_num carries different meanings for different node types - * (true in VPR RRG that is currently supported, may not be true in customized - *RRG) - * CHANX or CHANY: the track id in routing channels - * OPIN or IPIN: the index of pins in the logic block data structure - * SOURCE and SINK: the class id of a pin (indicating logic equivalence of - *pins) in the logic block data structure - * - * To ease the access to ptc_num for different types of nodes: - * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes - * node_track_num() is designed for routing tracks, which are CHANX and CHANY - *nodes - * node_class_num() is designed for routing source and sinks, which are SOURCE - *and SINK nodes - * - * Due to a useful identifier, ptc_num is used in building fast look-up - */ + * The ptc (pin, track, or class) number is an integer + * that allows you to differentiate between wires, pins or sources/sinks with overlapping x,y coordinates or extent. + * This is useful for drawing rr-graphs nicely. + * For example, all the CHANX rr_nodes that have the same y coordinate and x-coordinates + * that overlap will have different ptc numbers, by convention starting at 0. + * This allows them to be drawn without overlapping, as the ptc num can be used as a track identifier. + * The main routing code does not care about ptc num. + * + * The ptc_num carries different meanings for different node types + * (true in VPR RRG that is currently supported, may not be true in customized RRG) + * CHANX or CHANY: the track id in routing channels + * OPIN or IPIN: the index of pins in the logic block data structure + * SOURCE and SINK: the class id of a pin (indicating logic equivalence of pins) in the logic block data structure + * + * To ease the access to ptc_num for different types of nodes: + * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes + * node_track_num() is designed for routing tracks, which are CHANX and CHANY nodes + * node_class_num() is designed for routing source and sinks, which are SOURCE and SINK nodes + * + * Due to a useful identifier, ptc_num is used in building fast look-up + */ short node_ptc_num(const RRNodeId& node) const; short node_pin_num(const RRNodeId& node) const; short node_track_num(const RRNodeId& node) const; short node_class_num(const RRNodeId& node) const; /* Get the index of cost data in the list of cost_indexed_data data structure - * It contains the routing cost for different nodes in the RRGraph - * when used in evaluate different routing paths - * See cross-reference section in this header file for more details - */ + * It contains the routing cost for different nodes in the RRGraph + * when used in evaluate different routing paths + * See cross-reference section in this header file for more details + */ short node_cost_index(const RRNodeId& node) const; /* Get the directionality of a node - * see node coordinate for details - * only matters the routing track nodes (CHANX and CHANY) - */ + * see node coordinate for details + * only matters the routing track nodes (CHANX and CHANY) + */ e_direction node_direction(const RRNodeId& node) const; - /* Get the side where the node physically locates on a logic block. - * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of - *logic block - * The side should be consistent to definition in architecture - *XML - * - * TOP - * +-----------+ - * | | - * LEFT | Logic | RIGHT - * | Block | - * | | - * +-----------+ - * BOTTOM - * - */ + /* Get the side where the node physically locates on a logic block. + * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of logic block + * The side should be consistent to definition in architecture XML + * + * TOP + * +-----------+ + * | | + * LEFT | Logic | RIGHT + * | Block | + * | | + * +-----------+ + * BOTTOM + * + */ e_side node_side(const RRNodeId& node) const; /* Get resistance of a node, used to built RC tree for timing analysis */ @@ -493,9 +441,8 @@ class RRGraph { float node_C(const RRNodeId& node) const; /* Get segment id of a node, containing the information of the routing - * segment that the node represents. See more details in the data structure - * t_segment_inf - */ + * segment that the node represents. See more details in the data structure t_segment_inf + */ RRSegmentId node_segment(const RRNodeId& node) const; /* Get the number of non-configurable incoming edges to a node */ @@ -522,120 +469,99 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; - /* Edge-related attributes - * An example to explain the terminology used in RRGraph - * edgeA - * nodeA --------> nodeB - * | edgeB - * +-------> nodeC - * - * +----------+----------------+----------------+ - * | Edge Id | edge_src_node | edge_sink_node | - * +----------+----------------+----------------+ - * | edgeA | nodeA | nodeB | - * +----------+----------------+----------------+ - * | edgeB | nodeA | nodeC | - * +----------+----------------+----------------+ - * - */ - size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this - accessor as outside - functions should use - RREdgeId */ + /* Edge-related attributes + * An example to explain the terminology used in RRGraph + * edgeA + * nodeA --------> nodeB + * | edgeB + * +-------> nodeC + * + * +----------+----------------+----------------+ + * | Edge Id | edge_src_node | edge_sink_node | + * +----------+----------------+----------------+ + * | edgeA | nodeA | nodeB | + * +----------+----------------+----------------+ + * | edgeB | nodeA | nodeC | + * +----------+----------------+----------------+ + * + */ + size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this accessor as outside functions should use RREdgeId */ /* Get the source node which drives a edge */ RRNodeId edge_src_node(const RREdgeId& edge) const; /* Get the sink node which a edge ends to */ RRNodeId edge_sink_node(const RREdgeId& edge) const; /* Get the switch id which a edge represents - * using switch id, timing and other information can be found - * for any node-to-node connection - */ + * using switch id, timing and other information can be found + * for any node-to-node connection + */ RRSwitchId edge_switch(const RREdgeId& edge) const; - /* Judge if a edge is configurable or not. - * A configurable edge is controlled by a programmable memory bit - * while a non-configurable edge is typically a hard-wired connection - */ + /* Judge if a edge is configurable or not. + * A configurable edge is controlled by a programmable memory bit + * while a non-configurable edge is typically a hard-wired connection + */ bool edge_is_configurable(const RREdgeId& edge) const; bool edge_is_non_configurable(const RREdgeId& edge) const; /* Switch Info */ - size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate - this accessor as - outside functions - should use - RRSwitchId */ + size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate this accessor as outside functions should use RRSwitchId */ /* Get the switch info of a switch used in this RRGraph */ const t_rr_switch_inf& get_switch(const RRSwitchId& switch_id) const; /* Segment Info */ - size_t segment_index(const RRSegmentId& segment_id) - const; /* TODO: deprecate this accessor as outside functions should use - RRSegmentId */ + size_t segment_index(const RRSegmentId& segment_id) const; /* TODO: deprecate this accessor as outside functions should use RRSegmentId */ /* Get the segment info of a routing segment used in this RRGraph */ const t_segment_inf& get_segment(const RRSegmentId& segment_id) const; /* Utilities */ /* Find the edges connecting two nodes */ - std::vector find_edges(const RRNodeId& src_node, - const RRNodeId& sink_node) const; + std::vector find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const; /* Find a node with given features from internal fast look-up */ - RRNodeId find_node(const short& x, - const short& y, - const t_rr_type& type, - const int& ptc, - const e_side& side = NUM_SIDES) const; - /* Find the number of routing tracks in a routing channel with a given - * coordinate */ - short chan_num_tracks(const short& x, - const short& y, - const t_rr_type& type) const; - - /* This flag is raised when the RRgraph contains invalid nodes/edges etc. - * Invalid nodes/edges exist when users remove nodes/edges from RRGraph - * RRGraph object will not immediately remove the nodes and edges but - * will mark them with invalid ids. - * Afterwards the is_dirty flag is raised as an indicator, to tell users - * that a clean-up process (invoked by compress() function)is required. - * After executing compress(), the is_dirty will be reset to false - * - * Example: - * RRGraph rr_graph; - * RRNodeId node_id; // Node id to be removed - * rr_graph.remove_node(node_id); - * // RRGraph is now dirty (rr_graph.is_dirty() == true) - * ... - * // During this period, when you perform data query, - * // You may encounter invalid nodes and edges - * // It may happen that - * // 1. their ids are invalid - * // 2. the cross-reference between nodes and edge, i.e., - * // node_in_edges(), node_out_edges() - * // 3. invalid node returned from find_node(), which use fast look-up - * ... - * rr_graph.compress(); - * // RRGraph is now clean (rr_graph.is_dirty() == false) - */ + RRNodeId find_node(const short& x, const short& y, const t_rr_type& type, const int& ptc, const e_side& side = NUM_SIDES) const; + /* Find the number of routing tracks in a routing channel with a given coordinate */ + short chan_num_tracks(const short& x, const short& y, const t_rr_type& type) const; + + /* This flag is raised when the RRgraph contains invalid nodes/edges etc. + * Invalid nodes/edges exist when users remove nodes/edges from RRGraph + * RRGraph object will not immediately remove the nodes and edges but + * will mark them with invalid ids. + * Afterwards the is_dirty flag is raised as an indicator, to tell users + * that a clean-up process (invoked by compress() function)is required. + * After executing compress(), the is_dirty will be reset to false + * + * Example: + * RRGraph rr_graph; + * RRNodeId node_id; // Node id to be removed + * rr_graph.remove_node(node_id); + * // RRGraph is now dirty (rr_graph.is_dirty() == true) + * ... + * // During this period, when you perform data query, + * // You may encounter invalid nodes and edges + * // It may happen that + * // 1. their ids are invalid + * // 2. the cross-reference between nodes and edge, i.e., + * // node_in_edges(), node_out_edges() + * // 3. invalid node returned from find_node(), which use fast look-up + * ... + * rr_graph.compress(); + * // RRGraph is now clean (rr_graph.is_dirty() == false) + */ bool is_dirty() const; - public: /* Echos */ - void print_node(const RRNodeId& node) - const; /* Print the detailed information of a node */ + public: /* Echos */ + void print_node(const RRNodeId& node) const; /* Print the detailed information of a node */ public: /* Public Validators */ - /* Check data structure for internal consistency - * This function will - * 1. re-build fast look-up for nodes - * 2. check all the edges and nodes are connected - * Literally, no invalid ids in fan-in/fan-out of edges/nodes - * 3. check that all the nodes representing routing tracks have valid id - *linked to its segment-related data structure - * 4. check that all the edges have valid id linked to its switch-related data - *structure - * - * Any valid and non-dirty RRGraph should pass this check - * It is highly recommended to run this function after building any RRGraph - *object - */ + /* Check data structure for internal consistency + * This function will + * 1. re-build fast look-up for nodes + * 2. check all the edges and nodes are connected + * Literally, no invalid ids in fan-in/fan-out of edges/nodes + * 3. check that all the nodes representing routing tracks have valid id linked to its segment-related data structure + * 4. check that all the edges have valid id linked to its switch-related data structure + * + * Any valid and non-dirty RRGraph should pass this check + * It is highly recommended to run this function after building any RRGraph object + */ bool validate() const; /* Validate is the node id does exist in the RRGraph */ @@ -645,87 +571,78 @@ class RRGraph { bool valid_edge_id(const RREdgeId& edge) const; public: /* Mutators */ - /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * For example: - * RRGraph rr_graph; - * // Add 1000 CHANX nodes to the RRGraph object - * rr_graph.reserve_nodes(1000); - * for (size_t i = 0; i < 1000; ++i) { - * rr_graph.create_node(CHANX); - * } - */ + /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * For example: + * RRGraph rr_graph; + * // Add 1000 CHANX nodes to the RRGraph object + * rr_graph.reserve_nodes(1000); + * for (size_t i = 0; i < 1000; ++i) { + * rr_graph.create_node(CHANX); + * } + */ void reserve_nodes(const unsigned long& num_nodes); - /* We use long data type for edges because the number of edges is very large - */ void reserve_edges(const unsigned long& num_edges); void reserve_switches(const size_t& num_switches); void reserve_segments(const size_t& num_segments); - /* Reserve the lists of input/output edges for a RR node to be memory - *efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * - * For example: - * RRGraph rr_graph; - * // Add 1 source node to the RRGraph object - * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the output edges for the source node - * rr_graph.reserve_node_out_edges(src_node, 5); - * // Add your edges - */ + /* Reserve the lists of input/output edges for a RR node to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * + * For example: + * RRGraph rr_graph; + * // Add 1 source node to the RRGraph object + * RRNodeId src_node = rr_graph.create_node(SOURCE); + * // Reserve the output edges for the source node + * rr_graph.reserve_node_out_edges(src_node, 5); + * // Add your edges + */ void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); - void reserve_node_out_edges(const RRNodeId& node, - const size_t& num_out_edges); + void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); /* Add new elements (node, edge, switch, etc.) to RRGraph */ - /* Add a node to the RRGraph with a deposited type - * Detailed node-level information should be added using the set_node_* - * functions - * For example: - * RRNodeId node = create_node(); - * set_node_xlow(node, 0); - */ + /* Add a node to the RRGraph with a deposited type + * Detailed node-level information should be added using the set_node_* functions + * For example: + * RRNodeId node = create_node(); + * set_node_xlow(node, 0); + */ RRNodeId create_node(const t_rr_type& type); - /* Add a edge to the RRGraph, by providing the source and sink node - * This function will automatically create a node and - * configure the nodes and edges in connection - */ - RREdgeId create_edge(const RRNodeId& source, - const RRNodeId& sink, - const RRSwitchId& switch_id); + /* Add a edge to the RRGraph, by providing the source and sink node + * This function will automatically create a node and + * configure the nodes and edges in connection + */ + RREdgeId create_edge(const RRNodeId& source, const RRNodeId& sink, const RRSwitchId& switch_id); RRSwitchId create_switch(const t_rr_switch_inf& switch_info); RRSegmentId create_segment(const t_segment_inf& segment_info); /* Remove elements from RRGraph - * This function just turn the nodes and edges to an invalid id without - * deletion - * This will cause the RRGraph to be marked as dirty (is_dirty(): false => - * true) - * To thoroughly remove the edges and nodes as well as clear the dirty flag, - * use compress() after the remove functions - * Example: - * RRGraph rr_graph; - * rr_graph.remove_node() - * .. // remove more nodes - * rr_graph.remove_edge() - * .. // remove more nodes - * // rr_graph.is_dirty() == true - * // If you want to access any node or edge - * // Check codes for ids should be intensively used - * // Such as, - * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { - * // if (RREdgeId::INVALID() != in_edge) { - * // ... - * // } - * // } - * rr_graph.compress() - * // rr_graph.is_dirty() == false - */ + * This function just turn the nodes and edges to an invalid id without deletion + * This will cause the RRGraph to be marked as dirty (is_dirty(): false => true) + * To thoroughly remove the edges and nodes as well as clear the dirty flag, + * use compress() after the remove functions + * Example: + * RRGraph rr_graph; + * rr_graph.remove_node() + * .. // remove more nodes + * rr_graph.remove_edge() + * .. // remove more nodes + * // rr_graph.is_dirty() == true + * // If you want to access any node or edge + * // Check codes for ids should be intensively used + * // Such as, + * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { + * // if (RREdgeId::INVALID() != in_edge) { + * // ... + * // } + * // } + * rr_graph.compress() + * // rr_graph.is_dirty() == false + */ void remove_node(const RRNodeId& node); void remove_edge(const RREdgeId& edge); @@ -736,9 +653,9 @@ class RRGraph { void set_node_yhigh(const RRNodeId& node, const short& yhigh); /* This is a short-cut function, set xlow/xhigh/ylow/yhigh for a node - * Please respect the following to configure the bb object: - * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; - */ + * Please respect the following to configure the bb object: + * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; + */ void set_node_bounding_box(const RRNodeId& node, const vtr::Rect& bb); void set_node_capacity(const RRNodeId& node, const short& capacity); @@ -746,34 +663,30 @@ class RRGraph { /* A generic function to set the ptc_num for a node */ void set_node_ptc_num(const RRNodeId& node, const short& ptc); - /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the - * pin id in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the pin id in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_pin_num(const RRNodeId& node, const short& pin_id); - /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is - * the track id in a routing channel, - * Routing channel is a group of routing tracks, each of which has a unique - * index - * An example - * Routing Channel - * +------------------+ - * | | - * ---|----------------->|----> track_id: 0 - * | | - * ... More tracks ... - * | | - * ---|----------------->|----> track_id: 1 - * | | - * +------------------+ - */ + /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is the track id in a routing channel, + * Routing channel is a group of routing tracks, each of which has a unique index + * An example + * Routing Channel + * +------------------+ + * | | + * ---|----------------->|----> track_id: 0 + * | | + * ... More tracks ... + * | | + * ---|----------------->|----> track_id: 1 + * | | + * +------------------+ + */ void set_node_track_num(const RRNodeId& node, const short& track_id); - /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is - * the class number in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is the class number in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_class_num(const RRNodeId& node, const short& class_id); /* Set the routing cost index for node, see node_cost_index() for details */ @@ -790,47 +703,38 @@ class RRGraph { void set_node_R(const RRNodeId& node, const float& R); void set_node_C(const RRNodeId& node, const float& C); - /* Set the routing segment linked to a node, only applicable to CHANX and - * CHANY */ + /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in - * one vector, - * and efficiently iterate over all edges, or only the configurable or - * non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each - * node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) - */ + /* Edge partitioning is performed for efficiency, + * so we can store configurable and non-configurable edge lists for a node in one vector, + * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. + * This function will re-organize the incoming and outgoing edges of each node, + * i.e., node_in_edges() and node_out_edges(): + * 1. configurable edges (1st part of the vectors) + * 2. non-configurable edges (2nd part of the vectors) + */ void partition_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. - * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if - * it was set - */ + * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set + */ void compress(); /* top-level function to free, should be called when to delete a RRGraph */ void clear(); private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_node_in_edges(const RRNodeId& node); - /* classify the output edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_node_out_edges(const RRNodeId& node); - /* classify the input edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_in_edges(); - /* classify the output edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_out_edges(); private: /* Internal free functions */ @@ -876,10 +780,8 @@ class RRGraph { bool validate_node_edges(const RRNodeId& node) const; /* Edge-level checking */ - bool validate_node_is_edge_src(const RRNodeId& node, - const RREdgeId& edge) const; - bool validate_node_is_edge_sink(const RRNodeId& node, - const RREdgeId& edge) const; + bool validate_node_is_edge_src(const RRNodeId& node, const RREdgeId& edge) const; + bool validate_node_is_edge_sink(const RRNodeId& node, const RREdgeId& edge) const; bool validate_edge_switch(const RREdgeId& edge) const; bool validate_edge_src_node(const RREdgeId& edge) const; bool validate_edge_sink_node(const RREdgeId& edge) const; @@ -901,11 +803,10 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector - node_ids_; /* Unique identifiers for the nodes */ + vtr::vector node_ids_; /* Unique identifiers for the nodes */ vtr::vector node_types_; - vtr::vector > node_bounding_boxes_; + vtr::vector> node_bounding_boxes_; vtr::vector node_capacities_; vtr::vector node_ptc_nums_; @@ -914,15 +815,13 @@ class RRGraph { vtr::vector node_sides_; vtr::vector node_Rs_; vtr::vector node_Cs_; - vtr::vector node_segments_; /* Segment ids for each - node */ - /* Record the dividing point between configurable and non-configurable edges - * for each node */ + vtr::vector node_segments_; /* Segment ids for each node */ + /* Record the dividing point between configurable and non-configurable edges for each node */ vtr::vector node_num_non_configurable_in_edges_; vtr::vector node_num_non_configurable_out_edges_; - vtr::vector > node_in_edges_; - vtr::vector > node_out_edges_; + vtr::vector> node_in_edges_; + vtr::vector> node_out_edges_; /* Edge related data */ vtr::vector edge_ids_; /* unique identifiers for edges */ @@ -931,40 +830,29 @@ class RRGraph { vtr::vector edge_switches_; /* Switch related data - * Note that so far there has been no need to remove - * switches, so no such facility exists - */ + * Note that so far there has been no need to remove + * switches, so no such facility exists + */ /* Unique identifiers for switches which are used in the RRGraph */ vtr::vector switch_ids_; /* Detailed information about the switches, which are used in the RRGraph */ vtr::vector switches_; - /* Segment relatex data - * Segment info should be corrected annotated for each rr_node - * whose type is CHANX and CHANY - */ - vtr::vector - segment_ids_; /* unique identifiers for routing - segments which are used in the - RRGraph */ - vtr::vector segments_; /* detailed information - about the segments, - which are used in the - RRGraph */ + /* Segment relatex data + * Segment info should be corrected annotated for each rr_node + * whose type is CHANX and CHANY + */ + vtr::vector segment_ids_; /* unique identifiers for routing segments which are used in the RRGraph */ + vtr::vector segments_; /* detailed information about the segments, which are used in the RRGraph */ /* Misc. */ - /* A flag to indicate if the graph contains invalid elements (nodes/edges - * etc.) */ + /* A flag to indicate if the graph contains invalid elements (nodes/edges etc.) */ bool dirty_ = false; - /* Fast look-up to search a node by its type, coordinator and ptc_num - * Indexing of fast look-up: - * [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] - */ - typedef std::vector > > > > - NodeLookup; + /* Fast look-up to search a node by its type, coordinator and ptc_num + * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] + */ + typedef std::vector>>>> NodeLookup; mutable NodeLookup node_lookup_; }; From 1f5f178c45cb6e10431e95a8890e1f2df2116780 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 00:05:03 -0700 Subject: [PATCH 08/58] further remove the large vector used temporarily when loading RRGraph --- vpr/src/device/create_rr_graph.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 99ccd5aab8c..3a2996adea8 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -56,7 +56,6 @@ void convert_rr_graph(std::vector& vpr_segments) { device_ctx.rr_graph.reserve_nodes((unsigned long)device_ctx.rr_nodes.size()); // Create the nodes - std::vector old_to_new_rr_node(device_ctx.rr_nodes.size(), RRNodeId::INVALID()); for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { auto& node = device_ctx.rr_nodes[inode]; RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); @@ -85,9 +84,6 @@ void convert_rr_graph(std::vector& vpr_segments) { short irc_data = node.cost_index(); short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); - - VTR_ASSERT(inode < old_to_new_rr_node.size()); - old_to_new_rr_node[inode] = rr_node; } /* Reserve list of edges to be memory efficient */ @@ -104,8 +100,8 @@ void convert_rr_graph(std::vector& vpr_segments) { /* Reserve input and output edges for the node: * this is very important to avoid memory fragments!!! */ - device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.fan_in()); - device_ctx.rr_graph.reserve_node_out_edges(old_to_new_rr_node[inode], node.num_edges()); + device_ctx.rr_graph.reserve_node_in_edges(RRNodeId(inode), node.fan_in()); + device_ctx.rr_graph.reserve_node_out_edges(RRNodeId(inode), node.num_edges()); } /* Add edges for each node */ @@ -115,11 +111,8 @@ void convert_rr_graph(std::vector& vpr_segments) { size_t isink_node = node.edge_sink_node(iedge); int iswitch = node.edge_switch(iedge); - VTR_ASSERT(inode < old_to_new_rr_node.size()); - VTR_ASSERT(isink_node < old_to_new_rr_node.size()); - - device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], - old_to_new_rr_node[isink_node], + device_ctx.rr_graph.create_edge(RRNodeId(inode), + RRNodeId(isink_node), RRSwitchId(iswitch)); } } From 7b3a490943e2a24f76bcf3a17484192db8cc7382 Mon Sep 17 00:00:00 2001 From: kmurray Date: Thu, 21 Nov 2019 17:55:52 -0500 Subject: [PATCH 09/58] vpr: Remove unused INTRA_CLUSTER_EDGE RR node type --- vpr/src/base/vpr_types.h | 9 ++------- vpr/src/power/power.cpp | 3 --- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index bc2dfee7ba2..f3acaea19cd 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1133,10 +1133,6 @@ struct t_linked_f_pointer { typedef std::vector>>>> t_rr_node_indices; //[0..num_rr_types-1][0..grid_width-1][0..grid_height-1][0..NUM_SIDES-1][0..max_ptc-1] -/* Uncomment lines below to save some memory, at the cost of debugging ease. */ -/*enum e_rr_type {SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}; */ -/* typedef short t_rr_type */ - /* Type of a routing resource node. x-directed channel segment, * * y-directed channel segment, input pin to a clb to pad, output * * from a clb or pad (i.e. output pin of a net) and: * @@ -1151,12 +1147,11 @@ typedef enum e_rr_type : unsigned char { OPIN, CHANX, CHANY, - INTRA_CLUSTER_EDGE, NUM_RR_TYPES } t_rr_type; -constexpr std::array RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE}}; -constexpr std::array rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE"}}; +constexpr std::array RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}}; +constexpr std::array rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}}; /* Basic element used to store the traceback (routing) of each net. * * index: Array index (ID) of this routing resource node. * diff --git a/vpr/src/power/power.cpp b/vpr/src/power/power.cpp index 1fcd06f5209..94294cf55c2 100644 --- a/vpr/src/power/power.cpp +++ b/vpr/src/power/power.cpp @@ -1009,9 +1009,6 @@ static void power_usage_routing(t_power_usage* power_usage, power_ctx.commonly_used->total_cb_buffer_size += buffer_size; } break; - case INTRA_CLUSTER_EDGE: - VTR_ASSERT(0); - break; default: power_log_msg(POWER_LOG_WARNING, "The global routing-resource graph contains an unknown node type."); From 4f9f90c6c4005bd9d280b69322afd27289fec87a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 17:08:24 -0700 Subject: [PATCH 10/58] change num_non_config in/out edges to short integer, for sake of memory footprint --- vpr/src/device/rr_graph_obj.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f5611ce9b61..957d701b945 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -817,8 +817,8 @@ class RRGraph { vtr::vector node_Cs_; vtr::vector node_segments_; /* Segment ids for each node */ /* Record the dividing point between configurable and non-configurable edges for each node */ - vtr::vector node_num_non_configurable_in_edges_; - vtr::vector node_num_non_configurable_out_edges_; + vtr::vector node_num_non_configurable_in_edges_; + vtr::vector node_num_non_configurable_out_edges_; vtr::vector> node_in_edges_; vtr::vector> node_out_edges_; From 7be1bdf47cb46d51ff95636afc42488cb60cb3ba Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 17:29:50 -0700 Subject: [PATCH 11/58] use NdMatrix in fast node lookup in RRGraph object --- vpr/src/device/rr_graph_obj.cpp | 31 ++++++++++++++----------------- vpr/src/device/rr_graph_obj.h | 3 ++- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 2a93c588ad8..f610f166682 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -393,21 +393,21 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ /* Check if x, y, type and ptc, side is valid */ if ((x < 0) /* See if x is smaller than the index of first element */ - || (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */ + || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ if ((y < 0) /* See if y is smaller than the index of first element */ - || (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */ + || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ /* itype is always larger than -1, we can skip checking */ - if (itype > node_lookup_[x][y].size() - 1) { /* See if type is large than the index of last element */ + if (itype > node_lookup_.dim_size(2) - 1) { /* See if type is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } @@ -438,20 +438,20 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& /* Check if x, y, type and ptc is valid */ if ((x < 0) /* See if x is smaller than the index of first element */ - || (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */ + || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ if ((y < 0) /* See if y is smaller than the index of first element */ - || (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */ + || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ - if ((size_t(type) > node_lookup_[x][y].size() - 1)) { /* See if type is large than the index of last element */ + if ((size_t(type) > node_lookup_.dim_size(2) - 1)) { /* See if type is large than the index of last element */ /* Return a zero range! */ return 0; } @@ -1136,21 +1136,18 @@ void RRGraph::build_fast_node_lookup() const { /* Free the current fast node look-up, we will rebuild a new one here */ invalidate_fast_node_lookup(); + /* Get the max (x,y) and then we can resize the ndmatrix */ + vtr::Point max_coord(0, 0); for (auto node : nodes()) { - size_t x = node_xlow(node); - if (x >= node_lookup_.size()) { - node_lookup_.resize(x + 1); - } + max_coord.set_x(std::max(max_coord.x(), node_xlow(node))); + max_coord.set_y(std::max(max_coord.y(), node_ylow(node))); + } + node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); + for (auto node : nodes()) { + size_t x = node_xlow(node); size_t y = node_ylow(node); - if (y >= node_lookup_[x].size()) { - node_lookup_[x].resize(y + 1); - } - size_t itype = node_type(node); - if (itype >= node_lookup_[x][y].size()) { - node_lookup_[x][y].resize(itype + 1); - } size_t ptc = node_ptc_num(node); if (ptc >= node_lookup_[x][y][itype].size()) { diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 957d701b945..0591675e135 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -200,6 +200,7 @@ #include /* EXTERNAL library header files go second*/ +#include "vtr_ndmatrix.h" #include "vtr_vector.h" #include "vtr_range.h" #include "vtr_geometry.h" @@ -852,7 +853,7 @@ class RRGraph { /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] */ - typedef std::vector>>>> NodeLookup; + typedef vtr::NdMatrix>,3> NodeLookup; mutable NodeLookup node_lookup_; }; From 58ad5b062988add9209ca2ff42416d5acd8fc98a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 18:49:41 -0700 Subject: [PATCH 12/58] replace full vector of edge ids which simple edge range --- vpr/src/device/rr_graph_obj.cpp | 83 +++++++++++++++++++++++---------- vpr/src/device/rr_graph_obj.h | 9 +++- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index f610f166682..2747be84f97 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -15,13 +15,35 @@ #include "rr_graph_obj.h" #include "rr_graph_obj_utils.h" +/******************************************************************** + * Constructors + *******************************************************************/ +RRGraph::RRGraph() { + /* Set edge range to be zero ! */ + edge_id_range_ = 0; +} + //Accessors RRGraph::node_range RRGraph::nodes() const { return vtr::make_range(node_ids_.begin(), node_ids_.end()); } -RRGraph::edge_range RRGraph::edges() const { - return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); +std::vector RRGraph::edges() const { + /* Create a list of valid edge ids */ + std::vector edge_ids; + /* Reserve the edge list, since it could be very last. Also exclude the invalid edge ids */ + edge_ids.reserve(edge_id_range_ - invalid_edge_ids_.size()); + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + edge_ids.push_back(RREdgeId(id)); + } + return edge_ids; } RRGraph::switch_range RRGraph::switches() const { @@ -789,7 +811,6 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve a list of edges */ void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ - this->edge_ids_.reserve(num_edges); this->edge_src_nodes_.reserve(num_edges); this->edge_sink_nodes_.reserve(num_edges); this->edge_switches_.reserve(num_edges); @@ -861,17 +882,17 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons VTR_ASSERT(valid_node_id(sink)); VTR_ASSERT(valid_switch_id(switch_id)); - //Allocate an ID - RREdgeId edge_id = RREdgeId(edge_ids_.size()); - - //Initialize the attributes - edge_ids_.push_back(edge_id); + /* Allocate an ID */ + RREdgeId edge_id = RREdgeId(edge_id_range_); + /* Expand range of edge ids */ + edge_id_range_++; + /* Initialize the attributes */ edge_src_nodes_.push_back(source); edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - //Add the edge to the nodes + /* Add the edge to the nodes */ node_out_edges_[source].push_back(edge_id); node_in_edges_[sink].push_back(edge_id); @@ -933,8 +954,9 @@ void RRGraph::remove_edge(const RREdgeId& edge) { RRNodeId src_node = edge_src_node(edge); RRNodeId sink_node = edge_sink_node(edge); - //Invalidate node to edge references - // TODO: consider making this optional (e.g. if called from remove_node) + /* Invalidate node to edge references + * TODO: consider making this optional (e.g. if called from remove_node) + */ for (size_t i = 0; i < node_out_edges_[src_node].size(); ++i) { if (node_out_edges_[src_node][i] == edge) { node_out_edges_[src_node][i] = RREdgeId::INVALID(); @@ -948,8 +970,8 @@ void RRGraph::remove_edge(const RREdgeId& edge) { } } - //Mark edge invalid - edge_ids_[edge] = RREdgeId::INVALID(); + /* Mark edge invalid */ + invalid_edge_ids_[edge] = true; set_dirty(); } @@ -1189,7 +1211,8 @@ bool RRGraph::valid_node_id(const RRNodeId& node) const { } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { - return size_t(edge) < edge_ids_.size() && edge_ids_[edge] == edge; + return (size_t(edge) < edge_id_range_) + && (invalid_edge_ids_.end() == invalid_edge_ids_.find(edge)); } /* check if a given switch id is valid or not */ @@ -1235,9 +1258,9 @@ bool RRGraph::validate_node_sizes() const { } bool RRGraph::validate_edge_sizes() const { - return edge_src_nodes_.size() == edge_ids_.size() - && edge_sink_nodes_.size() == edge_ids_.size() - && edge_switches_.size() == edge_ids_.size(); + return edge_src_nodes_.size() == edge_id_range_ + && edge_sink_nodes_.size() == edge_id_range_ + && edge_switches_.size() == edge_id_range_; } bool RRGraph::validate_switch_sizes() const { @@ -1250,7 +1273,7 @@ bool RRGraph::validate_segment_sizes() const { void RRGraph::compress() { vtr::vector node_id_map(node_ids_.size()); - vtr::vector edge_id_map(edge_ids_.size()); + vtr::vector edge_id_map(edge_id_range_); build_id_maps(node_id_map, edge_id_map); @@ -1267,7 +1290,22 @@ void RRGraph::compress() { void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { node_id_map = compress_ids(node_ids_); - edge_id_map = compress_ids(edge_ids_); + + /* Build edge ids including invalid ids and compress */ + vtr::vector edge_ids; + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Give and invalid id */ + edge_ids.push_back(RREdgeId::INVALID()); + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + edge_ids.push_back(RREdgeId(id)); + } + edge_id_map = compress_ids(edge_ids); + } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { @@ -1292,16 +1330,13 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { - edge_ids_ = clean_and_reorder_ids(edge_id_map); + edge_id_range_ = edge_id_map.size(); edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map); edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map); edge_switches_ = clean_and_reorder_values(edge_switches_, edge_id_map); VTR_ASSERT(validate_edge_sizes()); - - VTR_ASSERT_MSG(are_contiguous(edge_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(edge_ids_), "All Ids should be valid"); } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { @@ -1342,7 +1377,7 @@ void RRGraph::clear_nodes() { /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { - edge_ids_.clear(); + edge_id_range_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 0591675e135..1b088ffb8f0 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -198,6 +198,7 @@ /* Standard header files required go first */ #include #include +#include /* EXTERNAL library header files go second*/ #include "vtr_ndmatrix.h" @@ -224,6 +225,9 @@ class RRGraph { typedef vtr::Range switch_range; typedef vtr::Range segment_range; + public: /* Constructors */ + RRGraph(); + public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments * To iterate over the nodes/edges/switches/segments in a RRGraph, @@ -249,7 +253,7 @@ class RRGraph { * } */ node_range nodes() const; - edge_range edges() const; + std::vector edges() const; switch_range switches() const; segment_range segments() const; @@ -825,7 +829,8 @@ class RRGraph { vtr::vector> node_out_edges_; /* Edge related data */ - vtr::vector edge_ids_; /* unique identifiers for edges */ + size_t edge_id_range_; /* Range of edge ids */ + std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_switches_; From d2ebba754791c96b930b3624663164143278f7af Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 20:33:06 -0700 Subject: [PATCH 13/58] replace node id vector with constant and minor bug fixing --- vpr/src/device/rr_graph_obj.cpp | 109 +++++++++++++++++++++----------- vpr/src/device/rr_graph_obj.h | 10 +-- 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 2747be84f97..b2dea1b0bf6 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -19,13 +19,31 @@ * Constructors *******************************************************************/ RRGraph::RRGraph() { + /* Set node range to be zero ! */ + node_id_range_ = 0; /* Set edge range to be zero ! */ edge_id_range_ = 0; } -//Accessors -RRGraph::node_range RRGraph::nodes() const { - return vtr::make_range(node_ids_.begin(), node_ids_.end()); +/******************************************************************** + * Accessors + *******************************************************************/ +std::vector RRGraph::nodes() const { + /* Create a list of valid node ids */ + std::vector node_ids; + /* Reserve the edge list, since it could be very last. Also exclude the invalid node ids */ + node_ids.reserve(node_id_range_ - invalid_node_ids_.size()); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + node_ids.push_back(RRNodeId(id)); + } + return node_ids; } std::vector RRGraph::edges() const { @@ -41,7 +59,7 @@ std::vector RRGraph::edges() const { continue; } /* Reach here, this is a valid id, push to the edge list */ - edge_ids.push_back(RREdgeId(id)); + edge_ids.push_back(RREdgeId(id)); } return edge_ids; } @@ -414,14 +432,14 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ size_t iside = side; /* Check if x, y, type and ptc, side is valid */ - if ((x < 0) /* See if x is smaller than the index of first element */ + if ((x < 0) /* See if x is smaller than the index of first element */ || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ - if ((y < 0) /* See if y is smaller than the index of first element */ + if ((y < 0) /* See if y is smaller than the index of first element */ || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); @@ -790,11 +808,11 @@ void RRGraph::clear_dirty() { void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ - this->node_ids_.reserve(num_nodes); this->node_types_.reserve(num_nodes); this->node_bounding_boxes_.reserve(num_nodes); this->node_capacities_.reserve(num_nodes); this->node_ptc_nums_.reserve(num_nodes); + this->node_cost_indices_.reserve(num_nodes); this->node_directions_.reserve(num_nodes); this->node_sides_.reserve(num_nodes); this->node_Rs_.reserve(num_nodes); @@ -846,11 +864,12 @@ void RRGraph::reserve_node_out_edges(const RRNodeId& node, const size_t& num_out /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { - //Allocate an ID - RRNodeId node_id = RRNodeId(node_ids_.size()); + /* Allocate an ID */ + RRNodeId node_id = RRNodeId(node_id_range_); + /* Expand range of node ids */ + node_id_range_++; - //Initialize the attributes - node_ids_.push_back(node_id); + /* Initialize the attributes */ node_types_.push_back(type); node_bounding_boxes_.emplace_back(-1, -1, -1, -1); @@ -938,7 +957,7 @@ void RRGraph::remove_node(const RRNodeId& node) { } //Mark node invalid - node_ids_[node] = RRNodeId::INVALID(); + invalid_node_ids_[node] = true; //Invalidate the node look-up invalidate_fast_node_lookup(); @@ -1207,7 +1226,8 @@ void RRGraph::initialize_fast_node_lookup() const { } bool RRGraph::valid_node_id(const RRNodeId& node) const { - return size_t(node) < node_ids_.size() && node_ids_[node] == node; + return (size_t(node) < node_id_range_) + && (invalid_node_ids_.end() == invalid_node_ids_.find(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { @@ -1241,20 +1261,20 @@ bool RRGraph::validate_sizes() const { } bool RRGraph::validate_node_sizes() const { - return node_types_.size() == node_ids_.size() - && node_bounding_boxes_.size() == node_ids_.size() - && node_capacities_.size() == node_ids_.size() - && node_ptc_nums_.size() == node_ids_.size() - && node_cost_indices_.size() == node_ids_.size() - && node_directions_.size() == node_ids_.size() - && node_sides_.size() == node_ids_.size() - && node_Rs_.size() == node_ids_.size() - && node_Cs_.size() == node_ids_.size() - && node_segments_.size() == node_ids_.size() - && node_num_non_configurable_in_edges_.size() == node_ids_.size() - && node_num_non_configurable_out_edges_.size() == node_ids_.size() - && node_in_edges_.size() == node_ids_.size() - && node_out_edges_.size() == node_ids_.size(); + return node_types_.size() == node_id_range_ + && node_bounding_boxes_.size() == node_id_range_ + && node_capacities_.size() == node_id_range_ + && node_ptc_nums_.size() == node_id_range_ + && node_cost_indices_.size() == node_id_range_ + && node_directions_.size() == node_id_range_ + && node_sides_.size() == node_id_range_ + && node_Rs_.size() == node_id_range_ + && node_Cs_.size() == node_id_range_ + && node_segments_.size() == node_id_range_ + && node_num_non_configurable_in_edges_.size() == node_id_range_ + && node_num_non_configurable_out_edges_.size() == node_id_range_ + && node_in_edges_.size() == node_id_range_ + && node_out_edges_.size() == node_id_range_; } bool RRGraph::validate_edge_sizes() const { @@ -1272,7 +1292,7 @@ bool RRGraph::validate_segment_sizes() const { } void RRGraph::compress() { - vtr::vector node_id_map(node_ids_.size()); + vtr::vector node_id_map(node_id_range_); vtr::vector edge_id_map(edge_id_range_); build_id_maps(node_id_map, edge_id_map); @@ -1284,12 +1304,31 @@ void RRGraph::compress() { invalidate_fast_node_lookup(); + /* Clear invalid node list */ + invalid_node_ids_.clear(); + + /* Clear invalid edge list */ + invalid_edge_ids_.clear(); + clear_dirty(); } void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { - node_id_map = compress_ids(node_ids_); + /* Build node ids including invalid ids and compress */ + vtr::vector node_ids; + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Give and invalid id */ + node_ids.push_back(RRNodeId::INVALID()); + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + node_ids.push_back(RRNodeId(id)); + } + node_id_map = compress_ids(node_ids); /* Build edge ids including invalid ids and compress */ vtr::vector edge_ids; @@ -1298,18 +1337,18 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); /* Give and invalid id */ - edge_ids.push_back(RREdgeId::INVALID()); + edge_ids.push_back(RREdgeId::INVALID()); continue; } /* Reach here, this is a valid id, push to the edge list */ - edge_ids.push_back(RREdgeId(id)); + edge_ids.push_back(RREdgeId(id)); } edge_id_map = compress_ids(edge_ids); } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { - node_ids_ = clean_and_reorder_ids(node_id_map); + node_id_range_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); @@ -1324,9 +1363,6 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map); VTR_ASSERT(validate_node_sizes()); - - VTR_ASSERT_MSG(are_contiguous(node_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(node_ids_), "All Ids should be valid"); } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { @@ -1351,8 +1387,7 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m /* Empty all the vectors related to nodes */ void RRGraph::clear_nodes() { - node_ids_.clear(); - + node_id_range_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 1b088ffb8f0..c5c1108c35e 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -252,7 +252,7 @@ class RRGraph { * // Do something with each segment * } */ - node_range nodes() const; + std::vector nodes() const; std::vector edges() const; switch_range switches() const; segment_range segments() const; @@ -808,7 +808,9 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector node_ids_; /* Unique identifiers for the nodes */ + size_t node_id_range_; /* Range of node ids */ + std::unordered_map invalid_node_ids_; /* Invalid edge ids */ + vtr::vector node_types_; vtr::vector> node_bounding_boxes_; @@ -829,7 +831,7 @@ class RRGraph { vtr::vector> node_out_edges_; /* Edge related data */ - size_t edge_id_range_; /* Range of edge ids */ + size_t edge_id_range_; /* Range of edge ids */ std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; @@ -858,7 +860,7 @@ class RRGraph { /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] */ - typedef vtr::NdMatrix>,3> NodeLookup; + typedef vtr::NdMatrix>, 3> NodeLookup; mutable NodeLookup node_lookup_; }; From b7b78e061d947dde03085635013735a47af03dd8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 20:46:49 -0700 Subject: [PATCH 14/58] further remove using nodes() and edges() inside RRGraph methods to save memory footprint --- vpr/src/device/rr_graph_obj.cpp | 122 +++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index b2dea1b0bf6..df12f3144e4 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -477,14 +477,14 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& initialize_fast_node_lookup(); /* Check if x, y, type and ptc is valid */ - if ((x < 0) /* See if x is smaller than the index of first element */ + if ((x < 0) /* See if x is smaller than the index of first element */ || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ - if ((y < 0) /* See if y is smaller than the index of first element */ + if ((y < 0) /* See if y is smaller than the index of first element */ || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return 0; @@ -529,15 +529,21 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const { /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_segment(node)) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_node_segment(RRNodeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Node %d has an invalid segment id (%d)!\n", - size_t(node), size_t(node_segment(node))); + id, size_t(node_segment(RRNodeId(id)))); } return all_valid; } @@ -551,15 +557,21 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_switch(edge)) { + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_edge_switch(RREdgeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Edge %d has an invalid switch id (%d)!\n", - size_t(edge), size_t(edge_switch(edge))); + id, size_t(edge_switch(RREdgeId(id)))); } return all_valid; } @@ -663,8 +675,14 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const { /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_in_edges(node)) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_node_in_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! @@ -678,8 +696,14 @@ bool RRGraph::validate_nodes_in_edges() const { /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_out_edges(node)) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_node_out_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! @@ -717,15 +741,21 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_src_node(edge)) { + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_edge_src_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid source node %d!\n", - size_t(edge), size_t(edge_src_node(edge))); + id, size_t(edge_src_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -734,15 +764,21 @@ bool RRGraph::validate_edge_src_nodes() const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_sink_node(edge)) { + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_edge_sink_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid sink node %d!\n", - size_t(edge), size_t(edge_sink_node(edge))); + id, size_t(edge_sink_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -1147,8 +1183,14 @@ void RRGraph::partition_node_out_edges(const RRNodeId& node) { */ void RRGraph::partition_in_edges() { /* For each node */ - for (auto node : nodes()) { - this->partition_node_in_edges(node); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + this->partition_node_in_edges(RRNodeId(id)); } } @@ -1157,8 +1199,14 @@ void RRGraph::partition_in_edges() { */ void RRGraph::partition_out_edges() { /* For each node */ - for (auto node : nodes()) { - this->partition_node_out_edges(node); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + this->partition_node_out_edges(RRNodeId(id)); } } @@ -1179,13 +1227,26 @@ void RRGraph::build_fast_node_lookup() const { /* Get the max (x,y) and then we can resize the ndmatrix */ vtr::Point max_coord(0, 0); - for (auto node : nodes()) { - max_coord.set_x(std::max(max_coord.x(), node_xlow(node))); - max_coord.set_y(std::max(max_coord.y(), node_ylow(node))); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + max_coord.set_x(std::max(max_coord.x(), node_xlow(RRNodeId(id)))); + max_coord.set_y(std::max(max_coord.y(), node_ylow(RRNodeId(id)))); } node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); - for (auto node : nodes()) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + RRNodeId node = RRNodeId(id); size_t x = node_xlow(node); size_t y = node_ylow(node); size_t itype = node_type(node); @@ -1376,7 +1437,14 @@ void RRGraph::clean_edges(const vtr::vector& edge_id_map) { } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { - for (const auto& node : nodes()) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + RRNodeId node = RRNodeId(id); node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map); node_out_edges_[node] = update_valid_refs(node_out_edges_[node], edge_id_map); From 922b4bf01f35c47711e9bd362c1cd3e4dc921e2f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 21:19:35 -0700 Subject: [PATCH 15/58] move convert rr_graph to be close to build_rr_graph --- vpr/src/device/create_rr_graph.cpp | 2 +- vpr/src/device/rr_graph_obj.cpp | 1 - vpr/src/route/rr_graph.cpp | 9 ++++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 3a2996adea8..53baf9771a0 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -23,7 +23,7 @@ *routers ********************************************************************/ void convert_rr_graph(std::vector& vpr_segments) { - vtr::ScopedStartFinishTimer timer("Build routing resource graph object"); + vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); /* IMPORTANT: to build clock tree, * vpr added segments to the original arch segments diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index df12f3144e4..9e05494dcde 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -1405,7 +1405,6 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, edge_ids.push_back(RREdgeId(id)); } edge_id_map = compress_ids(edge_ids); - } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 733ac6e41a4..ca3bb370bc4 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -332,6 +332,9 @@ void create_rr_graph(const t_graph_type graph_type, base_cost_type, &det_routing_arch->wire_to_rr_ipin_switch, det_routing_arch->read_rr_graph_filename.c_str()); + + /* Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); } } else { if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) { @@ -370,15 +373,15 @@ void create_rr_graph(const t_graph_type graph_type, det_routing_arch->wire_to_rr_ipin_switch, base_cost_type); } + + /* Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); } process_non_config_sets(); print_rr_graph_stats(); - /* Create rr_graph object: load rr_nodes to the object */ - convert_rr_graph(segment_inf); - //Write out rr graph file if needed if (!det_routing_arch->write_rr_graph_filename.empty()) { write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf); From 169cde1dbb382a61a9c02151805cc576c0d81cf4 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 21:32:54 -0700 Subject: [PATCH 16/58] move clear RRGraph object to free_rr_graph() --- vpr/src/device/create_rr_graph.cpp | 3 --- vpr/src/route/rr_graph.cpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 53baf9771a0..20f79efd6c2 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -31,9 +31,6 @@ void convert_rr_graph(std::vector& vpr_segments) { */ auto& device_ctx = g_vpr_ctx.mutable_device(); - /* make sure we have a clean empty rr_graph */ - device_ctx.rr_graph.clear(); - /* The number of switches are in general small, * reserve switches may not bring significant memory efficiency * So, we just use create_switch to push_back each time diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index ca3bb370bc4..12b3a101401 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -1379,6 +1379,9 @@ void free_rr_graph() { * allocated, as ALL the chunk allocated data is already free! */ auto& device_ctx = g_vpr_ctx.mutable_device(); + /* Clear the RRGraph object */ + device_ctx.rr_graph.clear(); + device_ctx.read_rr_graph_filename.clear(); device_ctx.rr_node_indices.clear(); From 46abc1d12257df8682a5cc0ae82c9d6ad7ed45eb Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 22 Nov 2019 11:17:10 -0700 Subject: [PATCH 17/58] now node_in/out_edges are arranged in the same vector with delimeters to identify groups --- vpr/src/device/create_rr_graph.cpp | 3 +- vpr/src/device/rr_graph_obj.cpp | 139 +++++++++++++++-------------- vpr/src/device/rr_graph_obj.h | 23 +++-- 3 files changed, 88 insertions(+), 77 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 20f79efd6c2..a81ece928e7 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -97,8 +97,7 @@ void convert_rr_graph(std::vector& vpr_segments) { /* Reserve input and output edges for the node: * this is very important to avoid memory fragments!!! */ - device_ctx.rr_graph.reserve_node_in_edges(RRNodeId(inode), node.fan_in()); - device_ctx.rr_graph.reserve_node_out_edges(RRNodeId(inode), node.num_edges()); + device_ctx.rr_graph.reserve_node_inout_edges(RRNodeId(inode), node.fan_in() + node.num_edges()); } /* Add edges for each node */ diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 9e05494dcde..3f7cfb16555 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -158,11 +158,11 @@ vtr::Point RRGraph::node_end_coordinate(const RRNodeId& node) const { } short RRGraph::node_fan_in(const RRNodeId& node) const { - return node_in_edges(node).size(); + return node_num_in_edges_[node]; } short RRGraph::node_fan_out(const RRNodeId& node) const { - return node_out_edges(node).size(); + return node_inout_edges_[node].size() - node_num_in_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { @@ -232,42 +232,36 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { /* * Get the number of configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough */ short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { - return node_configurable_in_edges(node).size(); + return node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; } /* * Get the number of configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough */ short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_configurable_out_edges(node).size(); + return node_inout_edges_[node].size() - node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; } /* * Get the number of non-configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() + * Use the node_num_configurable_in_edges() * when the rr_graph edges have been partitioned * This can avoid unneccessary walkthrough */ short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const { - return node_non_configurable_in_edges(node).size(); + return node_num_non_configurable_in_edges_[node]; } /* * Get the number of non-configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() + * Use the node_num_configurable_out_edges() * when the rr_graph edges have been partitioned * This can avoid unneccessary walkthrough */ short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { - return node_non_configurable_out_edges(node).size(); + return node_num_non_configurable_out_edges_[node]; } /* Get the list of configurable edges from the input edges of a given node @@ -277,16 +271,16 @@ RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) co /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).begin(); + /* By default the configurable edges will be stored at the first part of the inputedge list (0 to XX) */ + auto begin = node_inout_edges_[node].begin(); - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; + /* By default the non-configurable edges will be stored at second part of the input edge list (XX to end) */ + auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; return vtr::make_range(begin, end); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of non configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const { @@ -294,15 +288,15 @@ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node VTR_ASSERT_SAFE(valid_node_id(node)); /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; + auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end(); + auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node]; return vtr::make_range(begin, end); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const { @@ -310,15 +304,15 @@ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) c VTR_ASSERT_SAFE(valid_node_id(node)); /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).begin(); + auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node]; /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; + auto end = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; return vtr::make_range(begin, end); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of non configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const { @@ -326,22 +320,22 @@ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& nod VTR_ASSERT_SAFE(valid_node_id(node)); /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; + auto begin = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end(); + auto end = node_inout_edges_[node].end(); return vtr::make_range(begin, end); } RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_out_edges_[node].begin(), node_out_edges_[node].end()); + return vtr::make_range(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end()); } RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_in_edges_[node].begin(), node_in_edges_[node].end()); + return vtr::make_range(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node]); } //Edge attributes @@ -845,7 +839,9 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ this->node_types_.reserve(num_nodes); + this->node_bounding_boxes_.reserve(num_nodes); + this->node_capacities_.reserve(num_nodes); this->node_ptc_nums_.reserve(num_nodes); this->node_cost_indices_.reserve(num_nodes); @@ -854,12 +850,13 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { this->node_Rs_.reserve(num_nodes); this->node_Cs_.reserve(num_nodes); this->node_segments_.reserve(num_nodes); + this->node_num_non_configurable_in_edges_.reserve(num_nodes); this->node_num_non_configurable_out_edges_.reserve(num_nodes); /* Edge-relate vectors */ - this->node_in_edges_.reserve(num_nodes); - this->node_out_edges_.reserve(num_nodes); + this->node_num_in_edges_.reserve(num_nodes); + this->node_inout_edges_.reserve(num_nodes); } /* Reserve a list of edges */ @@ -883,19 +880,11 @@ void RRGraph::reserve_segments(const size_t& num_segments) { } /* Reserve the input edges for a node */ -void RRGraph::reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges) { +void RRGraph::reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges) { /* Validate the node id */ VTR_ASSERT_SAFE(true == valid_node_id(node)); /* Reserve the input edge list */ - this->node_in_edges_[node].reserve(num_in_edges); -} - -/* Reserve the input edges for a node */ -void RRGraph::reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges) { - /* Validate the node id */ - VTR_ASSERT_SAFE(true == valid_node_id(node)); - /* Reserve the input edge list */ - this->node_out_edges_[node].reserve(num_out_edges); + this->node_inout_edges_[node].reserve(num_inout_edges); } /* Mutators */ @@ -919,12 +908,12 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_Cs_.push_back(0.); node_segments_.push_back(RRSegmentId::INVALID()); - node_in_edges_.emplace_back(); //Initially empty - node_out_edges_.emplace_back(); //Initially empty - node_num_non_configurable_in_edges_.emplace_back(); //Initially empty node_num_non_configurable_out_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(); //Initially empty + node_inout_edges_.emplace_back(); //Initially empty + invalidate_fast_node_lookup(); VTR_ASSERT(validate_sizes()); @@ -947,9 +936,17 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - /* Add the edge to the nodes */ - node_out_edges_[source].push_back(edge_id); - node_in_edges_[sink].push_back(edge_id); + /* Add the edge to the nodes: + * We use delimeter to split incoming and outgoing edges + * for a node into two groups + * When adding the new edge, + * we will add the edge id to the tail of node_inout_edge list of source node + * we will insert the edge id to the delimeter of node_inout_edge list of sink node + * the delimeter node_num_in_edges_ will be updated for the sink node! + */ + node_inout_edges_[source].push_back(edge_id); + node_inout_edges_[sink].insert(node_inout_edges_[sink].begin() + (size_t)node_num_in_edges_[sink], edge_id); + node_num_in_edges_[sink]++; VTR_ASSERT(validate_sizes()); @@ -1012,15 +1009,15 @@ void RRGraph::remove_edge(const RREdgeId& edge) { /* Invalidate node to edge references * TODO: consider making this optional (e.g. if called from remove_node) */ - for (size_t i = 0; i < node_out_edges_[src_node].size(); ++i) { - if (node_out_edges_[src_node][i] == edge) { - node_out_edges_[src_node][i] = RREdgeId::INVALID(); + for (size_t i = 0; i < node_inout_edges_[src_node].size(); ++i) { + if (node_inout_edges_[src_node][i] == edge) { + node_inout_edges_[src_node][i] = RREdgeId::INVALID(); break; } } - for (size_t i = 0; i < node_in_edges_[sink_node].size(); ++i) { - if (node_in_edges_[sink_node][i] == edge) { - node_in_edges_[sink_node][i] = RREdgeId::INVALID(); + for (size_t i = 0; i < node_inout_edges_[sink_node].size(); ++i) { + if (node_inout_edges_[sink_node][i] == edge) { + node_inout_edges_[sink_node][i] = RREdgeId::INVALID(); break; } } @@ -1145,15 +1142,15 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_ */ void RRGraph::partition_node_in_edges(const RRNodeId& node) { //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_in_edges_[node].begin(), node_in_edges_[node].end(), + auto first_non_config_edge = std::partition(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node], [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - size_t num_conf_edges = std::distance(node_in_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_in_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range + size_t num_conf_edges = std::distance(node_inout_edges_[node].begin(), first_non_config_edge); + size_t num_non_conf_edges = node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_in_edges_[node].size(), + VTR_ASSERT_MSG(num_non_conf_edges <= (size_t)node_num_in_edges_[node], "Exceeded RR node maximum number of non-configurable input edges"); node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing @@ -1164,15 +1161,15 @@ void RRGraph::partition_node_in_edges(const RRNodeId& node) { */ void RRGraph::partition_node_out_edges(const RRNodeId& node) { //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_out_edges_[node].begin(), node_out_edges_[node].end(), + auto first_non_config_edge = std::partition(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end(), [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - size_t num_conf_edges = std::distance(node_out_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_out_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range + size_t num_conf_edges = std::distance(node_inout_edges_[node].begin() + node_num_in_edges_[node], first_non_config_edge); + size_t num_non_conf_edges = node_inout_edges_[node].size() - node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_out_edges_[node].size(), + VTR_ASSERT_MSG(num_non_conf_edges <= node_inout_edges_[node].size() - node_num_in_edges_[node], "Exceeded RR node maximum number of non-configurable output edges"); node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing @@ -1334,8 +1331,8 @@ bool RRGraph::validate_node_sizes() const { && node_segments_.size() == node_id_range_ && node_num_non_configurable_in_edges_.size() == node_id_range_ && node_num_non_configurable_out_edges_.size() == node_id_range_ - && node_in_edges_.size() == node_id_range_ - && node_out_edges_.size() == node_id_range_; + && node_num_in_edges_.size() == node_id_range_ + && node_inout_edges_.size() == node_id_range_; } bool RRGraph::validate_edge_sizes() const { @@ -1422,6 +1419,12 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_Rs_ = clean_and_reorder_values(node_Rs_, node_id_map); node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map); + node_segments_ = clean_and_reorder_values(node_segments_, node_id_map); + node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map); + node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map); + node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map); + node_inout_edges_ = clean_and_reorder_values(node_inout_edges_, node_id_map); + VTR_ASSERT(validate_node_sizes()); } @@ -1444,11 +1447,9 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m continue; } RRNodeId node = RRNodeId(id); - node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map); - node_out_edges_[node] = update_valid_refs(node_out_edges_[node], edge_id_map); + node_inout_edges_[node] = update_valid_refs(node_inout_edges_[node], edge_id_map); - VTR_ASSERT_MSG(all_valid(node_in_edges_[node]), "All Ids should be valid"); - VTR_ASSERT_MSG(all_valid(node_out_edges_[node]), "All Ids should be valid"); + VTR_ASSERT_MSG(all_valid(node_inout_edges_[node]), "All Ids should be valid"); } } @@ -1470,8 +1471,8 @@ void RRGraph::clear_nodes() { node_num_non_configurable_in_edges_.clear(); node_num_non_configurable_out_edges_.clear(); - node_in_edges_.clear(); - node_out_edges_.clear(); + node_num_in_edges_.clear(); + node_inout_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index c5c1108c35e..dc3f3145876 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -602,12 +602,11 @@ class RRGraph { * RRGraph rr_graph; * // Add 1 source node to the RRGraph object * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the output edges for the source node - * rr_graph.reserve_node_out_edges(src_node, 5); + * // Reserve the input and output edges for the source node + * rr_graph.reserve_node_inout_edges(src_node, 5); * // Add your edges */ - void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); - void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); + void reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges); /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type @@ -827,8 +826,20 @@ class RRGraph { vtr::vector node_num_non_configurable_in_edges_; vtr::vector node_num_non_configurable_out_edges_; - vtr::vector> node_in_edges_; - vtr::vector> node_out_edges_; + /* Record the dividing point between input and output edges for each node + * Both input and output edges are stored in a list for memory efficiency + * We use a dividing point to identify the groups + * The edges are arranged in as the following format: + * Index in list: + * 0--------------------------------------------------------------------------------------------------->N + * + * |<----------------------->|^ |<------------------------->| + * node_num_non_cinfigurable_in_edges | node_num_non_configurable_out_edges + * | + * node_num_in_edges + */ + vtr::vector node_num_in_edges_; + vtr::vector> node_inout_edges_; /* Edge related data */ size_t edge_id_range_; /* Range of edge ids */ From bb952ff8354b046fe1b900e7218a0ffee94cd966 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 22 Nov 2019 11:24:11 -0700 Subject: [PATCH 18/58] minor code format fix --- vpr/src/device/rr_graph_obj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 3f7cfb16555..1e8bacf8553 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -911,7 +911,7 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_num_non_configurable_in_edges_.emplace_back(); //Initially empty node_num_non_configurable_out_edges_.emplace_back(); //Initially empty - node_num_in_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(); //Initially empty node_inout_edges_.emplace_back(); //Initially empty invalidate_fast_node_lookup(); From 5ee9bb06ac4914f49f5dc29f9a55cc2bd839fd79 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:02:19 -0500 Subject: [PATCH 19/58] vpr: Rename RRGraph node/edge_id_range_ to num_nodes_/num_egdes_ --- vpr/src/device/rr_graph_obj.cpp | 95 ++++++++++++++++----------------- vpr/src/device/rr_graph_obj.h | 4 +- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 1e8bacf8553..696aedd15e0 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -20,9 +20,9 @@ *******************************************************************/ RRGraph::RRGraph() { /* Set node range to be zero ! */ - node_id_range_ = 0; + num_nodes_ = 0; /* Set edge range to be zero ! */ - edge_id_range_ = 0; + num_edges_ = 0; } /******************************************************************** @@ -32,8 +32,8 @@ std::vector RRGraph::nodes() const { /* Create a list of valid node ids */ std::vector node_ids; /* Reserve the edge list, since it could be very last. Also exclude the invalid node ids */ - node_ids.reserve(node_id_range_ - invalid_node_ids_.size()); - for (size_t id = 0; id < node_id_range_; ++id) { + node_ids.reserve(num_nodes_ - invalid_node_ids_.size()); + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -50,8 +50,8 @@ std::vector RRGraph::edges() const { /* Create a list of valid edge ids */ std::vector edge_ids; /* Reserve the edge list, since it could be very last. Also exclude the invalid edge ids */ - edge_ids.reserve(edge_id_range_ - invalid_edge_ids_.size()); - for (size_t id = 0; id < edge_id_range_; ++id) { + edge_ids.reserve(num_edges_ - invalid_edge_ids_.size()); + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -523,7 +523,7 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const { /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -551,7 +551,7 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -669,7 +669,7 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const { /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -690,7 +690,7 @@ bool RRGraph::validate_nodes_in_edges() const { /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -735,7 +735,7 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -758,7 +758,7 @@ bool RRGraph::validate_edge_src_nodes() const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -890,9 +890,9 @@ void RRGraph::reserve_node_inout_edges(const RRNodeId& node, const size_t& num_i /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { /* Allocate an ID */ - RRNodeId node_id = RRNodeId(node_id_range_); + RRNodeId node_id = RRNodeId(num_nodes_); /* Expand range of node ids */ - node_id_range_++; + num_nodes_++; /* Initialize the attributes */ node_types_.push_back(type); @@ -927,9 +927,9 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons VTR_ASSERT(valid_switch_id(switch_id)); /* Allocate an ID */ - RREdgeId edge_id = RREdgeId(edge_id_range_); + RREdgeId edge_id = RREdgeId(num_edges_); /* Expand range of edge ids */ - edge_id_range_++; + num_edges_++; /* Initialize the attributes */ edge_src_nodes_.push_back(source); @@ -1180,7 +1180,7 @@ void RRGraph::partition_node_out_edges(const RRNodeId& node) { */ void RRGraph::partition_in_edges() { /* For each node */ - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1196,7 +1196,7 @@ void RRGraph::partition_in_edges() { */ void RRGraph::partition_out_edges() { /* For each node */ - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1224,7 +1224,7 @@ void RRGraph::build_fast_node_lookup() const { /* Get the max (x,y) and then we can resize the ndmatrix */ vtr::Point max_coord(0, 0); - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1236,7 +1236,7 @@ void RRGraph::build_fast_node_lookup() const { } node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1284,12 +1284,12 @@ void RRGraph::initialize_fast_node_lookup() const { } bool RRGraph::valid_node_id(const RRNodeId& node) const { - return (size_t(node) < node_id_range_) + return (size_t(node) < num_nodes_) && (invalid_node_ids_.end() == invalid_node_ids_.find(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { - return (size_t(edge) < edge_id_range_) + return (size_t(edge) < num_edges_) && (invalid_edge_ids_.end() == invalid_edge_ids_.find(edge)); } @@ -1319,26 +1319,25 @@ bool RRGraph::validate_sizes() const { } bool RRGraph::validate_node_sizes() const { - return node_types_.size() == node_id_range_ - && node_bounding_boxes_.size() == node_id_range_ - && node_capacities_.size() == node_id_range_ - && node_ptc_nums_.size() == node_id_range_ - && node_cost_indices_.size() == node_id_range_ - && node_directions_.size() == node_id_range_ - && node_sides_.size() == node_id_range_ - && node_Rs_.size() == node_id_range_ - && node_Cs_.size() == node_id_range_ - && node_segments_.size() == node_id_range_ - && node_num_non_configurable_in_edges_.size() == node_id_range_ - && node_num_non_configurable_out_edges_.size() == node_id_range_ - && node_num_in_edges_.size() == node_id_range_ - && node_inout_edges_.size() == node_id_range_; + return node_types_.size() == num_nodes_ + && node_bounding_boxes_.size() == num_nodes_ + && node_capacities_.size() == num_nodes_ + && node_ptc_nums_.size() == num_nodes_ + && node_cost_indices_.size() == num_nodes_ + && node_directions_.size() == num_nodes_ + && node_sides_.size() == num_nodes_ + && node_Rs_.size() == num_nodes_ + && node_Cs_.size() == num_nodes_ + && node_segments_.size() == num_nodes_ + && node_num_non_configurable_in_edges_.size() == num_nodes_ + && node_num_non_configurable_out_edges_.size() == num_nodes_ + && node_inout_edges_.size() == num_nodes_; } bool RRGraph::validate_edge_sizes() const { - return edge_src_nodes_.size() == edge_id_range_ - && edge_sink_nodes_.size() == edge_id_range_ - && edge_switches_.size() == edge_id_range_; + return edge_src_nodes_.size() == num_edges_ + && edge_sink_nodes_.size() == num_edges_ + && edge_switches_.size() == num_edges_; } bool RRGraph::validate_switch_sizes() const { @@ -1350,8 +1349,8 @@ bool RRGraph::validate_segment_sizes() const { } void RRGraph::compress() { - vtr::vector node_id_map(node_id_range_); - vtr::vector edge_id_map(edge_id_range_); + vtr::vector node_id_map(num_nodes_); + vtr::vector edge_id_map(num_edges_); build_id_maps(node_id_map, edge_id_map); @@ -1375,7 +1374,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { /* Build node ids including invalid ids and compress */ vtr::vector node_ids; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1390,7 +1389,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, /* Build edge ids including invalid ids and compress */ vtr::vector edge_ids; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -1405,7 +1404,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { - node_id_range_ = node_id_map.size(); + num_nodes_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); @@ -1429,7 +1428,7 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { - edge_id_range_ = edge_id_map.size(); + num_edges_ = edge_id_map.size(); edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map); edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map); @@ -1439,7 +1438,7 @@ void RRGraph::clean_edges(const vtr::vector& edge_id_map) { } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1455,7 +1454,7 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m /* Empty all the vectors related to nodes */ void RRGraph::clear_nodes() { - node_id_range_ = 0; + num_nodes_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); @@ -1480,7 +1479,7 @@ void RRGraph::clear_nodes() { /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { - edge_id_range_ = 0; + num_edges_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index dc3f3145876..56b4beae63d 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -807,7 +807,7 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - size_t node_id_range_; /* Range of node ids */ + size_t num_nodes_; /* Range of node ids */ std::unordered_map invalid_node_ids_; /* Invalid edge ids */ vtr::vector node_types_; @@ -842,7 +842,7 @@ class RRGraph { vtr::vector> node_inout_edges_; /* Edge related data */ - size_t edge_id_range_; /* Range of edge ids */ + size_t num_edges_; /* Range of edge ids */ std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; From b60df75d25d7f6e123a56b268931f1e066cf7b95 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:11:41 -0500 Subject: [PATCH 20/58] vpr: Prefer using valid_node_id()/valid_edge_id() in RRGraph This avoids exposing the details of how we are tracking invalid edges through-out the RRGraph implementation code. --- vpr/src/device/rr_graph_obj.cpp | 45 +++++++++++---------------------- 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 696aedd15e0..82fee29dd57 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -35,8 +35,7 @@ std::vector RRGraph::nodes() const { node_ids.reserve(num_nodes_ - invalid_node_ids_.size()); for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -53,8 +52,7 @@ std::vector RRGraph::edges() const { edge_ids.reserve(num_edges_ - invalid_edge_ids_.size()); for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -525,8 +523,7 @@ bool RRGraph::validate_node_segments() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -553,8 +550,7 @@ bool RRGraph::validate_edge_switches() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -671,8 +667,7 @@ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -692,8 +687,7 @@ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -737,8 +731,7 @@ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -760,8 +753,7 @@ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -1182,8 +1174,7 @@ void RRGraph::partition_in_edges() { /* For each node */ for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1198,8 +1189,7 @@ void RRGraph::partition_out_edges() { /* For each node */ for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1226,8 +1216,7 @@ void RRGraph::build_fast_node_lookup() const { vtr::Point max_coord(0, 0); for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1238,8 +1227,7 @@ void RRGraph::build_fast_node_lookup() const { for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1376,8 +1364,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector node_ids; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Give and invalid id */ node_ids.push_back(RRNodeId::INVALID()); continue; @@ -1391,8 +1378,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector edge_ids; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Give and invalid id */ edge_ids.push_back(RREdgeId::INVALID()); continue; @@ -1440,8 +1426,7 @@ void RRGraph::clean_edges(const vtr::vector& edge_id_map) { void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } From 375f9ab52029014554d1c90eba81376b23b84eef Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:13:53 -0500 Subject: [PATCH 21/58] vpr: Use std::unordered_set for tracking invalied IDs in RRGraph Previously used a std::unordered_map but the value was unused. --- vpr/src/device/rr_graph_obj.cpp | 8 ++++---- vpr/src/device/rr_graph_obj.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 82fee29dd57..2723650f089 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -982,7 +982,7 @@ void RRGraph::remove_node(const RRNodeId& node) { } //Mark node invalid - invalid_node_ids_[node] = true; + invalid_node_ids_.insert(node); //Invalidate the node look-up invalidate_fast_node_lookup(); @@ -1015,7 +1015,7 @@ void RRGraph::remove_edge(const RREdgeId& edge) { } /* Mark edge invalid */ - invalid_edge_ids_[edge] = true; + invalid_edge_ids_.insert(edge); set_dirty(); } @@ -1273,12 +1273,12 @@ void RRGraph::initialize_fast_node_lookup() const { bool RRGraph::valid_node_id(const RRNodeId& node) const { return (size_t(node) < num_nodes_) - && (invalid_node_ids_.end() == invalid_node_ids_.find(node)); + && (!invalid_node_ids_.count(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { return (size_t(edge) < num_edges_) - && (invalid_edge_ids_.end() == invalid_edge_ids_.find(edge)); + && (!invalid_edge_ids_.count(edge)); } /* check if a given switch id is valid or not */ diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 56b4beae63d..f9d0c4eada2 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -808,7 +808,7 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ size_t num_nodes_; /* Range of node ids */ - std::unordered_map invalid_node_ids_; /* Invalid edge ids */ + std::unordered_set invalid_node_ids_; /* Invalid edge ids */ vtr::vector node_types_; @@ -843,7 +843,7 @@ class RRGraph { /* Edge related data */ size_t num_edges_; /* Range of edge ids */ - std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ + std::unordered_set invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_switches_; From 659192a4a8e8675100c6582c6526859657a2a47b Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:36:34 -0500 Subject: [PATCH 22/58] vpr: Use lazy iterators to iterate through RRGraph nodes/edges This should be more run-time and memory efficient than creating a vector of the entire range and returning it. --- vpr/src/device/rr_graph_obj.cpp | 36 ++++------------------ vpr/src/device/rr_graph_obj.h | 53 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 2723650f089..12c7d7efc1f 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -28,38 +28,14 @@ RRGraph::RRGraph() { /******************************************************************** * Accessors *******************************************************************/ -std::vector RRGraph::nodes() const { - /* Create a list of valid node ids */ - std::vector node_ids; - /* Reserve the edge list, since it could be very last. Also exclude the invalid node ids */ - node_ids.reserve(num_nodes_ - invalid_node_ids_.size()); - for (size_t id = 0; id < num_nodes_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_node_id(RRNodeId(id))) { - /* Skip this id */ - continue; - } - /* Reach here, this is a valid id, push to the edge list */ - node_ids.push_back(RRNodeId(id)); - } - return node_ids; +RRGraph::lazy_node_range RRGraph::nodes() const { + return vtr::make_range(lazy_node_iterator(RRNodeId(0), invalid_node_ids_), + lazy_node_iterator(RRNodeId(num_nodes_), invalid_node_ids_)); } -std::vector RRGraph::edges() const { - /* Create a list of valid edge ids */ - std::vector edge_ids; - /* Reserve the edge list, since it could be very last. Also exclude the invalid edge ids */ - edge_ids.reserve(num_edges_ - invalid_edge_ids_.size()); - for (size_t id = 0; id < num_edges_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_edge_id(RREdgeId(id))) { - /* Skip this id */ - continue; - } - /* Reach here, this is a valid id, push to the edge list */ - edge_ids.push_back(RREdgeId(id)); - } - return edge_ids; +RRGraph::lazy_edge_range RRGraph::edges() const { + return vtr::make_range(lazy_edge_iterator(RREdgeId(0), invalid_edge_ids_), + lazy_edge_iterator(RREdgeId(num_edges_), invalid_edge_ids_)); } RRGraph::switch_range RRGraph::switches() const { diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f9d0c4eada2..6c726492624 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -213,6 +213,53 @@ class RRGraph { public: /* Types */ + class lazy_node_iterator : public std::iterator { + public: + lazy_node_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} + iterator operator++() { + value_ = RRNodeId(size_t(value_) + 1); + return *this; + } + iterator operator--() { + value_ = RRNodeId(size_t(value_) - 1); + return *this; + } + value_type operator*() const { return (invalid_ids_.count(value_)) ? RRNodeId::INVALID() : value_; } + + friend bool operator==(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + + class lazy_edge_iterator : public std::iterator { + public: + lazy_edge_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} + iterator operator++() { + value_ = RREdgeId(size_t(value_) + 1); + return *this; + } + iterator operator--() { + value_ = RREdgeId(size_t(value_) - 1); + return *this; + } + value_type operator*() const { return (invalid_ids_.count(value_)) ? RREdgeId::INVALID() : value_; } + + friend bool operator==(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + + /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; @@ -225,6 +272,8 @@ class RRGraph { typedef vtr::Range switch_range; typedef vtr::Range segment_range; + typedef vtr::Range lazy_node_range; + typedef vtr::Range lazy_edge_range; public: /* Constructors */ RRGraph(); @@ -252,8 +301,8 @@ class RRGraph { * // Do something with each segment * } */ - std::vector nodes() const; - std::vector edges() const; + lazy_node_range nodes() const; + lazy_edge_range edges() const; switch_range switches() const; segment_range segments() const; From 9ad5ca2ac039e1da2a8b6be4f0ef576d6dee2406 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:49:37 -0500 Subject: [PATCH 23/58] vpr: Refactor lazy RRGraph node/edge iterators into a common template class --- vpr/src/device/rr_graph_obj.cpp | 9 +++---- vpr/src/device/rr_graph_obj.h | 43 ++++++++++----------------------- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 12c7d7efc1f..dcabffe5176 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -18,11 +18,10 @@ /******************************************************************** * Constructors *******************************************************************/ -RRGraph::RRGraph() { - /* Set node range to be zero ! */ - num_nodes_ = 0; - /* Set edge range to be zero ! */ - num_edges_ = 0; +RRGraph::RRGraph() + : num_nodes_(0) + , num_edges_(0) { + //Pass } /******************************************************************** diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 6c726492624..aa8d08be33f 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -213,52 +213,35 @@ class RRGraph { public: /* Types */ - class lazy_node_iterator : public std::iterator { - public: - lazy_node_iterator(value_type init, const std::unordered_set& invalid_ids) - : value_(init) - , invalid_ids_(invalid_ids) {} - iterator operator++() { - value_ = RRNodeId(size_t(value_) + 1); - return *this; - } - iterator operator--() { - value_ = RRNodeId(size_t(value_) - 1); - return *this; - } - value_type operator*() const { return (invalid_ids_.count(value_)) ? RRNodeId::INVALID() : value_; } - - friend bool operator==(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return lhs.value_ == rhs.value_; } - friend bool operator!=(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return !(lhs == rhs); } - - private: - value_type value_; - const std::unordered_set& invalid_ids_; - }; - class lazy_edge_iterator : public std::iterator { + template + class lazy_id_iterator : public std::iterator { public: - lazy_edge_iterator(value_type init, const std::unordered_set& invalid_ids) + typedef typename std::iterator::value_type value_type; + typedef typename std::iterator::iterator iterator; + lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) : value_(init) , invalid_ids_(invalid_ids) {} iterator operator++() { - value_ = RREdgeId(size_t(value_) + 1); + value_ = ID(size_t(value_) + 1); return *this; } iterator operator--() { - value_ = RREdgeId(size_t(value_) - 1); + value_ = ID(size_t(value_) - 1); return *this; } - value_type operator*() const { return (invalid_ids_.count(value_)) ? RREdgeId::INVALID() : value_; } + value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } - friend bool operator==(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return lhs.value_ == rhs.value_; } - friend bool operator!=(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return !(lhs == rhs); } + friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } private: value_type value_; - const std::unordered_set& invalid_ids_; + const std::unordered_set& invalid_ids_; }; + typedef lazy_id_iterator lazy_node_iterator; + typedef lazy_id_iterator lazy_edge_iterator; /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; From 329c69b86cef7fab74f8734417b7bdba5b7a2cc4 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 11:01:07 -0500 Subject: [PATCH 24/58] vpr: Use forward declaration to move lazy_id_iterator implementation Users of the RRGraph shouldn't care how the edge/node iteration is implemented so move the implementation below the public methods to improve readability. --- vpr/src/device/rr_graph_obj.h | 81 +++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index aa8d08be33f..7a0461a6728 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -214,49 +214,26 @@ class RRGraph { public: /* Types */ + //Lazy iterator utility forward declaration template - class lazy_id_iterator : public std::iterator { - public: - typedef typename std::iterator::value_type value_type; - typedef typename std::iterator::iterator iterator; - lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) - : value_(init) - , invalid_ids_(invalid_ids) {} - iterator operator++() { - value_ = ID(size_t(value_) + 1); - return *this; - } - iterator operator--() { - value_ = ID(size_t(value_) - 1); - return *this; - } - value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } - - friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } - friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } - - private: - value_type value_; - const std::unordered_set& invalid_ids_; - }; - - typedef lazy_id_iterator lazy_node_iterator; - typedef lazy_id_iterator lazy_edge_iterator; + class lazy_id_iterator; /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; typedef vtr::vector::const_iterator segment_iterator; + typedef lazy_id_iterator lazy_node_iterator; + typedef lazy_id_iterator lazy_edge_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; typedef vtr::Range edge_range; typedef vtr::Range switch_range; typedef vtr::Range segment_range; - typedef vtr::Range lazy_node_range; typedef vtr::Range lazy_edge_range; + public: /* Constructors */ RRGraph(); @@ -760,6 +737,54 @@ class RRGraph { /* top-level function to free, should be called when to delete a RRGraph */ void clear(); + public: /* Type implementations */ + + /* + * This class (forward delcared above) is a template used to represent a lazily calculated + * iterator of the specified ID type. The key assumption made is that the ID space is + * contiguous and can be walked by incrementing the underlying ID value. To account for + * invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for + * ID values in the set. + * + * It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes()) + * just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_), + * and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_). + */ + template + class lazy_id_iterator : public std::iterator { + public: + //Since we pass ID as a template to std::iterator we need to use an explicit 'typename' + //to bring the value_type and iterator names into scope + typedef typename std::iterator::value_type value_type; + typedef typename std::iterator::iterator iterator; + + lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} + + //Advance to the next ID value + iterator operator++() { + value_ = ID(size_t(value_) + 1); + return *this; + } + + //Advance to the previous ID value + iterator operator--() { + value_ = ID(size_t(value_) - 1); + return *this; + } + + //Dereference the iterator + value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } + + friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + private: /* Internal Mutators to perform edge partitioning */ /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_node_in_edges(const RRNodeId& node); From 97196e8bacc1d1aa6d4d8ce24e663e56c9dbd293 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 13:33:20 -0500 Subject: [PATCH 25/58] vpr: Reduce RRGraph memory usage by merging node edge arrays We now use a single array to store the edges associated with a node. The array is sorted into sub-ranges (e.g. incoming/outgoing, configurable/nonconfigurable) which still allows efficient iteration through the edge subranges. We store the sizes of the various sub-ranges to enable quickly determination of the delimiters between sub-ranges. We also use a raw pointer for the edge array (rather than a vtr::vector) which further saves memory. The create_edge() routine now no longer inserts the edge into the node data. Instead a single call is made to rebuild_node_edges() which will walk the various RRGraph::edge_* members to precisely allocate the relevant node_edges_ and node_num*edges_ data members. The trade-off of this change is that the various node_*_edges() will not work properly after an edge is added to the RR graph until rebuild_node_edges() is called. Currently it rebuilds the node edges from scratch, and so calls to it should be minimized (the preferred approach is to add all edges and then call rebuild_node_edges() once). If needed, support for incrementally rebuilding node_edges could be added (while the use of a single array per node type in general require insertion not at the end of the array, an O(n) operation, the number of edges per node is typically bounded by a small constant, so it would still be reasonably efficient); it is not currently required and so is left as *potential* future work should the need for it arise. --- vpr/src/device/create_rr_graph.cpp | 11 +- vpr/src/device/rr_graph_obj.cpp | 319 +++++++++++++++------------- vpr/src/device/rr_graph_obj.h | 118 +++++----- vpr/src/device/rr_graph_obj_utils.h | 26 +++ 4 files changed, 248 insertions(+), 226 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index a81ece928e7..6faced34b31 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -91,15 +91,6 @@ void convert_rr_graph(std::vector& vpr_segments) { } device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); - // Create the edges - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - const auto& node = device_ctx.rr_nodes[inode]; - /* Reserve input and output edges for the node: - * this is very important to avoid memory fragments!!! - */ - device_ctx.rr_graph.reserve_node_inout_edges(RRNodeId(inode), node.fan_in() + node.num_edges()); - } - /* Add edges for each node */ for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; @@ -121,7 +112,7 @@ void convert_rr_graph(std::vector& vpr_segments) { * See how the router will use the edges and determine the strategy * if we want to partition the edges first or depends on the routing needs */ - device_ctx.rr_graph.partition_edges(); + device_ctx.rr_graph.rebuild_node_edges(); /* Essential check for rr_graph, build look-up and */ if (false == device_ctx.rr_graph.validate()) { diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index dcabffe5176..59907c4cdec 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -135,7 +135,7 @@ short RRGraph::node_fan_in(const RRNodeId& node) const { } short RRGraph::node_fan_out(const RRNodeId& node) const { - return node_inout_edges_[node].size() - node_num_in_edges_[node]; + return node_num_out_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { @@ -214,7 +214,7 @@ short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { * Get the number of configurable output edges of a node */ short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_inout_edges_[node].size() - node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; + return node_num_out_edges_[node] - node_num_non_configurable_in_edges_[node]; } /* @@ -237,78 +237,65 @@ short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { return node_num_non_configurable_out_edges_[node]; } +RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node]); +} + +RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node]); +} + +RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); +} + /* Get the list of configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the inputedge list (0 to XX) */ - auto begin = node_inout_edges_[node].begin(); - - /* By default the non-configurable edges will be stored at second part of the input edge list (XX to end) */ - auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]); } /* Get the list of non configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range(node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node], + node_edges_[node].get() + node_num_in_edges_[node]); } /* Get the list of configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]); } /* Get the list of non configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ - VTR_ASSERT_SAFE(valid_node_id(node)); - - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_inout_edges_[node].end(); - - return vtr::make_range(begin, end); -} - -RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end()); -} -RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { - VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node]); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node], + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); } //Edge attributes @@ -818,12 +805,12 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { this->node_Cs_.reserve(num_nodes); this->node_segments_.reserve(num_nodes); + /* Edge-related vectors */ + this->node_num_in_edges_.reserve(num_nodes); + this->node_num_out_edges_.reserve(num_nodes); this->node_num_non_configurable_in_edges_.reserve(num_nodes); this->node_num_non_configurable_out_edges_.reserve(num_nodes); - - /* Edge-relate vectors */ - this->node_num_in_edges_.reserve(num_nodes); - this->node_inout_edges_.reserve(num_nodes); + this->node_edges_.reserve(num_nodes); } /* Reserve a list of edges */ @@ -846,14 +833,6 @@ void RRGraph::reserve_segments(const size_t& num_segments) { this->segments_.reserve(num_segments); } -/* Reserve the input edges for a node */ -void RRGraph::reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges) { - /* Validate the node id */ - VTR_ASSERT_SAFE(true == valid_node_id(node)); - /* Reserve the input edge list */ - this->node_inout_edges_[node].reserve(num_inout_edges); -} - /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { /* Allocate an ID */ @@ -875,11 +854,12 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_Cs_.push_back(0.); node_segments_.push_back(RRSegmentId::INVALID()); - node_num_non_configurable_in_edges_.emplace_back(); //Initially empty - node_num_non_configurable_out_edges_.emplace_back(); //Initially empty + node_edges_.emplace_back(); //Initially empty - node_num_in_edges_.emplace_back(); //Initially empty - node_inout_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(0); + node_num_out_edges_.emplace_back(0); + node_num_non_configurable_in_edges_.emplace_back(0); + node_num_non_configurable_out_edges_.emplace_back(0); invalidate_fast_node_lookup(); @@ -903,17 +883,10 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - /* Add the edge to the nodes: - * We use delimeter to split incoming and outgoing edges - * for a node into two groups - * When adding the new edge, - * we will add the edge id to the tail of node_inout_edge list of source node - * we will insert the edge id to the delimeter of node_inout_edge list of sink node - * the delimeter node_num_in_edges_ will be updated for the sink node! - */ - node_inout_edges_[source].push_back(edge_id); - node_inout_edges_[sink].insert(node_inout_edges_[sink].begin() + (size_t)node_num_in_edges_[sink], edge_id); - node_num_in_edges_[sink]++; + //We do not create the entry in node_edges_ here! + //For memory efficiency this is done when + //rebuild_node_edges() is called (i.e. after all + //edges have been created). VTR_ASSERT(validate_sizes()); @@ -976,15 +949,15 @@ void RRGraph::remove_edge(const RREdgeId& edge) { /* Invalidate node to edge references * TODO: consider making this optional (e.g. if called from remove_node) */ - for (size_t i = 0; i < node_inout_edges_[src_node].size(); ++i) { - if (node_inout_edges_[src_node][i] == edge) { - node_inout_edges_[src_node][i] = RREdgeId::INVALID(); + for (size_t i = 0; i < node_num_in_edges_[src_node]; ++i) { + if (node_edges_[src_node][i] == edge) { + node_edges_[src_node][i] = RREdgeId::INVALID(); break; } } - for (size_t i = 0; i < node_inout_edges_[sink_node].size(); ++i) { - if (node_inout_edges_[sink_node][i] == edge) { - node_inout_edges_[sink_node][i] = RREdgeId::INVALID(); + for (size_t i = node_num_in_edges_[sink_node]; i < node_num_in_edges_[sink_node] + node_num_out_edges_[sink_node]; ++i) { + if (node_edges_[sink_node][i] == edge) { + node_edges_[sink_node][i] = RREdgeId::INVALID(); break; } } @@ -1103,84 +1076,121 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_ node_segments_[node] = segment_id; } +void RRGraph::rebuild_node_edges() { + node_edges_.resize(nodes().size()); + node_num_in_edges_.resize(nodes().size(), 0); + node_num_out_edges_.resize(nodes().size(), 0); + node_num_non_configurable_in_edges_.resize(nodes().size(), 0); + node_num_non_configurable_out_edges_.resize(nodes().size(), 0); + + //Count the number of edges of each type + for (RREdgeId edge : edges()) { + if (!edge) continue; + + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); + bool config = edge_is_configurable(edge); + + ++node_num_out_edges_[src_node]; + ++node_num_in_edges_[sink_node]; + if (!config) { + ++node_num_non_configurable_out_edges_[src_node]; + ++node_num_non_configurable_in_edges_[sink_node]; + } + } -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_in_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node], - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - - size_t num_conf_edges = std::distance(node_inout_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range - - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= (size_t)node_num_in_edges_[node], - "Exceeded RR node maximum number of non-configurable input edges"); - - node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing -} - -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_out_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end(), - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - - size_t num_conf_edges = std::distance(node_inout_edges_[node].begin() + node_num_in_edges_[node], first_non_config_edge); - size_t num_non_conf_edges = node_inout_edges_[node].size() - node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range + //Allocate precisely the correct space for each nodes edge list + for (RRNodeId node : nodes()) { + if (!node) continue; - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_inout_edges_[node].size() - node_num_in_edges_[node], - "Exceeded RR node maximum number of non-configurable output edges"); + node_edges_[node] = std::make_unique(node_num_in_edges_[node] + node_num_out_edges_[node]); + } - node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing -} + //Insert the edges into the node lists + { + vtr::vector inserted_edge_cnt(nodes().size(), 0); + for (RREdgeId edge : edges()) { + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); -/* For all nodes in a rr_graph - * classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_in_edges() { - /* For each node */ - for (size_t id = 0; id < num_nodes_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_node_id(RRNodeId(id))) { - /* Skip this id */ - continue; + node_edges_[src_node][inserted_edge_cnt[src_node]++] = edge; + node_edges_[sink_node][inserted_edge_cnt[sink_node]++] = edge; } - this->partition_node_in_edges(RRNodeId(id)); } -} -/* For all nodes in a rr_graph - * classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_out_edges() { - /* For each node */ - for (size_t id = 0; id < num_nodes_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_node_id(RRNodeId(id))) { - /* Skip this id */ - continue; +#if 0 + //TODO: Sanity Check remove! + for (RRNodeId node : nodes()) { + for (size_t iedge = 0; iedge < node_num_in_edges_[node] + node_num_out_edges_[node]; ++iedge) { + RREdgeId edge = node_edges_[node][iedge]; + VTR_ASSERT(edge_src_node(edge) == node || edge_sink_node(edge) == node); } - this->partition_node_out_edges(RRNodeId(id)); } -} - -/* For all nodes in a rr_graph - * classify both input and output edges of each node - * to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_edges() { - /* Partition input edges */ - this->partition_in_edges(); - /* Partition output edges */ - this->partition_out_edges(); +#endif + + //Partition each node's edge lists according to their type to line up with the counts + + auto is_configurable_edge = [&](const RREdgeId edge) { + return edge_is_configurable(edge); + }; + + for (RRNodeId node : nodes()) { + if (!node) continue; + + //We partition the nodes first by incoming/outgoing: + // + // +---------------------------+-----------------------------+ + // | in | out | + // +---------------------------+-----------------------------+ + // + //and then the two subsets by configurability. So the final ordering is: + // + // +-----------+---------------+------------+----------------+ + // | in_config | in_non_config | out_config | out_non_config | + // +-----------+---------------+------------+----------------+ + // + + //Partition first into incoming/outgoing + auto is_incoming_edge = [&](const RREdgeId edge) { + return edge_sink_node(edge) == node; + }; + std::partition(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], + is_incoming_edge); + + //Partition incoming by configurable/non-configurable + std::partition(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node], + is_configurable_edge); + + //Partition outgoing by configurable/non-configurable + std::partition(node_edges_[node].get() + node_num_in_edges_[node], + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], + is_configurable_edge); + +#if 0 + //TODO: Sanity check remove! + size_t nedges = node_num_in_edges_[node] + node_num_out_edges_[node]; + for (size_t iedge = 0; iedge < nedges; ++iedge) { + RREdgeId edge = node_edges_[node][iedge]; + if (iedge < node_num_in_edges_[node]) { //Incoming + VTR_ASSERT(edge_sink_node(edge) == node); + if (iedge < node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]) { + VTR_ASSERT(edge_is_configurable(edge)); + } else { + VTR_ASSERT(!edge_is_configurable(edge)); + } + } else { //Outgoing + VTR_ASSERT(edge_src_node(edge) == node); + if (iedge < node_num_in_edges_[node] + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]) { + VTR_ASSERT(edge_is_configurable(edge)); + } else { + VTR_ASSERT(!edge_is_configurable(edge)); + } + } + } +#endif + } } void RRGraph::build_fast_node_lookup() const { @@ -1294,7 +1304,7 @@ bool RRGraph::validate_node_sizes() const { && node_segments_.size() == num_nodes_ && node_num_non_configurable_in_edges_.size() == num_nodes_ && node_num_non_configurable_out_edges_.size() == num_nodes_ - && node_inout_edges_.size() == num_nodes_; + && node_edges_.size() == num_nodes_; } bool RRGraph::validate_edge_sizes() const { @@ -1383,7 +1393,8 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map); node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map); node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map); - node_inout_edges_ = clean_and_reorder_values(node_inout_edges_, node_id_map); + node_num_out_edges_ = clean_and_reorder_values(node_num_out_edges_, node_id_map); + //node_edges_ = clean_and_reorder_values(node_edges_, node_id_map); VTR_ASSERT(validate_node_sizes()); } @@ -1406,9 +1417,12 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m continue; } RRNodeId node = RRNodeId(id); - node_inout_edges_[node] = update_valid_refs(node_inout_edges_[node], edge_id_map); - VTR_ASSERT_MSG(all_valid(node_inout_edges_[node]), "All Ids should be valid"); + auto begin = node_edges_[node].get(); + auto end = begin + node_num_in_edges_[node] + node_num_out_edges_[node]; + update_valid_refs(begin, end, edge_id_map); + + VTR_ASSERT_MSG(all_valid(begin, end), "All Ids should be valid"); } } @@ -1427,11 +1441,12 @@ void RRGraph::clear_nodes() { node_Cs_.clear(); node_segments_.clear(); + node_num_in_edges_.clear(); + node_num_out_edges_.clear(); node_num_non_configurable_in_edges_.clear(); node_num_non_configurable_out_edges_.clear(); - node_num_in_edges_.clear(); - node_inout_edges_.clear(); + node_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 7a0461a6728..d20203bf920 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -213,7 +213,6 @@ class RRGraph { public: /* Types */ - //Lazy iterator utility forward declaration template class lazy_id_iterator; @@ -228,7 +227,7 @@ class RRGraph { /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; - typedef vtr::Range edge_range; + typedef vtr::Range edge_range; typedef vtr::Range switch_range; typedef vtr::Range segment_range; typedef vtr::Range lazy_node_range; @@ -471,11 +470,9 @@ class RRGraph { /* Get the number of non-configurable output edges of a node */ short node_num_non_configurable_out_edges(const RRNodeId& node) const; - /* Get the range (list) of edges related to a given node */ - edge_range node_configurable_in_edges(const RRNodeId& node) const; - edge_range node_non_configurable_in_edges(const RRNodeId& node) const; - edge_range node_configurable_out_edges(const RRNodeId& node) const; - edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + //Returns an iterable range of all edges (incoming & outgoing) for + //the specified node + edge_range node_edges(const RRNodeId& node) const; /* Get a list of edge ids, which are incoming edges to a node */ edge_range node_in_edges(const RRNodeId& node) const; @@ -483,6 +480,12 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; + /* Get the range (list) of edges related to a given node */ + edge_range node_configurable_in_edges(const RRNodeId& node) const; + edge_range node_non_configurable_in_edges(const RRNodeId& node) const; + edge_range node_configurable_out_edges(const RRNodeId& node) const; + edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + /* Edge-related attributes * An example to explain the terminology used in RRGraph * edgeA @@ -602,21 +605,6 @@ class RRGraph { void reserve_switches(const size_t& num_switches); void reserve_segments(const size_t& num_segments); - /* Reserve the lists of input/output edges for a RR node to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * - * For example: - * RRGraph rr_graph; - * // Add 1 source node to the RRGraph object - * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the input and output edges for the source node - * rr_graph.reserve_node_inout_edges(src_node, 5); - * // Add your edges - */ - void reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges); - /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type * Detailed node-level information should be added using the set_node_* functions @@ -625,6 +613,7 @@ class RRGraph { * set_node_xlow(node, 0); */ RRNodeId create_node(const t_rr_type& type); + /* Add a edge to the RRGraph, by providing the source and sink node * This function will automatically create a node and * configure the nodes and edges in connection @@ -719,15 +708,14 @@ class RRGraph { /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in one vector, - * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) + /* + * Build the node to edge references to allow iteration through + * a node's in/out edges. + * + * Must be called before any node_*_in_edges() or node_*_out_edges() member + * functions can be called. */ - void partition_edges(); + void rebuild_node_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set @@ -738,7 +726,6 @@ class RRGraph { void clear(); public: /* Type implementations */ - /* * This class (forward delcared above) is a template used to represent a lazily calculated * iterator of the specified ID type. The key assumption made is that the ID space is @@ -785,19 +772,6 @@ class RRGraph { const std::unordered_set& invalid_ids_; }; - private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_in_edges(const RRNodeId& node); - - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_out_edges(const RRNodeId& node); - - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_in_edges(); - - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_out_edges(); - private: /* Internal free functions */ void clear_nodes(); void clear_edges(); @@ -864,7 +838,7 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - size_t num_nodes_; /* Range of node ids */ + size_t num_nodes_; /* Range of node ids */ std::unordered_set invalid_node_ids_; /* Invalid edge ids */ vtr::vector node_types_; @@ -879,27 +853,43 @@ class RRGraph { vtr::vector node_Rs_; vtr::vector node_Cs_; vtr::vector node_segments_; /* Segment ids for each node */ - /* Record the dividing point between configurable and non-configurable edges for each node */ - vtr::vector node_num_non_configurable_in_edges_; - vtr::vector node_num_non_configurable_out_edges_; - - /* Record the dividing point between input and output edges for each node - * Both input and output edges are stored in a list for memory efficiency - * We use a dividing point to identify the groups - * The edges are arranged in as the following format: - * Index in list: - * 0--------------------------------------------------------------------------------------------------->N - * - * |<----------------------->|^ |<------------------------->| - * node_num_non_cinfigurable_in_edges | node_num_non_configurable_out_edges - * | - * node_num_in_edges - */ - vtr::vector node_num_in_edges_; - vtr::vector> node_inout_edges_; + + /* + * We store the edges assoicated with each node in a single array per node (for memory efficiency). + * + * The array of edges is sorted into sub-ranges to allow for easy iteration (with node_in_edges(), + * node_non_configurable_out_edges() etc.). + * + * For a particular 'node' we store the sizes of the various sub-ranges in the node_num_* members, + * from which the delimiters for each sub-range can be calculated. + * + * + * node_edges_[node]: + * + * + * node_num_non_configurable_in_edges_[node] node_num_non_configurable_out_edges_[node] + * <-------------------> <--------------------> + * + * +------------------+---------------------+------------------+----------------------+ + * | in_edges_config | in_edges_non_config | out_edges_config | out_edges_non_config | + * +------------------+---------------------+------------------+----------------------+ + * + * <--------------------------------------> <---------------------------------------> + * node_num_in_edges_[node] node_num_out_edges_[node] + * + * All elements of node_edges_ should be initialized after all edges have been created (with create_edge()), + * by calling rebuild_node_edges(), which will allocate node_edges_, add the relevant edges and partition + * each node's arrays into the appropriate. rebuild_node_edges() also initializes all the node_num_* members + * based on the edges (created with create_edge()) in the edge_* members. + */ + vtr::vector node_num_in_edges_; + vtr::vector node_num_out_edges_; + vtr::vector node_num_non_configurable_in_edges_; + vtr::vector node_num_non_configurable_out_edges_; + vtr::vector> node_edges_; /* Edge related data */ - size_t num_edges_; /* Range of edge ids */ + size_t num_edges_; /* Range of edge ids */ std::unordered_set invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; diff --git a/vpr/src/device/rr_graph_obj_utils.h b/vpr/src/device/rr_graph_obj_utils.h index 910b0ce3acd..5c3a8f6d6a6 100644 --- a/vpr/src/device/rr_graph_obj_utils.h +++ b/vpr/src/device/rr_graph_obj_utils.h @@ -38,6 +38,16 @@ bool all_valid(const Container& values) { return true; } +template +bool all_valid(Iterator begin, Iterator end) { + for (auto itr = begin; itr != end; ++itr) { + if (!*itr) { + return false; + } + } + return true; +} + //Builds a mapping from old to new ids by skipping values marked invalid template Container compress_ids(const Container& ids) { @@ -162,4 +172,20 @@ ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer return updated; } +template +void update_valid_refs(Iterator begin, Iterator end, const IdContainer& id_map) { + for (auto itr = begin; itr != end; ++itr) { + auto orig_val = *itr; + if (orig_val) { + //Original item valid + + auto new_val = id_map[orig_val]; + if (new_val) { + //The original item exists in the new mapping + *itr = new_val; + } + } + } +} + #endif From 7898667663e5df33aa6a336eaf837eb328872061 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 13:37:49 -0500 Subject: [PATCH 26/58] vpr: Remove RRGraph::node_num_*edge() data members. Instead clients should use the .size() member of the relevant range. --- vpr/src/device/rr_graph_obj.cpp | 34 --------------------------------- vpr/src/device/rr_graph_obj.h | 12 ------------ 2 files changed, 46 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 59907c4cdec..2df4a77bfa5 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -203,40 +203,6 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { return node_segments_[node]; } -/* - * Get the number of configurable input edges of a node - */ -short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { - return node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; -} - -/* - * Get the number of configurable output edges of a node - */ -short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_num_out_edges_[node] - node_num_non_configurable_in_edges_[node]; -} - -/* - * Get the number of non-configurable input edges of a node - * Use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const { - return node_num_non_configurable_in_edges_[node]; -} - -/* - * Get the number of non-configurable output edges of a node - * Use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { - return node_num_non_configurable_out_edges_[node]; -} - RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index d20203bf920..4ffbe3daf2d 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -458,18 +458,6 @@ class RRGraph { */ RRSegmentId node_segment(const RRNodeId& node) const; - /* Get the number of non-configurable incoming edges to a node */ - short node_num_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable outgoing edges from a node */ - short node_num_non_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of configurable output edges of a node */ - short node_num_configurable_out_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable output edges of a node */ - short node_num_non_configurable_out_edges(const RRNodeId& node) const; - //Returns an iterable range of all edges (incoming & outgoing) for //the specified node edge_range node_edges(const RRNodeId& node) const; From 2854baa3881e8dfdc7ef53e888a83e8a4f3ef33c Mon Sep 17 00:00:00 2001 From: kmurray Date: Mon, 25 Nov 2019 11:54:41 -0500 Subject: [PATCH 27/58] flow: Pretty print upgraded architectures by default --- vtr_flow/scripts/upgrade_arch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtr_flow/scripts/upgrade_arch.py b/vtr_flow/scripts/upgrade_arch.py index 3ffbefdb3a2..2ea9f6510aa 100755 --- a/vtr_flow/scripts/upgrade_arch.py +++ b/vtr_flow/scripts/upgrade_arch.py @@ -53,7 +53,7 @@ def parse_args(): choices=supported_upgrades, default=supported_upgrades) parser.add_argument("--debug", default=False, action="store_true", help="Print to stdout instead of modifying file inplace") - parser.add_argument("--pretty", default=False, action="store_true", help="Pretty print the output?") + parser.add_argument("--pretty", default=True, help="Pretty print the output? (default: %(default)s)") return parser.parse_args() From a2c37c91c9836429efe18a8bd6fd68bc656e32b7 Mon Sep 17 00:00:00 2001 From: kmurray Date: Mon, 25 Nov 2019 12:00:00 -0500 Subject: [PATCH 28/58] flow: Automatically run upgrade_arch.py on titan architectures This will attempt to automatically upgrade the architecture files from the Titan benchmark release, which should decrease the forced coupling required between VTR and Titan releases. --- vtr_flow/scripts/download_titan.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vtr_flow/scripts/download_titan.py b/vtr_flow/scripts/download_titan.py index 400c34822d4..840af89858f 100755 --- a/vtr_flow/scripts/download_titan.py +++ b/vtr_flow/scripts/download_titan.py @@ -59,6 +59,10 @@ def parse_args(): choices=["eecg", "google"], help="Download mirror") + parser.add_argument("--upgrade_archs", + default=True, + help="Try to upgrade included architecture files (using the upgrade_archs.py)") + return parser.parse_args() def main(): @@ -178,6 +182,8 @@ def extract_to_vtr_flow_dir(args, tar_gz_filename): titan_other_benchmarks_extract_dir = os.path.join(benchmarks_dir, 'titan_other_blif') titan_arch_extract_dir = os.path.join(arch_dir, 'titan') + arch_upgrade_script = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'upgrade_arch.py') + if not args.force: #Check that all expected directories exist expected_dirs = [args.vtr_flow_dir, benchmarks_dir, arch_dir, titan_benchmarks_extract_dir, titan_arch_extract_dir] @@ -208,6 +214,12 @@ def extract_to_vtr_flow_dir(args, tar_gz_filename): dst_file_path = os.path.join(titan_other_benchmarks_extract_dir, filename) else: assert filename.endswith(".xml") + + if args.upgrade_archs: + #Apply the Architecture XML upgrade script + print "Upgrading architecture file:" + os.system("{} {}".format(arch_upgrade_script, src_file_path)) + dst_file_path = os.path.join(titan_arch_extract_dir, filename) shutil.move(src_file_path, dst_file_path) From 0a8dcf10219ceecb9d0b3e304cd0e987faea9c17 Mon Sep 17 00:00:00 2001 From: kmurray Date: Mon, 25 Nov 2019 15:00:49 -0500 Subject: [PATCH 29/58] flow: Update titan benchmarks version --- vtr_flow/scripts/download_titan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtr_flow/scripts/download_titan.py b/vtr_flow/scripts/download_titan.py index 840af89858f..907e536d971 100755 --- a/vtr_flow/scripts/download_titan.py +++ b/vtr_flow/scripts/download_titan.py @@ -41,7 +41,7 @@ def parse_args(): ) parser.add_argument("--titan_version", - default="1.3.0", + default="1.3.1", help="Titan release version to download") parser.add_argument("--vtr_flow_dir", required=True, From f265da929a5722603ec693bf6bc05b2d39fa3cc3 Mon Sep 17 00:00:00 2001 From: kmurray Date: Mon, 25 Nov 2019 15:33:31 -0500 Subject: [PATCH 30/58] flow: Add murax & picosoc Symbiflow benchmarks to nightly regressions --- .../titan_other/config/config.txt | 2 + .../titan_other/config/golden_results.txt | 46 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/config.txt index 7b96f2c8eb7..69b4a9d53fe 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/config.txt @@ -31,6 +31,8 @@ circuit_list_add=SURF_desc_stratixiv_arch_timing.blif circuit_list_add=ucsb_152_tap_fir_stratixiv_arch_timing.blif circuit_list_add=uoft_raytracer_stratixiv_arch_timing.blif circuit_list_add=wb_conmax_stratixiv_arch_timing.blif +circuit_list_add=picosoc_stratixiv_arch_timing.blif +circuit_list_add=murax_stratixiv_arch_timing.blif # Add architectures to list to sweep arch_list_add=stratixiv_arch.timing.xml diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/golden_results.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/golden_results.txt index 042d489f5e7..64b492dde8d 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/golden_results.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly/titan_other/config/golden_results.txt @@ -1,22 +1,24 @@ -arch circuit script_params vtr_flow_elapsed_time error num_io num_LAB num_DSP num_M9K num_M144K num_PLL vpr_revision vpr_status max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_time placed_wirelength_est place_time placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est routed_wirelength total_nets_routed total_connections_routed total_heap_pushes total_heap_pops logic_block_area_total logic_block_area_used routing_area_total routing_area_per_tile crit_path_route_success_iteration critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS crit_path_route_time -stratixiv_arch.timing.xml carpat_stratixiv_arch_timing.blif common 362.80 274 975 36 59 0 2 v8.0.0-rc1-1092-gb22604c1a success 1921084 22 252 53002 29055 7 24687 1346 89 66 5874 DSP auto 22.98 247302 269.19 7.53847 -70602 -7.53847 339560 62666 123122 225890989 53645423 0 0 1.14511e+08 19494.6 17 8.08469 -75512.8 -8.08469 0 0 40.80 -stratixiv_arch.timing.xml CH_DFSIN_stratixiv_arch_timing.blif common 347.40 36 1578 10 10 0 0 v8.0.0-rc1-1092-gb22604c1a success 1475420 3 33 48977 39238 1 25492 1634 54 40 2160 LAB auto 57.82 301283 234.83 77.1476 -113037 -77.1476 384546 75111 199234 210864935 30857019 0 0 4.19619e+07 19426.8 22 72.384 -149884 -72.384 0 0 33.44 -stratixiv_arch.timing.xml CHERI_stratixiv_arch_timing.blif common 599.02 211 2260 3 210 0 0 v8.0.0-rc1-1092-gb22604c1a success 2018732 38 173 62895 59067 3 36192 2684 86 64 5504 M9K auto 124.29 666278 367.26 12.9152 -424937 -12.9152 904540 142059 499287 446787334 64126874 0 0 1.07278e+08 19491.0 23 13.4989 -476720 -13.4989 0 0 71.96 -stratixiv_arch.timing.xml EKF-SLAM_Jacobians_stratixiv_arch_timing.blif common 685.84 574 2801 16 0 0 0 v8.0.0-rc1-1092-gb22604c1a success 2183676 4 570 66175 54803 2 39598 3391 90 67 6030 io auto 105.44 671330 386.44 28.2069 -121190 -28.2069 938899 180688 701176 844979745 141433421 0 0 1.17551e+08 19494.3 24 29.8963 -136786 -29.8963 0 0 158.14 -stratixiv_arch.timing.xml fir_cascade_stratixiv_arch_timing.blif common 997.12 40 3627 172 1 0 0 v8.0.0-rc1-1092-gb22604c1a success 5669748 19 21 171111 96274 1 72773 3840 194 144 27936 DSP auto 82.76 735672 758.44 4.76352 -299468 -4.76352 862954 132669 161562 288286106 60410740 0 0 5.45834e+08 19538.7 13 5.16904 -322497 -5.16904 0 0 62.60 -stratixiv_arch.timing.xml jacobi_stratixiv_arch_timing.blif common 431.72 536 1970 7 4 0 0 v8.0.0-rc1-1092-gb22604c1a success 1755592 227 309 49176 40422 1 28287 2517 84 62 5208 io auto 75.05 308908 300.52 198.378 -155165 -198.378 403197 75020 232264 199565007 23473025 0 0 1.01410e+08 19471.9 18 192.361 -184608 -192.361 0 0 26.23 -stratixiv_arch.timing.xml JPEG_stratixiv_arch_timing.blif common 323.44 36 1333 8 149 2 0 v8.0.0-rc1-1092-gb22604c1a success 1635728 3 33 52402 39411 1 28111 1528 73 54 3942 M9K auto 57.40 341735 202.06 17.2121 -372726 -17.2121 454111 80161 198143 221562036 35152566 0 0 7.68908e+07 19505.5 19 18.4783 -409378 -18.4783 0 0 36.88 -stratixiv_arch.timing.xml leon2_stratixiv_arch_timing.blif common 108.53 251 962 1 17 0 0 v8.0.0-rc1-1092-gb22604c1a success 1089052 55 196 20132 19957 1 8489 1231 43 32 1376 io LAB auto 34.55 119730 48.28 7.62646 -101721 -7.62646 170866 22905 91912 81521998 9349269 0 0 2.65578e+07 19300.7 11 8.5 -110502 -8.5 0 0 8.93 -stratixiv_arch.timing.xml leon3mp_stratixiv_arch_timing.blif common 253.57 255 2103 1 28 0 0 v8.0.0-rc1-1092-gb22604c1a success 1457916 84 171 36458 36247 3 20430 2387 62 46 2852 LAB auto 70.39 295949 142.22 12.5487 -110901 -12.5487 401354 52798 182051 138628997 16136391 0 0 5.55485e+07 19477.0 13 13.9184 -123889 -13.9184 0 0 18.14 -stratixiv_arch.timing.xml MCML_stratixiv_arch_timing.blif common 414.56 69 2126 10 295 16 0 v8.0.0-rc1-1092-gb22604c1a success 2109248 36 33 57796 49182 1 20066 2516 105 78 8190 M9K auto 61.52 254102 269.49 8.76505 -179533 -8.76505 415796 55678 148348 217393015 40806309 0 0 1.60352e+08 19579.0 17 8.84615 -236971 -8.84615 0 0 45.43 -stratixiv_arch.timing.xml MMM_stratixiv_arch_timing.blif common 355.67 478 1249 1 300 4 0 v8.0.0-rc1-1092-gb22604c1a success 1850772 202 276 35125 30509 3 21545 2032 106 79 8374 M9K auto 52.47 269667 232.88 9.30878 -112098 -9.30878 410683 50206 136904 194081070 34749500 0 0 1.63945e+08 19577.8 15 9.85381 -125628 -9.85381 0 0 34.39 -stratixiv_arch.timing.xml radar20_stratixiv_arch_timing.blif common 183.49 5 332 31 105 0 2 v8.0.0-rc1-1092-gb22604c1a success 1448772 3 2 14862 10304 26 7587 475 89 66 5874 DSP auto 26.46 121572 119.91 5.78307 -68289.9 -5.78307 177639 17043 35857 52997427 10378106 0 0 1.14511e+08 19494.6 11 6.10098 -80159.9 -6.10098 0 0 10.46 -stratixiv_arch.timing.xml random_stratixiv_arch_timing.blif common 447.89 693 1767 25 16 0 0 v8.0.0-rc1-1092-gb22604c1a success 2112824 35 658 51416 37539 1 27766 2501 107 79 8453 io auto 56.13 261009 324.29 39.2138 -74576 -39.2138 351442 65635 189849 207005380 34587838 0 0 1.65513e+08 19580.3 17 39.762 -80279.4 -39.762 0 0 29.88 -stratixiv_arch.timing.xml Reed_Solomon_stratixiv_arch_timing.blif common 309.26 753 1119 5 32 0 0 v8.0.0-rc1-1092-gb22604c1a success 1933516 13 740 25173 25306 1 12702 1909 116 86 9976 io auto 43.15 159543 218.06 8.87249 -53834.9 -8.87249 207125 26542 97351 77913812 9238903 0 0 1.95789e+08 19626.0 12 9.82172 -58557.3 -9.82172 0 0 10.25 -stratixiv_arch.timing.xml smithwaterman_stratixiv_arch_timing.blif common 355.08 117 2107 0 0 0 0 v8.0.0-rc1-1092-gb22604c1a success 1631436 79 38 66795 54922 1 36742 2224 62 46 2852 LAB auto 61.27 301059 249.33 10.2147 -194780 -10.2147 403345 92956 193982 160603004 18869471 0 0 5.55485e+07 19477.0 16 11.2024 -228462 -11.2024 0 0 21.01 -stratixiv_arch.timing.xml stap_steering_stratixiv_arch_timing.blif common 256.20 213 1560 26 4 0 0 v8.0.0-rc1-1092-gb22604c1a success 1813184 139 74 57121 41054 1 24137 1803 75 56 4200 DSP auto 48.46 174848 162.12 5.83415 -78074.1 -5.83415 232518 50058 89413 114733821 22043970 0 0 8.19675e+07 19516.1 13 6.42913 -84534.6 -6.42913 0 0 19.23 -stratixiv_arch.timing.xml sudoku_check_stratixiv_arch_timing.blif common 105.43 54 680 0 40 0 1 v8.0.0-rc1-1092-gb22604c1a success 1081300 2 52 16673 16662 2 12058 775 38 28 1064 LAB auto 28.20 180644 42.33 5.72679 -40652.3 -5.72679 237236 47460 147343 150367852 20774500 0 0 2.04926e+07 19260.0 16 6.28333 -46223.3 -6.28333 0 0 19.31 -stratixiv_arch.timing.xml SURF_desc_stratixiv_arch_timing.blif common 392.81 445 2178 19 53 0 0 v8.0.0-rc1-1092-gb22604c1a success 1844836 131 314 57881 45152 1 32522 2695 71 53 3763 io auto 65.18 317897 266.86 194.693 -90036.8 -194.693 420073 83018 240981 220094336 29019829 0 0 7.34110e+07 19508.6 21 188.547 -100555 -188.547 0 0 33.26 -stratixiv_arch.timing.xml ucsb_152_tap_fir_stratixiv_arch_timing.blif common 66.40 42 753 0 0 0 0 v8.0.0-rc1-1092-gb22604c1a success 1011108 13 29 26295 20086 1 12415 795 39 29 1131 LAB auto 9.65 80370 40.06 4.8494 -14201.6 -4.8494 83423 24866 32259 28860263 3251424 0 0 2.17765e+07 19254.2 13 4.97188 -15343.1 -4.97188 0 0 3.40 -stratixiv_arch.timing.xml uoft_raytracer_stratixiv_arch_timing.blif common 522.08 964 975 19 34 0 0 v8.0.0-rc1-1092-gb22604c1a success 2571100 542 422 37341 26102 1 20643 1992 146 108 15768 io auto 39.43 268703 406.25 8.28683 -69299.5 -8.28683 348811 60221 132320 171562070 33704288 0 0 3.10255e+08 19676.2 16 8.90162 -77366.1 -8.90162 0 0 26.20 -stratixiv_arch.timing.xml wb_conmax_stratixiv_arch_timing.blif common 513.40 1107 724 0 0 0 0 v8.0.0-rc1-1092-gb22604c1a success 2995884 403 704 15490 16194 1 8396 1831 166 123 20418 io auto 34.14 192263 413.30 11.5314 -25344 -11.5314 233605 20329 78036 57616624 6472047 0 0 4.01631e+08 19670.5 13 12.1687 -29599.5 -12.1687 0 0 7.93 +arch circuit script_params vtr_flow_elapsed_time error num_io num_LAB num_DSP num_M9K num_M144K num_PLL vpr_revision vpr_status max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_time placed_wirelength_est place_time placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est routed_wirelength total_nets_routed total_connections_routed total_heap_pushes total_heap_pops logic_block_area_total logic_block_area_used routing_area_total routing_area_per_tile crit_path_route_success_iteration critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS crit_path_route_time +stratixiv_arch.timing.xml carpat_stratixiv_arch_timing.blif common 338.28 274 975 36 59 0 2 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1919964 22 252 53002 29055 7 24687 1346 89 66 5874 DSP auto 22.54 247302 244.57 7.53847 -70602 -7.53847 339678 62804 123496 227319798 53989440 0 0 1.14511e+08 19494.6 17 8.08469 -75504.1 -8.08469 0 0 40.94 +stratixiv_arch.timing.xml CH_DFSIN_stratixiv_arch_timing.blif common 333.75 36 1578 10 10 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1475128 3 33 48977 39238 1 25492 1634 54 40 2160 LAB auto 57.51 301283 219.62 77.1476 -113037 -77.1476 384809 77195 203500 214695259 31342194 0 0 4.19619e+07 19426.8 22 72.3848 -157579 -72.3848 0 0 34.16 +stratixiv_arch.timing.xml CHERI_stratixiv_arch_timing.blif common 579.42 211 2260 3 210 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 2018440 38 173 62895 59067 3 36192 2684 86 64 5504 M9K auto 124.65 666278 347.07 12.9152 -424937 -12.9152 904540 142059 499287 446787334 64126874 0 0 1.07278e+08 19491.0 23 13.4989 -476720 -13.4989 0 0 70.80 +stratixiv_arch.timing.xml EKF-SLAM_Jacobians_stratixiv_arch_timing.blif common 673.38 574 2801 16 0 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 2182172 4 570 66175 54803 2 39598 3391 90 67 6030 io auto 106.34 671330 370.14 28.2069 -121190 -28.2069 940236 193031 766120 902530828 151446683 0 0 1.17551e+08 19494.3 23 29.8956 -136530 -29.8956 0 0 159.98 +stratixiv_arch.timing.xml fir_cascade_stratixiv_arch_timing.blif common 965.00 40 3627 172 1 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 5669200 19 21 171111 96274 1 72773 3840 194 144 27936 DSP auto 83.03 735672 725.66 4.76352 -299468 -4.76352 862954 132669 161562 288286106 60410740 0 0 5.45834e+08 19538.7 13 5.16904 -322497 -5.16904 0 0 60.47 +stratixiv_arch.timing.xml jacobi_stratixiv_arch_timing.blif common 421.89 536 1970 7 4 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1754976 227 309 49176 40422 1 28287 2517 84 62 5208 io auto 74.75 308908 289.11 198.378 -155165 -198.378 403221 75506 233406 200583064 23577488 0 0 1.01410e+08 19471.9 18 192.339 -184625 -192.339 0 0 26.96 +stratixiv_arch.timing.xml JPEG_stratixiv_arch_timing.blif common 314.28 36 1333 8 149 2 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1634988 3 33 52402 39411 1 28111 1528 73 54 3942 M9K auto 57.04 341735 192.26 17.2121 -372726 -17.2121 454807 80372 200417 224638148 35740470 0 0 7.68908e+07 19505.5 17 18.4622 -409411 -18.4622 0 0 37.02 +stratixiv_arch.timing.xml leon2_stratixiv_arch_timing.blif common 103.45 251 962 1 17 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1088648 55 196 20132 19957 1 8489 1231 43 32 1376 io LAB auto 34.56 119730 43.61 7.62646 -101721 -7.62646 171107 23140 92616 82228963 9460502 0 0 2.65578e+07 19300.7 12 8.5 -110418 -8.5 0 0 9.36 +stratixiv_arch.timing.xml leon3mp_stratixiv_arch_timing.blif common 245.84 255 2103 1 28 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1457404 84 171 36458 36247 3 20430 2387 62 46 2852 LAB auto 72.30 295949 131.56 12.5487 -110901 -12.5487 401336 53586 184553 140609347 16373646 0 0 5.55485e+07 19477.0 13 13.9184 -123800 -13.9184 0 0 18.75 +stratixiv_arch.timing.xml MCML_stratixiv_arch_timing.blif common 400.85 69 2126 10 295 16 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 2108456 36 33 57796 49182 1 20066 2516 105 78 8190 M9K auto 61.96 254102 253.56 8.76505 -179533 -8.76505 415796 55678 148348 217393015 40806309 0 0 1.60352e+08 19579.0 17 8.84615 -236971 -8.84615 0 0 46.43 +stratixiv_arch.timing.xml MMM_stratixiv_arch_timing.blif common 348.51 478 1249 1 300 4 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1849960 202 276 35125 30509 3 21545 2032 106 79 8374 M9K auto 53.58 269667 223.28 9.30878 -112098 -9.30878 410683 50206 136904 194081070 34749500 0 0 1.63945e+08 19577.8 15 9.85381 -125628 -9.85381 0 0 35.17 +stratixiv_arch.timing.xml radar20_stratixiv_arch_timing.blif common 178.37 5 332 31 105 0 2 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1448264 3 2 14862 10304 26 7587 475 89 66 5874 DSP auto 26.33 121572 114.74 5.78307 -68289.9 -5.78307 177639 17043 35857 52997427 10378106 0 0 1.14511e+08 19494.6 11 6.10098 -80159.9 -6.10098 0 0 10.59 +stratixiv_arch.timing.xml random_stratixiv_arch_timing.blif common 441.29 693 1767 25 16 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 2112392 35 658 51416 37539 1 27766 2501 107 79 8453 io auto 56.34 261009 317.36 39.2138 -74576 -39.2138 351426 66439 191966 209971537 35338726 0 0 1.65513e+08 19580.3 17 39.762 -80278.4 -39.762 0 0 29.86 +stratixiv_arch.timing.xml Reed_Solomon_stratixiv_arch_timing.blif common 310.16 753 1119 5 32 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1932928 13 740 25173 25306 1 12702 1909 116 86 9976 io auto 43.80 159543 217.79 8.87249 -53834.9 -8.87249 207125 26542 97351 77913812 9238903 0 0 1.95789e+08 19626.0 12 9.82172 -58557.3 -9.82172 0 0 10.43 +stratixiv_arch.timing.xml smithwaterman_stratixiv_arch_timing.blif common 356.19 117 2107 0 0 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1630956 79 38 66795 54922 1 36742 2224 62 46 2852 LAB auto 62.29 301059 248.22 10.2147 -194780 -10.2147 403567 93627 195637 162353359 19226014 0 0 5.55485e+07 19477.0 16 11.2408 -228073 -11.2408 0 0 21.64 +stratixiv_arch.timing.xml stap_steering_stratixiv_arch_timing.blif common 257.61 213 1560 26 4 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1812712 139 74 57121 41054 1 24137 1803 75 56 4200 DSP auto 50.73 174848 159.15 5.83415 -78074.1 -5.83415 232522 50334 90407 120906551 23695418 0 0 8.19675e+07 19516.1 14 6.42913 -84548.8 -6.42913 0 0 21.22 +stratixiv_arch.timing.xml sudoku_check_stratixiv_arch_timing.blif common 107.39 54 680 0 40 0 1 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1080824 2 52 16673 16662 2 12058 775 38 28 1064 LAB auto 28.72 180644 43.08 5.72679 -40652.3 -5.72679 238131 47422 147613 150776326 20843740 0 0 2.04926e+07 19260.0 16 6.27823 -46114.2 -6.27823 0 0 20.31 +stratixiv_arch.timing.xml SURF_desc_stratixiv_arch_timing.blif common 372.97 445 2178 19 53 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1844888 131 314 57881 45152 1 32522 2695 71 53 3763 io auto 67.86 317897 245.34 194.693 -90036.8 -194.693 420209 83538 241982 220976183 29120261 0 0 7.34110e+07 19508.6 21 188.391 -100554 -188.391 0 0 31.71 +stratixiv_arch.timing.xml ucsb_152_tap_fir_stratixiv_arch_timing.blif common 70.68 42 753 0 0 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1010572 13 29 26295 20086 1 12415 795 39 29 1131 LAB auto 9.94 80370 42.86 4.8494 -14201.6 -4.8494 83423 24866 32259 28860263 3251424 0 0 2.17765e+07 19254.2 13 4.97188 -15343.1 -4.97188 0 0 3.58 +stratixiv_arch.timing.xml uoft_raytracer_stratixiv_arch_timing.blif common 459.59 964 975 19 34 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 2570904 542 422 37341 26102 1 20643 1992 146 108 15768 io auto 41.00 268703 344.44 8.28683 -69299.5 -8.28683 348811 60221 132320 171562070 33704288 0 0 3.10255e+08 19676.2 16 8.90162 -77366.1 -8.90162 0 0 23.68 +stratixiv_arch.timing.xml wb_conmax_stratixiv_arch_timing.blif common 457.45 1107 724 0 0 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 2994940 403 704 15490 16194 1 8396 1831 166 123 20418 io auto 34.63 192263 358.34 11.5314 -25344 -11.5314 233605 20329 78036 57616624 6472047 0 0 4.01631e+08 19670.5 13 12.1687 -29599.5 -12.1687 0 0 7.34 +stratixiv_arch.timing.xml picosoc_stratixiv_arch_timing.blif common 85.62 35 728 0 6 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 1022192 18 17 16969 16357 1 6348 769 39 29 1131 LAB auto 36.09 82353 29.35 6.69186 -56782.9 -6.69186 112431 16636 70068 56582291 6241307 0 0 2.17765e+07 19254.2 14 6.90599 -62263.2 -6.90599 0 0 6.38 +stratixiv_arch.timing.xml murax_stratixiv_arch_timing.blif common 16.88 35 74 0 8 0 0 v8.0.0-rc1-1111-g8afe2abb6-dirty success 792864 18 17 2291 2142 1 1477 117 16 12 192 LAB M9K auto 3.86 10912 2.60 4.965 -7029.52 -4.965 14553 3223 7490 6872262 934411 0 0 3.53715e+06 18422.6 13 5.16652 -7447.09 -5.16652 0 0 0.80 From 11f719a4ec150182c6795541dde127585c2d67ba Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 25 Nov 2019 21:20:12 -0700 Subject: [PATCH 31/58] add malloc_trim to have clean memory stats when building rr_graph --- vpr/src/device/create_rr_graph.cpp | 4 ++++ vpr/src/route/rr_graph.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 6faced34b31..ecd9501a6c1 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -4,6 +4,7 @@ /* EXTERNAL library header files go second*/ #include "vtr_assert.h" #include "vtr_time.h" +#include "vtr_memory.h" /* VPR header files go then */ #include "vpr_types.h" @@ -25,6 +26,9 @@ void convert_rr_graph(std::vector& vpr_segments) { vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); + /* Release freed memory before start building rr_graph */ + vtr::malloc_trim(0); + /* IMPORTANT: to build clock tree, * vpr added segments to the original arch segments * This is why to use vpr_segments as an inputs!!! diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 12b3a101401..a50c7da7fe4 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -437,6 +437,9 @@ static void build_rr_graph(const t_graph_type graph_type, int* Warnings) { vtr::ScopedStartFinishTimer timer("Build routing resource graph"); + /* Release freed memory before start building rr_graph */ + vtr::malloc_trim(0); + /* Reset warning flag */ *Warnings = RR_GRAPH_NO_WARN; From 3ac57f5adc6daebf88e1159bb1ea09e09f67e75e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 15 Nov 2019 12:14:45 -0700 Subject: [PATCH 32/58] add create rr_graph_obj function which loads rr_nodes to the object --- libs/libvtrutil/src/vtr_geometry.h | 1 + libs/libvtrutil/src/vtr_geometry.tpp | 10 ++ vpr/src/base/vpr_context.h | 4 + vpr/src/device/check_rr_graph_obj.cpp | 19 ++- vpr/src/device/create_rr_graph.cpp | 149 +++++++++++++++++++++++ vpr/src/device/create_rr_graph.h | 17 +++ vpr/src/device/rr_graph_obj.cpp | 14 +-- vpr/src/route/rr_graph.cpp | 4 + vpr/src/util/rr_graph_obj_util.cpp | 30 +++++ vpr/src/util/rr_graph_obj_util.h | 14 +++ vpr/src/util/rr_graph_obj_utils.h | 165 ++++++++++++++++++++++++++ 11 files changed, 407 insertions(+), 20 deletions(-) create mode 100644 vpr/src/device/create_rr_graph.cpp create mode 100644 vpr/src/device/create_rr_graph.h create mode 100644 vpr/src/util/rr_graph_obj_util.cpp create mode 100644 vpr/src/util/rr_graph_obj_util.h create mode 100644 vpr/src/util/rr_graph_obj_utils.h diff --git a/libs/libvtrutil/src/vtr_geometry.h b/libs/libvtrutil/src/vtr_geometry.h index 65c53ecea65..cc8be19c139 100644 --- a/libs/libvtrutil/src/vtr_geometry.h +++ b/libs/libvtrutil/src/vtr_geometry.h @@ -48,6 +48,7 @@ template class Point { public: //Constructors Point(T x_val, T y_val) noexcept; + Point(); public: //Accessors //Coordinates diff --git a/libs/libvtrutil/src/vtr_geometry.tpp b/libs/libvtrutil/src/vtr_geometry.tpp index a1a852850c1..1517bcfc699 100644 --- a/libs/libvtrutil/src/vtr_geometry.tpp +++ b/libs/libvtrutil/src/vtr_geometry.tpp @@ -10,6 +10,11 @@ Point::Point(T x_val, T y_val) noexcept //pass } +template +Point::Point() { + //pass +} + template T Point::x() const { return x_; @@ -74,6 +79,11 @@ Rect::Rect(Point bottom_left_val, Point top_right_val) //pass } +template +Rect::Rect() { + //pass +} + template T Rect::xmin() const { return bottom_left_.x(); diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index 40a81bb41b5..00811f29496 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -21,6 +21,7 @@ #include "router_lookahead.h" #include "place_macro.h" #include "compressed_grid.h" +#include "rr_graph_obj.h" //A Context is collection of state relating to a particular part of VPR // @@ -136,6 +137,9 @@ struct DeviceContext : public Context { /* chan_width is for x|y-directed channels; i.e. between rows */ t_chan_width chan_width; + /* Object to define routing resources */ + RRGraph rr_graph; + /* Structures to define the routing architecture of the FPGA. */ std::vector rr_nodes; /* autogenerated in build_rr_graph */ diff --git a/vpr/src/device/check_rr_graph_obj.cpp b/vpr/src/device/check_rr_graph_obj.cpp index 253092fb730..69c772fcbf7 100644 --- a/vpr/src/device/check_rr_graph_obj.cpp +++ b/vpr/src/device/check_rr_graph_obj.cpp @@ -107,7 +107,7 @@ static bool check_rr_graph_source_nodes(const RRGraph& rr_graph) { } } - return invalid_sources; + return !invalid_sources; } /*********************************************************************** @@ -136,7 +136,7 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { } } - return invalid_sinks; + return !invalid_sinks; } /*********************************************************************** @@ -153,48 +153,43 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { * will work properly. **********************************************************************/ bool check_rr_graph(const RRGraph& rr_graph) { - bool check_flag = true; size_t num_err = 0; if (false == check_rr_graph_duplicated_edges(rr_graph)) { VTR_LOG_WARN("Fail in checking duplicated edges !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_dangling_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking dangling nodes !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp new file mode 100644 index 00000000000..e57c536ce2c --- /dev/null +++ b/vpr/src/device/create_rr_graph.cpp @@ -0,0 +1,149 @@ +/* Standard header files required go first */ +#include + +/* EXTERNAL library header files go second*/ +#include "vtr_assert.h" +#include "vtr_time.h" + +/* VPR header files go then */ +#include "vpr_types.h" +#include "rr_graph_obj.h" +#include "check_rr_graph_obj.h" +#include "create_rr_graph.h" + +/* Finally we include global variables */ +#include "globals.h" + +/******************************************************************** + * TODO: remove when this conversion (from traditional to new data structure) + * is no longer needed + * This function will convert an existing rr_graph in device_ctx to the RRGraph + *object + * This function is used to test our RRGraph if it is acceptable in downstream + *routers + ********************************************************************/ +void convert_rr_graph(std::vector& vpr_segments) { + vtr::ScopedStartFinishTimer timer("Build routing resource graph object"); + + /* IMPORTANT: to build clock tree, + * vpr added segments to the original arch segments + * This is why to use vpr_segments as an inputs!!! + */ + auto& device_ctx = g_vpr_ctx.mutable_device(); + + /* make sure we have a clean empty rr_graph */ + device_ctx.rr_graph.clear(); + + /* The number of switches are in general small, + * reserve switches may not bring significant memory efficiency + * So, we just use create_switch to push_back each time + */ + device_ctx.rr_graph.reserve_switches(device_ctx.rr_switch_inf.size()); + // Create the switches + for (size_t iswitch = 0; iswitch < device_ctx.rr_switch_inf.size(); ++iswitch) { + device_ctx.rr_graph.create_switch(device_ctx.rr_switch_inf[iswitch]); + } + + /* The number of segments are in general small, reserve segments may not bring + * significant memory efficiency */ + device_ctx.rr_graph.reserve_segments(vpr_segments.size()); + // Create the segments + for (size_t iseg = 0; iseg < vpr_segments.size(); ++iseg) { + device_ctx.rr_graph.create_segment(vpr_segments[iseg]); + } + + /* Reserve list of nodes to be memory efficient */ + device_ctx.rr_graph.reserve_nodes(device_ctx.rr_nodes.size()); + + // Create the nodes + std::map old_to_new_rr_node; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + auto& node = device_ctx.rr_nodes[inode]; + RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); + + device_ctx.rr_graph.set_node_xlow(rr_node, node.xlow()); + device_ctx.rr_graph.set_node_ylow(rr_node, node.ylow()); + device_ctx.rr_graph.set_node_xhigh(rr_node, node.xhigh()); + device_ctx.rr_graph.set_node_yhigh(rr_node, node.yhigh()); + + device_ctx.rr_graph.set_node_capacity(rr_node, node.capacity()); + + device_ctx.rr_graph.set_node_ptc_num(rr_node, node.ptc_num()); + + device_ctx.rr_graph.set_node_cost_index(rr_node, node.cost_index()); + + if (CHANX == node.type() || CHANY == node.type()) { + device_ctx.rr_graph.set_node_direction(rr_node, node.direction()); + } + if (IPIN == node.type() || OPIN == node.type()) { + device_ctx.rr_graph.set_node_side(rr_node, node.side()); + } + device_ctx.rr_graph.set_node_R(rr_node, node.R()); + device_ctx.rr_graph.set_node_C(rr_node, node.C()); + + /* Set up segment id */ + short irc_data = node.cost_index(); + short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; + device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); + + VTR_ASSERT(!old_to_new_rr_node.count(inode)); + old_to_new_rr_node[inode] = rr_node; + } + + /* Reserve list of edges to be memory efficient */ + { + int num_edges_to_reserve = 0; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + num_edges_to_reserve += node.num_edges(); + } + device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); + } + + // Create the edges + std::map, RREdgeId> old_to_new_rr_edge; // Key: + // {inode,iedge} + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + for (int iedge = 0; iedge < node.num_edges(); ++iedge) { + int isink_node = node.edge_sink_node(iedge); + int iswitch = node.edge_switch(iedge); + + VTR_ASSERT(old_to_new_rr_node.count(inode)); + VTR_ASSERT(old_to_new_rr_node.count(isink_node)); + + RREdgeId rr_edge = device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], + old_to_new_rr_node[isink_node], + RRSwitchId(iswitch)); + + auto key = std::make_pair(inode, iedge); + VTR_ASSERT(!old_to_new_rr_edge.count(key)); + old_to_new_rr_edge[key] = rr_edge; + } + } + + /* Partition edges to be two class: configurable (1st part) and + * non-configurable (2nd part) + * See how the router will use the edges and determine the strategy + * if we want to partition the edges first or depends on the routing needs + */ + device_ctx.rr_graph.partition_edges(); + + /* Essential check for rr_graph, build look-up and */ + if (false == device_ctx.rr_graph.validate()) { + /* Error out if built-in validator of rr_graph fails */ + vpr_throw(VPR_ERROR_ROUTE, + __FILE__, + __LINE__, + "Fundamental errors occurred when validating rr_graph object!\n"); + } + + /* Error out if advanced checker of rr_graph fails */ + if (false == check_rr_graph(device_ctx.rr_graph)) { + vpr_throw(VPR_ERROR_ROUTE, + __FILE__, + __LINE__, + "Advanced checking rr_graph object fails! Routing may still work " + "but not smooth\n"); + } +} diff --git a/vpr/src/device/create_rr_graph.h b/vpr/src/device/create_rr_graph.h new file mode 100644 index 00000000000..5cc57ec924a --- /dev/null +++ b/vpr/src/device/create_rr_graph.h @@ -0,0 +1,17 @@ +#ifndef CREATE_RR_GRAPH_H +#define CREATE_RR_GRAPH_H + +/* + * Notes in include header files in a head file + * Only include the neccessary header files + * that is required by the data types in the function/class declarations! + */ +#include "rr_graph_obj.h" + +/* IMPORTANT: to build clock tree, + * vpr added segments to the original arch segments + * This is why to use vpr_segments as an inputs!!! + */ +void convert_rr_graph(std::vector& vpr_segments); + +#endif diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 0cd9c49e83f..53066e89aff 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -714,7 +714,6 @@ bool RRGraph::validate_edge_sink_nodes() const { * Warnings are thrown if optional checking fails */ bool RRGraph::validate() const { - bool check_flag = true; size_t num_err = 0; initialize_fast_node_lookup(); @@ -724,34 +723,32 @@ bool RRGraph::validate() const { */ if (false == validate_sizes()) { VTR_LOG_WARN("Fail in validating node- and edge-related vector sizes!\n"); - check_flag = false; num_err++; } /* Fundamental check */ if (false == validate_nodes_edges()) { VTR_LOG_WARN("Fail in validating edges connected to each node!\n"); - check_flag = false; num_err++; } if (false == validate_node_segments()) { VTR_LOG_WARN("Fail in validating segment IDs of nodes !\n"); - check_flag = false; num_err++; } if (false == validate_edge_switches()) { VTR_LOG_WARN("Fail in validating switch IDs of edges !\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } bool RRGraph::is_dirty() const { @@ -827,6 +824,7 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_sides_.push_back(NUM_SIDES); node_Rs_.push_back(0.); node_Cs_.push_back(0.); + node_segments_.push_back(RRSegmentId::INVALID()); node_in_edges_.emplace_back(); //Initially empty node_out_edges_.emplace_back(); //Initially empty diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 3aa6afd94a9..733ac6e41a4 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -33,6 +33,7 @@ #include "rr_graph_reader.h" #include "router_lookahead_map.h" #include "rr_graph_clock.h" +#include "create_rr_graph.h" #include "rr_types.h" @@ -375,6 +376,9 @@ void create_rr_graph(const t_graph_type graph_type, print_rr_graph_stats(); + /* Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); + //Write out rr graph file if needed if (!det_routing_arch->write_rr_graph_filename.empty()) { write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf); diff --git a/vpr/src/util/rr_graph_obj_util.cpp b/vpr/src/util/rr_graph_obj_util.cpp new file mode 100644 index 00000000000..d7f824421d0 --- /dev/null +++ b/vpr/src/util/rr_graph_obj_util.cpp @@ -0,0 +1,30 @@ +/**************************************************************************** + * This file include most-utilized functions that manipulate on the + * RRGraph object + ***************************************************************************/ +#include +#include "rr_graph_obj_util.h" + +/**************************************************************************** + * Find the switches interconnecting two nodes + * Return a vector of switch ids + ***************************************************************************/ +std::vector find_rr_graph_switches(const RRGraph& rr_graph, + const RRNodeId& from_node, + const RRNodeId& to_node) { + std::vector switches; + std::vector edges = rr_graph.find_edges(from_node, to_node); + if (true == edges.empty()) { + /* edge is open, we return an empty vector of switches */ + return switches; + } + + /* Reach here, edge list is not empty, find switch id one by one + * and update the switch list + */ + for (auto edge : edges) { + switches.push_back(rr_graph.edge_switch(edge)); + } + + return switches; +} diff --git a/vpr/src/util/rr_graph_obj_util.h b/vpr/src/util/rr_graph_obj_util.h new file mode 100644 index 00000000000..cade12c22ad --- /dev/null +++ b/vpr/src/util/rr_graph_obj_util.h @@ -0,0 +1,14 @@ +#ifndef RR_GRAPH_OBJ_UTIL_H +#define RR_GRAPH_OBJ_UTIL_H + +/* Include header files which include data structures used by + * the function declaration + */ +#include "rr_graph_obj.h" + +/* Get node-to-node switches in a RRGraph */ +std::vector find_rr_graph_switches(const RRGraph& rr_graph, + const RRNodeId& from_node, + const RRNodeId& to_node); + +#endif diff --git a/vpr/src/util/rr_graph_obj_utils.h b/vpr/src/util/rr_graph_obj_utils.h new file mode 100644 index 00000000000..910b0ce3acd --- /dev/null +++ b/vpr/src/util/rr_graph_obj_utils.h @@ -0,0 +1,165 @@ +#ifndef RR_GRAPH_OBJ_UTILS_H +#define RR_GRAPH_OBJ_UTILS_H + +/* Include header files which include data structures used by + * the function declaration + */ +#include +#include "vtr_vector_map.h" + +/* + * + * Templated utility functions for cleaning and reordering IdMaps + * + */ + +//Returns true if all elements are contiguously ascending values (i.e. equal to their index) +template +bool are_contiguous(const Container& values) { + using T = typename Container::value_type; + size_t i = 0; + for (T val : values) { + if (val != T(i)) { + return false; + } + ++i; + } + return true; +} + +//Returns true if all elements in the vector 'values' evaluate true +template +bool all_valid(const Container& values) { + for (auto val : values) { + if (!val) { + return false; + } + } + return true; +} + +//Builds a mapping from old to new ids by skipping values marked invalid +template +Container compress_ids(const Container& ids) { + using Id = typename Container::value_type; + Container id_map(ids.size()); + size_t i = 0; + for (auto id : ids) { + if (id) { + //Valid + id_map[id] = Id(i); + ++i; + } + } + + return id_map; +} + +//Returns a vector based on 'values', which has had entries dropped & re-ordered according according to 'id_map'. +//Each entry in id_map corresponds to the assoicated element in 'values'. +//The value of the id_map entry is the new ID of the entry in values. +// +//If it is an invalid ID, the element in values is dropped. +//Otherwise the element is moved to the new ID location. +template +ValueContainer clean_and_reorder_values(const ValueContainer& values, const IdContainer& id_map) { + using Id = typename IdContainer::value_type; + VTR_ASSERT(values.size() == id_map.size()); + + //Allocate space for the values that will not be dropped + ValueContainer result(values.size()); + + //Move over the valid entries to their new locations + size_t new_count = 0; + for (size_t cur_idx = 0; cur_idx < values.size(); ++cur_idx) { + Id old_id = Id(cur_idx); + + Id new_id = id_map[old_id]; + if (new_id) { + //There is a valid mapping + result[new_id] = std::move(values[old_id]); + ++new_count; + } + } + + result.resize(new_count); + + return result; +} + +//Returns the set of new valid Ids defined by 'id_map' +//TODO: merge with clean_and_reorder_values +template +Container clean_and_reorder_ids(const Container& id_map) { + //For IDs, the values are the new id's stored in the map + using Id = typename Container::value_type; + + //Allocate a new vector to store the values that have been not dropped + Container result(id_map.size()); + + //Move over the valid entries to their new locations + size_t new_count = 0; + for (size_t cur_idx = 0; cur_idx < id_map.size(); ++cur_idx) { + Id old_id = Id(cur_idx); + + Id new_id = id_map[old_id]; + if (new_id) { + result[new_id] = new_id; + ++new_count; + } + } + + result.resize(new_count); + + return result; +} + +//Count how many of the Id's referenced in 'range' have a valid +//new mapping in 'id_map' +template +size_t count_valid_refs(R range, const vtr::vector_map& id_map) { + size_t valid_count = 0; + + for (Id old_id : range) { + if (id_map[old_id]) { + ++valid_count; + } + } + + return valid_count; +} + +//Updates the Ids in 'values' based on id_map, even if the original or new mapping is not valid +template +Container update_all_refs(const Container& values, const vtr::vector_map& id_map) { + Container updated; + + for (ValId orig_val : values) { + //The original item was valid + ValId new_val = id_map[orig_val]; + //The original item exists in the new mapping + updated.emplace_back(new_val); + } + + return updated; +} + +template +ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer& id_map) { + ValueContainer updated; + + for (auto orig_val : values) { + if (orig_val) { + //Original item valid + + auto new_val = id_map[orig_val]; + if (new_val) { + //The original item exists in the new mapping + updated.emplace_back(new_val); + } + } + } + return updated; +} + +#endif From 6896e1b6f8af276c7b1f35a0342eaa8fa15bd449 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 17:35:34 -0700 Subject: [PATCH 33/58] add in/out edge reserve methods for RRGraph object --- vpr/src/device/create_rr_graph.cpp | 10 ++++++++++ vpr/src/device/rr_graph_obj.cpp | 16 ++++++++++++++++ vpr/src/device/rr_graph_obj.h | 16 ++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index e57c536ce2c..e538156e806 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -103,6 +103,16 @@ void convert_rr_graph(std::vector& vpr_segments) { // Create the edges std::map, RREdgeId> old_to_new_rr_edge; // Key: // {inode,iedge} + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + /* Reserve input and output edges for the node: + * this is very important to avoid memory fragments!!! + */ + device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.fan_in()); + device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.num_edges()); + } + + /* Add edges for each node */ for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; for (int iedge = 0; iedge < node.num_edges(); ++iedge) { diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 53066e89aff..33aef97ec26 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -806,6 +806,22 @@ void RRGraph::reserve_segments(const int& num_segments) { this->segments_.reserve(num_segments); } +/* Reserve the input edges for a node */ +void RRGraph::reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges) { + /* Validate the node id */ + VTR_ASSERT_SAFE(true == valid_node_id(node)); + /* Reserve the input edge list */ + this->node_in_edges_[node].reserve(num_in_edges); +} + +/* Reserve the input edges for a node */ +void RRGraph::reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges) { + /* Validate the node id */ + VTR_ASSERT_SAFE(true == valid_node_id(node)); + /* Reserve the input edge list */ + this->node_out_edges_[node].reserve(num_out_edges); +} + /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { //Allocate an ID diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f34b1116205..5b6ae1bdcf7 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -588,6 +588,22 @@ class RRGraph { void reserve_switches(const int& num_switches); void reserve_segments(const int& num_segments); + /* Reserve the lists of input/output edges for a RR node to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * + * For example: + * RRGraph rr_graph; + * // Add 1 source node to the RRGraph object + * RRNodeId src_node = rr_graph.create_node(SOURCE); + * // Reserve the output edges for the source node + * rr_graph.reserve_node_out_edges(src_node, 5); + * // Add your edges + */ + void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); + void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); + /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type * Detailed node-level information should be added using the set_node_* functions From b6ad5b00c612b1f37af887f9457ee0c8ba3d7b01 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 17:42:21 -0700 Subject: [PATCH 34/58] remove redundant files from util about RRGraph object --- vpr/src/util/rr_graph_obj_util.cpp | 30 ------ vpr/src/util/rr_graph_obj_util.h | 14 --- vpr/src/util/rr_graph_obj_utils.h | 165 ----------------------------- 3 files changed, 209 deletions(-) delete mode 100644 vpr/src/util/rr_graph_obj_util.cpp delete mode 100644 vpr/src/util/rr_graph_obj_util.h delete mode 100644 vpr/src/util/rr_graph_obj_utils.h diff --git a/vpr/src/util/rr_graph_obj_util.cpp b/vpr/src/util/rr_graph_obj_util.cpp deleted file mode 100644 index d7f824421d0..00000000000 --- a/vpr/src/util/rr_graph_obj_util.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** - * This file include most-utilized functions that manipulate on the - * RRGraph object - ***************************************************************************/ -#include -#include "rr_graph_obj_util.h" - -/**************************************************************************** - * Find the switches interconnecting two nodes - * Return a vector of switch ids - ***************************************************************************/ -std::vector find_rr_graph_switches(const RRGraph& rr_graph, - const RRNodeId& from_node, - const RRNodeId& to_node) { - std::vector switches; - std::vector edges = rr_graph.find_edges(from_node, to_node); - if (true == edges.empty()) { - /* edge is open, we return an empty vector of switches */ - return switches; - } - - /* Reach here, edge list is not empty, find switch id one by one - * and update the switch list - */ - for (auto edge : edges) { - switches.push_back(rr_graph.edge_switch(edge)); - } - - return switches; -} diff --git a/vpr/src/util/rr_graph_obj_util.h b/vpr/src/util/rr_graph_obj_util.h deleted file mode 100644 index cade12c22ad..00000000000 --- a/vpr/src/util/rr_graph_obj_util.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef RR_GRAPH_OBJ_UTIL_H -#define RR_GRAPH_OBJ_UTIL_H - -/* Include header files which include data structures used by - * the function declaration - */ -#include "rr_graph_obj.h" - -/* Get node-to-node switches in a RRGraph */ -std::vector find_rr_graph_switches(const RRGraph& rr_graph, - const RRNodeId& from_node, - const RRNodeId& to_node); - -#endif diff --git a/vpr/src/util/rr_graph_obj_utils.h b/vpr/src/util/rr_graph_obj_utils.h deleted file mode 100644 index 910b0ce3acd..00000000000 --- a/vpr/src/util/rr_graph_obj_utils.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef RR_GRAPH_OBJ_UTILS_H -#define RR_GRAPH_OBJ_UTILS_H - -/* Include header files which include data structures used by - * the function declaration - */ -#include -#include "vtr_vector_map.h" - -/* - * - * Templated utility functions for cleaning and reordering IdMaps - * - */ - -//Returns true if all elements are contiguously ascending values (i.e. equal to their index) -template -bool are_contiguous(const Container& values) { - using T = typename Container::value_type; - size_t i = 0; - for (T val : values) { - if (val != T(i)) { - return false; - } - ++i; - } - return true; -} - -//Returns true if all elements in the vector 'values' evaluate true -template -bool all_valid(const Container& values) { - for (auto val : values) { - if (!val) { - return false; - } - } - return true; -} - -//Builds a mapping from old to new ids by skipping values marked invalid -template -Container compress_ids(const Container& ids) { - using Id = typename Container::value_type; - Container id_map(ids.size()); - size_t i = 0; - for (auto id : ids) { - if (id) { - //Valid - id_map[id] = Id(i); - ++i; - } - } - - return id_map; -} - -//Returns a vector based on 'values', which has had entries dropped & re-ordered according according to 'id_map'. -//Each entry in id_map corresponds to the assoicated element in 'values'. -//The value of the id_map entry is the new ID of the entry in values. -// -//If it is an invalid ID, the element in values is dropped. -//Otherwise the element is moved to the new ID location. -template -ValueContainer clean_and_reorder_values(const ValueContainer& values, const IdContainer& id_map) { - using Id = typename IdContainer::value_type; - VTR_ASSERT(values.size() == id_map.size()); - - //Allocate space for the values that will not be dropped - ValueContainer result(values.size()); - - //Move over the valid entries to their new locations - size_t new_count = 0; - for (size_t cur_idx = 0; cur_idx < values.size(); ++cur_idx) { - Id old_id = Id(cur_idx); - - Id new_id = id_map[old_id]; - if (new_id) { - //There is a valid mapping - result[new_id] = std::move(values[old_id]); - ++new_count; - } - } - - result.resize(new_count); - - return result; -} - -//Returns the set of new valid Ids defined by 'id_map' -//TODO: merge with clean_and_reorder_values -template -Container clean_and_reorder_ids(const Container& id_map) { - //For IDs, the values are the new id's stored in the map - using Id = typename Container::value_type; - - //Allocate a new vector to store the values that have been not dropped - Container result(id_map.size()); - - //Move over the valid entries to their new locations - size_t new_count = 0; - for (size_t cur_idx = 0; cur_idx < id_map.size(); ++cur_idx) { - Id old_id = Id(cur_idx); - - Id new_id = id_map[old_id]; - if (new_id) { - result[new_id] = new_id; - ++new_count; - } - } - - result.resize(new_count); - - return result; -} - -//Count how many of the Id's referenced in 'range' have a valid -//new mapping in 'id_map' -template -size_t count_valid_refs(R range, const vtr::vector_map& id_map) { - size_t valid_count = 0; - - for (Id old_id : range) { - if (id_map[old_id]) { - ++valid_count; - } - } - - return valid_count; -} - -//Updates the Ids in 'values' based on id_map, even if the original or new mapping is not valid -template -Container update_all_refs(const Container& values, const vtr::vector_map& id_map) { - Container updated; - - for (ValId orig_val : values) { - //The original item was valid - ValId new_val = id_map[orig_val]; - //The original item exists in the new mapping - updated.emplace_back(new_val); - } - - return updated; -} - -template -ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer& id_map) { - ValueContainer updated; - - for (auto orig_val : values) { - if (orig_val) { - //Original item valid - - auto new_val = id_map[orig_val]; - if (new_val) { - //The original item exists in the new mapping - updated.emplace_back(new_val); - } - } - } - return updated; -} - -#endif From a41491b10ab476c0284cfdbea46fdc2072dd6a55 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 18:16:46 -0700 Subject: [PATCH 35/58] fix bugs in reserving in/out_edges for RRGraph object --- vpr/src/device/create_rr_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index e538156e806..9227ede96fa 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -109,7 +109,7 @@ void convert_rr_graph(std::vector& vpr_segments) { * this is very important to avoid memory fragments!!! */ device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.fan_in()); - device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.num_edges()); + device_ctx.rr_graph.reserve_node_out_edges(old_to_new_rr_node[inode], node.num_edges()); } /* Add edges for each node */ From 0b5f0046b29442d26bb66744fcb5675ded7354b6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 23:28:41 -0700 Subject: [PATCH 36/58] optimizing memory footprints by removing unused vectors and maps --- vpr/src/device/create_rr_graph.cpp | 39 +- vpr/src/device/rr_graph_obj.cpp | 10 +- vpr/src/device/rr_graph_obj.h | 948 ++++++++++++++++------------- 3 files changed, 553 insertions(+), 444 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 9227ede96fa..99ccd5aab8c 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -53,10 +53,10 @@ void convert_rr_graph(std::vector& vpr_segments) { } /* Reserve list of nodes to be memory efficient */ - device_ctx.rr_graph.reserve_nodes(device_ctx.rr_nodes.size()); + device_ctx.rr_graph.reserve_nodes((unsigned long)device_ctx.rr_nodes.size()); // Create the nodes - std::map old_to_new_rr_node; + std::vector old_to_new_rr_node(device_ctx.rr_nodes.size(), RRNodeId::INVALID()); for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { auto& node = device_ctx.rr_nodes[inode]; RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); @@ -86,23 +86,19 @@ void convert_rr_graph(std::vector& vpr_segments) { short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); - VTR_ASSERT(!old_to_new_rr_node.count(inode)); + VTR_ASSERT(inode < old_to_new_rr_node.size()); old_to_new_rr_node[inode] = rr_node; } /* Reserve list of edges to be memory efficient */ - { - int num_edges_to_reserve = 0; - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - const auto& node = device_ctx.rr_nodes[inode]; - num_edges_to_reserve += node.num_edges(); - } - device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); + unsigned long num_edges_to_reserve = 0; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + num_edges_to_reserve += node.num_edges(); } + device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); // Create the edges - std::map, RREdgeId> old_to_new_rr_edge; // Key: - // {inode,iedge} for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; /* Reserve input and output edges for the node: @@ -116,22 +112,21 @@ void convert_rr_graph(std::vector& vpr_segments) { for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; for (int iedge = 0; iedge < node.num_edges(); ++iedge) { - int isink_node = node.edge_sink_node(iedge); + size_t isink_node = node.edge_sink_node(iedge); int iswitch = node.edge_switch(iedge); - VTR_ASSERT(old_to_new_rr_node.count(inode)); - VTR_ASSERT(old_to_new_rr_node.count(isink_node)); + VTR_ASSERT(inode < old_to_new_rr_node.size()); + VTR_ASSERT(isink_node < old_to_new_rr_node.size()); - RREdgeId rr_edge = device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], - old_to_new_rr_node[isink_node], - RRSwitchId(iswitch)); - - auto key = std::make_pair(inode, iedge); - VTR_ASSERT(!old_to_new_rr_edge.count(key)); - old_to_new_rr_edge[key] = rr_edge; + device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], + old_to_new_rr_node[isink_node], + RRSwitchId(iswitch)); } } + /* Ensure that we reserved what we want */ + VTR_ASSERT(num_edges_to_reserve == (unsigned long)device_ctx.rr_graph.edges().size()); + /* Partition edges to be two class: configurable (1st part) and * non-configurable (2nd part) * See how the router will use the edges and determine the strategy diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 33aef97ec26..2a93c588ad8 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -7,6 +7,7 @@ #include #include +#include "vtr_geometry.h" #include "vtr_vector_map.h" #include "vtr_log.h" #include "vtr_util.h" @@ -764,7 +765,7 @@ void RRGraph::clear_dirty() { } /* Reserve a list of nodes */ -void RRGraph::reserve_nodes(const int& num_nodes) { +void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ this->node_ids_.reserve(num_nodes); @@ -786,7 +787,7 @@ void RRGraph::reserve_nodes(const int& num_nodes) { } /* Reserve a list of edges */ -void RRGraph::reserve_edges(const int& num_edges) { +void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ this->edge_ids_.reserve(num_edges); this->edge_src_nodes_.reserve(num_edges); @@ -795,13 +796,13 @@ void RRGraph::reserve_edges(const int& num_edges) { } /* Reserve a list of switches */ -void RRGraph::reserve_switches(const int& num_switches) { +void RRGraph::reserve_switches(const size_t& num_switches) { this->switch_ids_.reserve(num_switches); this->switches_.reserve(num_switches); } /* Reserve a list of segments */ -void RRGraph::reserve_segments(const int& num_segments) { +void RRGraph::reserve_segments(const size_t& num_segments) { this->segment_ids_.reserve(num_segments); this->segments_.reserve(num_segments); } @@ -1132,6 +1133,7 @@ void RRGraph::partition_edges() { } void RRGraph::build_fast_node_lookup() const { + /* Free the current fast node look-up, we will rebuild a new one here */ invalidate_fast_node_lookup(); for (auto node : nodes()) { diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 5b6ae1bdcf7..57f7130636a 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -1,25 +1,28 @@ /************************************************************************ - * This file introduces a class to model a Routing Resource Graph (RRGraph or RRG) + * This file introduces a class to model a Routing Resource Graph (RRGraph or + *RRG) * which is widely used by placers, routers, analyzers etc. * * Overview * ======== * RRGraph aims to describe in a general way how routing resources are connected * in a FPGA fabric. - * It includes device-level information for routing resources, - * such as the physical location of nodes, - * routing segment information of each routing resource + * It includes device-level information for routing resources, + * such as the physical location of nodes, + * routing segment information of each routing resource * switch information of each routing resource. - * - * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many cycles), + * + * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many + *cycles), * which consists of a number of nodes and edges. * * Node * ---- - * Each node represents a routing resource, which could be - * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) - * 2. an input or an output of a logic block (IPIN or OPIN) - * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending points of routing trees. + * Each node represents a routing resource, which could be + * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) + * 2. an input or an output of a logic block (IPIN or OPIN) + * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending + *points of routing trees. * * Edge * ---- @@ -34,42 +37,47 @@ * * The switch information are categorized in the rr_switch_inf of RRGraph class. * rr_switch_inf is created to minimize memory footprint of RRGraph classs - * While the RRG could contain millions (even much larger) of edges, there are only + * While the RRG could contain millions (even much larger) of edges, there are + *only * a limited number of types of switches. - * Hence, we use a flyweight pattern to store switch-related information that differs + * Hence, we use a flyweight pattern to store switch-related information that + *differs * only for types of switches (switch type, drive strength, R, C, etc.). - * Each edge stores the ids of the switch that implements it so this additional information + * Each edge stores the ids of the switch that implements it so this additional + *information * can be easily looked up. * - * Note: All the switch-related information, such as R, C, should be placed in rr_switch_inf - * but NOT directly in the edge-related data of RRGraph. - * If you wish to create a new data structure to represent switches between routing resources, + * Note: All the switch-related information, such as R, C, should be placed in + *rr_switch_inf + * but NOT directly in the edge-related data of RRGraph. + * If you wish to create a new data structure to represent switches between + *routing resources, * please follow the flyweight pattern by linking your switch ids to edges only! * - * Guidlines on using the RRGraph data structure + * Guidlines on using the RRGraph data structure * ============================================= * * For those want to access data from RRGraph * ------------------------------------------ * Some examples for most frequent data query: - * + * * // Strongly suggest to use a read-only rr_graph object * const RRGraph& rr_graph; * * // Access type of a node with a given node id - * // Get the unique node id that you may get - * // from other data structures or functions - * RRNodeId node_id; + * // Get the unique node id that you may get + * // from other data structures or functions + * RRNodeId node_id; * t_rr_type node_type = rr_graph.node_type(node_id); * - * // Access all the fan-out edges from a given node + * // Access all the fan-out edges from a given node * for (const RREdgeId& out_edge_id : rr_graph.node_out_edges(node_id)) { * // Do something with out_edge * } * // If you only want to learn the number of fan-out edges * size_t num_out_edges = rr_graph.node_fan_out(node_id); * - * // Access all the switches connected to a given node + * // Access all the switches connected to a given node * for (const RREdgeId& in_edge_id : rr_graph.node_in_edges(node_id)) { * RRSwitchId edge_switch_id = rr_graph.edge_switch(in_edge_id); * // Do something with the switch @@ -84,56 +92,75 @@ * We suggest developers to create builders in separated C/C++ source files * outside the rr_graph header and source files * - * After build/modify a RRGraph, please do run a fundamental check, a public accessor. - * to ensure that your RRGraph does not include invalid nodes/edges/switches/segements + * After build/modify a RRGraph, please do run a fundamental check, a public + *accessor. + * to ensure that your RRGraph does not include invalid + *nodes/edges/switches/segements * as well as connections. - * The validate() function gurantees the consistency between internal data structures, + * The validate() function gurantees the consistency between internal data + *structures, * such as the id cross-reference between nodes and edges etc., * so failing it indicates a fatal bug! - * This is a must-do check! + * This is a must-do check! * - * Example: + * Example: * RRGraph rr_graph; * ... // Building RRGraph - * rr_graph.validate(); + * rr_graph.validate(); * - * Optionally, we strongly recommend developers to run an advance check in check_rr_graph() + * Optionally, we strongly recommend developers to run an advance check in + *check_rr_graph() * This guarantees legal and routable RRGraph for VPR routers. * - * This checks for connectivity or other information in the RRGraph that is unexpected - * or unusual in an FPGA, and likely indicates a problem in your graph generation. - * However, if you are intentionally creating an RRGraph with this unusual, - * buts still technically legal, behaviour, you can write your own check_rr_graph() with weaker assumptions. + * This checks for connectivity or other information in the RRGraph that is + *unexpected + * or unusual in an FPGA, and likely indicates a problem in your graph + *generation. + * However, if you are intentionally creating an RRGraph with this unusual, + * buts still technically legal, behaviour, you can write your own + *check_rr_graph() with weaker assumptions. * - * Note: Do NOT modify the coordinate system for nodes, they are designed for downstream drawers and routers + * Note: Do NOT modify the coordinate system for nodes, they are designed for + *downstream drawers and routers * * For those want to extend RRGraph data structure * -------------------------------------------------------------------------- * Please avoid modifying any existing public/private accessors/mutators * in order to keep a stable RRGraph object in the framework - * Developers may add more internal data to RRGraph as well as associate accessors/mutators - * Please update and comment on the added features properly to keep this data structure friendly to be extended. + * Developers may add more internal data to RRGraph as well as associate + *accessors/mutators + * Please update and comment on the added features properly to keep this data + *structure friendly to be extended. * - * Try to keep your extension within only graph-related internal data to RRGraph. - * In other words, extension is necessary when the new node/edge attributes are needed. - * RRGraph should NOT include other data which are shared by other data structures outside. + * Try to keep your extension within only graph-related internal data to + *RRGraph. + * In other words, extension is necessary when the new node/edge attributes are + *needed. + * RRGraph should NOT include other data which are shared by other data + *structures outside. * The rr-graph is the single largest data structure in VPR, - * so avoid adding unnecessary information per node or per edge to it, as it will impact memory footprint. - * Instead, using indices to point to the outside data source instead of embedding to RRGraph - * For example: - * For any placement/routing cost related information, try to extend t_rr_indexed_data, but not RRGraph - * For any placement/routing results, try to extend PlaceContext and RoutingContext, but not RRGraph - * + * so avoid adding unnecessary information per node or per edge to it, as it + *will impact memory footprint. + * Instead, using indices to point to the outside data source instead of + *embedding to RRGraph + * For example: + * For any placement/routing cost related information, try to extend + *t_rr_indexed_data, but not RRGraph + * For any placement/routing results, try to extend PlaceContext and + *RoutingContext, but not RRGraph + * * For those want to develop placers or routers * -------------------------------------------------------------------------- * The RRGraph is designed to be a read-only database/graph, once created. * Placement and routing should NOT change any attributes of RRGraph. - * Any placement and routing results should be stored in other data structures, such as PlaceContext and RoutingContext. + * Any placement and routing results should be stored in other data structures, + *such as PlaceContext and RoutingContext. * - * Tracing Cross-Reference + * Tracing Cross-Reference * ======================= * RRGraph is designed to a self-contained data structure as much as possible. - * It includes the switch information (rr_switch) and segment_information (rr_segment) + * It includes the switch information (rr_switch) and segment_information + *(rr_segment) * which are necessary to build-up any external data structures. * * Internal cross-reference @@ -163,13 +190,14 @@ * The only cross-reference to outside data structures is the cost_index * corresponding to the data structure t_rr_index_data * Details can be found in the definition of t_rr_index_data - * This allows rapid look up by the router of additional information it needs for this node, using a flyweight pattern. + * This allows rapid look up by the router of additional information it needs + *for this node, using a flyweight pattern. * * +---------+ cost_index +------------------------------+ - * | RRGraph |-------------->| cost_index_data[cost_index] | + * | RRGraph |-------------->| cost_index_data[cost_index] | * +---------+ +------------------------------+ * - * Note: if you wish to use a customized routing-cost data structure, + * Note: if you wish to use a customized routing-cost data structure, * please use the flyweigth pattern as we do for t_rr_index_data! * * Access to a node/edge/switch/segment, please use the StrongId created @@ -180,18 +208,19 @@ * For segment, use RRSegmentId * * These are the unique identifier for each data type. - * To check if your id is valid or not, use the INVALID() function of StrongId class. + * To check if your id is valid or not, use the INVALID() function of + *StrongId class. * Example: * if (node_id == RRNodeId::INVALID()) { - * } + * } * ***********************************************************************/ #ifndef RR_GRAPH_OBJ_H #define RR_GRAPH_OBJ_H /* - * Notes in include header files in a head file - * Only include the neccessary header files + * Notes in include header files in a head file + * Only include the neccessary header files * that is required by the data types in the function/class declarations! */ /* Header files should be included in a sequence */ @@ -211,11 +240,13 @@ class RRGraph { public: /* Types */ - /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ + /* Iterators used to create iterator-based loop for + * nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; - typedef vtr::vector::const_iterator segment_iterator; + typedef vtr::vector::const_iterator + segment_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; @@ -225,213 +256,234 @@ class RRGraph { public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments - * To iterate over the nodes/edges/switches/segments in a RRGraph, - * using a range-based loop is suggested. - * ----------------------------------------------------------------- - * Example: iterate over all the nodes - * // Strongly suggest to use a read-only rr_graph object - * const RRGraph& rr_graph; - * for (const RRNodeId& node : rr_graph.nodes()) { - * // Do something with each node - * } - * - * for (const RREdgeId& edge : rr_graph.edges()) { - * // Do something with each edge - * } - * - * for (const RRSwitchId& switch : rr_graph.switches()) { - * // Do something with each switch - * } - * - * for (const RRSegmentId& segment : rr_graph.segments()) { - * // Do something with each segment - * } - */ + * To iterate over the nodes/edges/switches/segments in a RRGraph, + * using a range-based loop is suggested. + * ----------------------------------------------------------------- + * Example: iterate over all the nodes + * // Strongly suggest to use a read-only rr_graph object + * const RRGraph& rr_graph; + * for (const RRNodeId& node : rr_graph.nodes()) { + * // Do something with each node + * } + * + * for (const RREdgeId& edge : rr_graph.edges()) { + * // Do something with each edge + * } + * + * for (const RRSwitchId& switch : rr_graph.switches()) { + * // Do something with each switch + * } + * + * for (const RRSegmentId& segment : rr_graph.segments()) { + * // Do something with each segment + * } + */ node_range nodes() const; edge_range edges() const; switch_range switches() const; segment_range segments() const; /* Node-level attributes */ - size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this accessor as outside functions should use RRNodeId */ - - /* get the type of a RRGraph node : types of each node, can be channel wires (CHANX or CHANY) or - * logic block pins(OPIN or IPIN) or virtual nodes (SOURCE or SINK) - * see t_rr_type definition for more details - */ + size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this + accessor as outside + functions should use + RRNodeId */ + + /* get the type of a RRGraph node : types of each node, can be channel wires + * (CHANX or CHANY) or + * logic block pins(OPIN or IPIN) or virtual + * nodes (SOURCE or SINK) + * see t_rr_type definition for more details + */ t_rr_type node_type(const RRNodeId& node) const; /* Get coordinate of a node. (xlow, xhigh, ylow, yhigh): - * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh - * This is still the case when a logic block has a height > 1 - * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent - * where the routing segment starts and ends. - * Note that our convention alway keeps - * xlow <= xhigh and ylow <= yhigh - * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in INC_DIRECTION - * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION - * - * Note: there is only a single drive point for each routing segment (track) - * in the context of uni-directional wires - * - * Example : - * CHANX in INC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * ----------------------------> - * - * CHANX in DEC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * <---------------------------- - * - * CHANY in INC_DIRECTION - * - * /|\ <-------(xhigh, yhigh) - * | - * | <-------(xlow, ylow) - * - * CHANY in DEC_DIRECTION - * - * | <-------(xhigh, yhigh) - * | - * \|/ <-------(xlow, ylow) - */ + * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh + * This is still the case when a logic block has a height > 1 + * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent + * where the routing segment starts and ends. + * Note that our convention alway keeps + * xlow <= xhigh and ylow <= yhigh + * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in + *INC_DIRECTION + * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION + * + * Note: there is only a single drive point for each routing segment (track) + * in the context of uni-directional wires + * + * Example : + * CHANX in INC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * ----------------------------> + * + * CHANX in DEC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * <---------------------------- + * + * CHANY in INC_DIRECTION + * + * /|\ <-------(xhigh, yhigh) + * | + * | <-------(xlow, ylow) + * + * CHANY in DEC_DIRECTION + * + * | <-------(xhigh, yhigh) + * | + * \|/ <-------(xlow, ylow) + */ short node_xlow(const RRNodeId& node) const; short node_ylow(const RRNodeId& node) const; short node_xhigh(const RRNodeId& node) const; short node_yhigh(const RRNodeId& node) const; - /* Get the length of a routing track. - * Note that it is ONLY meaningful for CHANX and CHANY, which represents the number of logic blocks that a routing track spans - * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be always 0 - */ + /* Get the length of a routing track. + * Note that it is ONLY meaningful for CHANX and CHANY, which represents the + * number of logic blocks that a routing track spans + * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be + * always 0 + */ short node_length(const RRNodeId& node) const; /* A short-cut function to get coordinates of a node, - * where xmin of vtr::Rect = xlow, - * ymin of vtr::Rect = ylow, - * xmax of vtr::Rect = xhigh, - * ymax of vtr::Rect = yhigh. - */ + * where xmin of vtr::Rect = xlow, + * ymin of vtr::Rect = ylow, + * xmax of vtr::Rect = xhigh, + * ymax of vtr::Rect = yhigh. + */ vtr::Rect node_bounding_box(const RRNodeId& node) const; - /* Get node starting and ending points in routing channels. - * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and node_yhigh() - * For routing tracks in INC_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * For routing tracks in DEC_DIRECTION: - * node_start_coordinate() returns (xhigh, yhigh) as the starting point - * node_end_coordinate() returns (xlow, ylow) as the ending point - * - * For routing tracks in BI_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * Applicable to routing track nodes only!!! - * This function will requires the types of node to be either CHANX or CHANY - */ + /* Get node starting and ending points in routing channels. + * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and + *node_yhigh() + * For routing tracks in INC_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * For routing tracks in DEC_DIRECTION: + * node_start_coordinate() returns (xhigh, yhigh) as the starting point + * node_end_coordinate() returns (xlow, ylow) as the ending point + * + * For routing tracks in BI_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * Applicable to routing track nodes only!!! + * This function will requires the types of node to be either CHANX or CHANY + */ vtr::Point node_start_coordinate(const RRNodeId& node) const; vtr::Point node_end_coordinate(const RRNodeId& node) const; - /* Get the capacity of a node. - * Literally, how many nets can be mapped to the node. - * Typically, each node has a capacity of 1 but special nodes (SOURCE and SINK) will have a - * large number due to logic equivalent pins - * See Vaughn Betz's book for more details - */ + /* Get the capacity of a node. + * Literally, how many nets can be mapped to the node. + * Typically, each node has a capacity of 1 but special nodes (SOURCE and + * SINK) will have a + * large number due to logic equivalent pins + * See Vaughn Betz's book for more details + */ short node_capacity(const RRNodeId& node) const; /* Get the number of edges that drives a given node - * Note that each edge is typically driven by a node - * (true in VPR RRG that is currently supported, may not be true in customized RRG) - * This can also represent the number of drive nodes - * An example where fan-in of a node C is 2 - * - * edge A - * node A -------->+ - * | - * |-->node C - * edgeB | - * node B -------->+ - * - */ + * Note that each edge is typically driven by a node + * (true in VPR RRG that is currently supported, may not be true in customized + *RRG) + * This can also represent the number of drive nodes + * An example where fan-in of a node C is 2 + * + * edge A + * node A -------->+ + * | + * |-->node C + * edgeB | + * node B -------->+ + * + */ short node_fan_in(const RRNodeId& node) const; /* Get the number of edges that are driven a given node - * Note that each edge typically drives by a node - * (true in VPR RRG that is currently supported, may not be true in customized RRG) - * This can also represent the number of fan-out nodes - * An example where fan-out of a node A is 2 - * - * edge A - * node A -+--------> node B - * | - * | - * | edgeB - * +--------> node C - * - */ + * Note that each edge typically drives by a node + * (true in VPR RRG that is currently supported, may not be true in customized + *RRG) + * This can also represent the number of fan-out nodes + * An example where fan-out of a node A is 2 + * + * edge A + * node A -+--------> node B + * | + * | + * | edgeB + * +--------> node C + * + */ short node_fan_out(const RRNodeId& node) const; /* Get the ptc_num of a node - * The ptc (pin, track, or class) number is an integer - * that allows you to differentiate between wires, pins or sources/sinks with overlapping x,y coordinates or extent. - * This is useful for drawing rr-graphs nicely. - * For example, all the CHANX rr_nodes that have the same y coordinate and x-coordinates - * that overlap will have different ptc numbers, by convention starting at 0. - * This allows them to be drawn without overlapping, as the ptc num can be used as a track identifier. - * The main routing code does not care about ptc num. - * - * The ptc_num carries different meanings for different node types - * (true in VPR RRG that is currently supported, may not be true in customized RRG) - * CHANX or CHANY: the track id in routing channels - * OPIN or IPIN: the index of pins in the logic block data structure - * SOURCE and SINK: the class id of a pin (indicating logic equivalence of pins) in the logic block data structure - * - * To ease the access to ptc_num for different types of nodes: - * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes - * node_track_num() is designed for routing tracks, which are CHANX and CHANY nodes - * node_class_num() is designed for routing source and sinks, which are SOURCE and SINK nodes - * - * Due to a useful identifier, ptc_num is used in building fast look-up - */ + * The ptc (pin, track, or class) number is an integer + * that allows you to differentiate between wires, pins or sources/sinks with + *overlapping x,y coordinates or extent. + * This is useful for drawing rr-graphs nicely. + * For example, all the CHANX rr_nodes that have the same y coordinate and + *x-coordinates + * that overlap will have different ptc numbers, by convention starting at 0. + * This allows them to be drawn without overlapping, as the ptc num can be + *used as a track identifier. + * The main routing code does not care about ptc num. + * + * The ptc_num carries different meanings for different node types + * (true in VPR RRG that is currently supported, may not be true in customized + *RRG) + * CHANX or CHANY: the track id in routing channels + * OPIN or IPIN: the index of pins in the logic block data structure + * SOURCE and SINK: the class id of a pin (indicating logic equivalence of + *pins) in the logic block data structure + * + * To ease the access to ptc_num for different types of nodes: + * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes + * node_track_num() is designed for routing tracks, which are CHANX and CHANY + *nodes + * node_class_num() is designed for routing source and sinks, which are SOURCE + *and SINK nodes + * + * Due to a useful identifier, ptc_num is used in building fast look-up + */ short node_ptc_num(const RRNodeId& node) const; short node_pin_num(const RRNodeId& node) const; short node_track_num(const RRNodeId& node) const; short node_class_num(const RRNodeId& node) const; /* Get the index of cost data in the list of cost_indexed_data data structure - * It contains the routing cost for different nodes in the RRGraph - * when used in evaluate different routing paths - * See cross-reference section in this header file for more details - */ + * It contains the routing cost for different nodes in the RRGraph + * when used in evaluate different routing paths + * See cross-reference section in this header file for more details + */ short node_cost_index(const RRNodeId& node) const; /* Get the directionality of a node - * see node coordinate for details - * only matters the routing track nodes (CHANX and CHANY) - */ + * see node coordinate for details + * only matters the routing track nodes (CHANX and CHANY) + */ e_direction node_direction(const RRNodeId& node) const; - /* Get the side where the node physically locates on a logic block. - * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of logic block - * The side should be consistent to definition in architecture XML - * - * TOP - * +-----------+ - * | | - * LEFT | Logic | RIGHT - * | Block | - * | | - * +-----------+ - * BOTTOM - * - */ + /* Get the side where the node physically locates on a logic block. + * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of + *logic block + * The side should be consistent to definition in architecture + *XML + * + * TOP + * +-----------+ + * | | + * LEFT | Logic | RIGHT + * | Block | + * | | + * +-----------+ + * BOTTOM + * + */ e_side node_side(const RRNodeId& node) const; /* Get resistance of a node, used to built RC tree for timing analysis */ @@ -441,8 +493,9 @@ class RRGraph { float node_C(const RRNodeId& node) const; /* Get segment id of a node, containing the information of the routing - * segment that the node represents. See more details in the data structure t_segment_inf - */ + * segment that the node represents. See more details in the data structure + * t_segment_inf + */ RRSegmentId node_segment(const RRNodeId& node) const; /* Get the number of non-configurable incoming edges to a node */ @@ -469,99 +522,120 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; - /* Edge-related attributes - * An example to explain the terminology used in RRGraph - * edgeA - * nodeA --------> nodeB - * | edgeB - * +-------> nodeC - * - * +----------+----------------+----------------+ - * | Edge Id | edge_src_node | edge_sink_node | - * +----------+----------------+----------------+ - * | edgeA | nodeA | nodeB | - * +----------+----------------+----------------+ - * | edgeB | nodeA | nodeC | - * +----------+----------------+----------------+ - * - */ - size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this accessor as outside functions should use RREdgeId */ + /* Edge-related attributes + * An example to explain the terminology used in RRGraph + * edgeA + * nodeA --------> nodeB + * | edgeB + * +-------> nodeC + * + * +----------+----------------+----------------+ + * | Edge Id | edge_src_node | edge_sink_node | + * +----------+----------------+----------------+ + * | edgeA | nodeA | nodeB | + * +----------+----------------+----------------+ + * | edgeB | nodeA | nodeC | + * +----------+----------------+----------------+ + * + */ + size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this + accessor as outside + functions should use + RREdgeId */ /* Get the source node which drives a edge */ RRNodeId edge_src_node(const RREdgeId& edge) const; /* Get the sink node which a edge ends to */ RRNodeId edge_sink_node(const RREdgeId& edge) const; /* Get the switch id which a edge represents - * using switch id, timing and other information can be found - * for any node-to-node connection - */ + * using switch id, timing and other information can be found + * for any node-to-node connection + */ RRSwitchId edge_switch(const RREdgeId& edge) const; - /* Judge if a edge is configurable or not. - * A configurable edge is controlled by a programmable memory bit - * while a non-configurable edge is typically a hard-wired connection - */ + /* Judge if a edge is configurable or not. + * A configurable edge is controlled by a programmable memory bit + * while a non-configurable edge is typically a hard-wired connection + */ bool edge_is_configurable(const RREdgeId& edge) const; bool edge_is_non_configurable(const RREdgeId& edge) const; /* Switch Info */ - size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate this accessor as outside functions should use RRSwitchId */ + size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate + this accessor as + outside functions + should use + RRSwitchId */ /* Get the switch info of a switch used in this RRGraph */ const t_rr_switch_inf& get_switch(const RRSwitchId& switch_id) const; /* Segment Info */ - size_t segment_index(const RRSegmentId& segment_id) const; /* TODO: deprecate this accessor as outside functions should use RRSegmentId */ + size_t segment_index(const RRSegmentId& segment_id) + const; /* TODO: deprecate this accessor as outside functions should use + RRSegmentId */ /* Get the segment info of a routing segment used in this RRGraph */ const t_segment_inf& get_segment(const RRSegmentId& segment_id) const; /* Utilities */ /* Find the edges connecting two nodes */ - std::vector find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const; + std::vector find_edges(const RRNodeId& src_node, + const RRNodeId& sink_node) const; /* Find a node with given features from internal fast look-up */ - RRNodeId find_node(const short& x, const short& y, const t_rr_type& type, const int& ptc, const e_side& side = NUM_SIDES) const; - /* Find the number of routing tracks in a routing channel with a given coordinate */ - short chan_num_tracks(const short& x, const short& y, const t_rr_type& type) const; - - /* This flag is raised when the RRgraph contains invalid nodes/edges etc. - * Invalid nodes/edges exist when users remove nodes/edges from RRGraph - * RRGraph object will not immediately remove the nodes and edges but - * will mark them with invalid ids. - * Afterwards the is_dirty flag is raised as an indicator, to tell users - * that a clean-up process (invoked by compress() function)is required. - * After executing compress(), the is_dirty will be reset to false - * - * Example: - * RRGraph rr_graph; - * RRNodeId node_id; // Node id to be removed - * rr_graph.remove_node(node_id); - * // RRGraph is now dirty (rr_graph.is_dirty() == true) - * ... - * // During this period, when you perform data query, - * // You may encounter invalid nodes and edges - * // It may happen that - * // 1. their ids are invalid - * // 2. the cross-reference between nodes and edge, i.e., - * // node_in_edges(), node_out_edges() - * // 3. invalid node returned from find_node(), which use fast look-up - * ... - * rr_graph.compress(); - * // RRGraph is now clean (rr_graph.is_dirty() == false) - */ + RRNodeId find_node(const short& x, + const short& y, + const t_rr_type& type, + const int& ptc, + const e_side& side = NUM_SIDES) const; + /* Find the number of routing tracks in a routing channel with a given + * coordinate */ + short chan_num_tracks(const short& x, + const short& y, + const t_rr_type& type) const; + + /* This flag is raised when the RRgraph contains invalid nodes/edges etc. + * Invalid nodes/edges exist when users remove nodes/edges from RRGraph + * RRGraph object will not immediately remove the nodes and edges but + * will mark them with invalid ids. + * Afterwards the is_dirty flag is raised as an indicator, to tell users + * that a clean-up process (invoked by compress() function)is required. + * After executing compress(), the is_dirty will be reset to false + * + * Example: + * RRGraph rr_graph; + * RRNodeId node_id; // Node id to be removed + * rr_graph.remove_node(node_id); + * // RRGraph is now dirty (rr_graph.is_dirty() == true) + * ... + * // During this period, when you perform data query, + * // You may encounter invalid nodes and edges + * // It may happen that + * // 1. their ids are invalid + * // 2. the cross-reference between nodes and edge, i.e., + * // node_in_edges(), node_out_edges() + * // 3. invalid node returned from find_node(), which use fast look-up + * ... + * rr_graph.compress(); + * // RRGraph is now clean (rr_graph.is_dirty() == false) + */ bool is_dirty() const; - public: /* Echos */ - void print_node(const RRNodeId& node) const; /* Print the detailed information of a node */ + public: /* Echos */ + void print_node(const RRNodeId& node) + const; /* Print the detailed information of a node */ public: /* Public Validators */ - /* Check data structure for internal consistency - * This function will - * 1. re-build fast look-up for nodes - * 2. check all the edges and nodes are connected - * Literally, no invalid ids in fan-in/fan-out of edges/nodes - * 3. check that all the nodes representing routing tracks have valid id linked to its segment-related data structure - * 4. check that all the edges have valid id linked to its switch-related data structure - * - * Any valid and non-dirty RRGraph should pass this check - * It is highly recommended to run this function after building any RRGraph object - */ + /* Check data structure for internal consistency + * This function will + * 1. re-build fast look-up for nodes + * 2. check all the edges and nodes are connected + * Literally, no invalid ids in fan-in/fan-out of edges/nodes + * 3. check that all the nodes representing routing tracks have valid id + *linked to its segment-related data structure + * 4. check that all the edges have valid id linked to its switch-related data + *structure + * + * Any valid and non-dirty RRGraph should pass this check + * It is highly recommended to run this function after building any RRGraph + *object + */ bool validate() const; /* Validate is the node id does exist in the RRGraph */ @@ -571,78 +645,87 @@ class RRGraph { bool valid_edge_id(const RREdgeId& edge) const; public: /* Mutators */ - /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * For example: - * RRGraph rr_graph; - * // Add 1000 CHANX nodes to the RRGraph object - * rr_graph.reserve_nodes(1000); - * for (size_t i = 0; i < 1000; ++i) { - * rr_graph.create_node(CHANX); - * } - */ - void reserve_nodes(const int& num_nodes); - void reserve_edges(const int& num_edges); - void reserve_switches(const int& num_switches); - void reserve_segments(const int& num_segments); - - /* Reserve the lists of input/output edges for a RR node to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * - * For example: - * RRGraph rr_graph; - * // Add 1 source node to the RRGraph object - * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the output edges for the source node - * rr_graph.reserve_node_out_edges(src_node, 5); - * // Add your edges - */ + /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * For example: + * RRGraph rr_graph; + * // Add 1000 CHANX nodes to the RRGraph object + * rr_graph.reserve_nodes(1000); + * for (size_t i = 0; i < 1000; ++i) { + * rr_graph.create_node(CHANX); + * } + */ + void reserve_nodes(const unsigned long& num_nodes); + /* We use long data type for edges because the number of edges is very large + */ + void reserve_edges(const unsigned long& num_edges); + void reserve_switches(const size_t& num_switches); + void reserve_segments(const size_t& num_segments); + + /* Reserve the lists of input/output edges for a RR node to be memory + *efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * + * For example: + * RRGraph rr_graph; + * // Add 1 source node to the RRGraph object + * RRNodeId src_node = rr_graph.create_node(SOURCE); + * // Reserve the output edges for the source node + * rr_graph.reserve_node_out_edges(src_node, 5); + * // Add your edges + */ void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); - void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); + void reserve_node_out_edges(const RRNodeId& node, + const size_t& num_out_edges); /* Add new elements (node, edge, switch, etc.) to RRGraph */ - /* Add a node to the RRGraph with a deposited type - * Detailed node-level information should be added using the set_node_* functions - * For example: - * RRNodeId node = create_node(); - * set_node_xlow(node, 0); - */ + /* Add a node to the RRGraph with a deposited type + * Detailed node-level information should be added using the set_node_* + * functions + * For example: + * RRNodeId node = create_node(); + * set_node_xlow(node, 0); + */ RRNodeId create_node(const t_rr_type& type); - /* Add a edge to the RRGraph, by providing the source and sink node - * This function will automatically create a node and - * configure the nodes and edges in connection - */ - RREdgeId create_edge(const RRNodeId& source, const RRNodeId& sink, const RRSwitchId& switch_id); + /* Add a edge to the RRGraph, by providing the source and sink node + * This function will automatically create a node and + * configure the nodes and edges in connection + */ + RREdgeId create_edge(const RRNodeId& source, + const RRNodeId& sink, + const RRSwitchId& switch_id); RRSwitchId create_switch(const t_rr_switch_inf& switch_info); RRSegmentId create_segment(const t_segment_inf& segment_info); /* Remove elements from RRGraph - * This function just turn the nodes and edges to an invalid id without deletion - * This will cause the RRGraph to be marked as dirty (is_dirty(): false => true) - * To thoroughly remove the edges and nodes as well as clear the dirty flag, - * use compress() after the remove functions - * Example: - * RRGraph rr_graph; - * rr_graph.remove_node() - * .. // remove more nodes - * rr_graph.remove_edge() - * .. // remove more nodes - * // rr_graph.is_dirty() == true - * // If you want to access any node or edge - * // Check codes for ids should be intensively used - * // Such as, - * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { - * // if (RREdgeId::INVALID() != in_edge) { - * // ... - * // } - * // } - * rr_graph.compress() - * // rr_graph.is_dirty() == false - */ + * This function just turn the nodes and edges to an invalid id without + * deletion + * This will cause the RRGraph to be marked as dirty (is_dirty(): false => + * true) + * To thoroughly remove the edges and nodes as well as clear the dirty flag, + * use compress() after the remove functions + * Example: + * RRGraph rr_graph; + * rr_graph.remove_node() + * .. // remove more nodes + * rr_graph.remove_edge() + * .. // remove more nodes + * // rr_graph.is_dirty() == true + * // If you want to access any node or edge + * // Check codes for ids should be intensively used + * // Such as, + * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { + * // if (RREdgeId::INVALID() != in_edge) { + * // ... + * // } + * // } + * rr_graph.compress() + * // rr_graph.is_dirty() == false + */ void remove_node(const RRNodeId& node); void remove_edge(const RREdgeId& edge); @@ -653,9 +736,9 @@ class RRGraph { void set_node_yhigh(const RRNodeId& node, const short& yhigh); /* This is a short-cut function, set xlow/xhigh/ylow/yhigh for a node - * Please respect the following to configure the bb object: - * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; - */ + * Please respect the following to configure the bb object: + * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; + */ void set_node_bounding_box(const RRNodeId& node, const vtr::Rect& bb); void set_node_capacity(const RRNodeId& node, const short& capacity); @@ -663,30 +746,34 @@ class RRGraph { /* A generic function to set the ptc_num for a node */ void set_node_ptc_num(const RRNodeId& node, const short& ptc); - /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the pin id in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the + * pin id in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_pin_num(const RRNodeId& node, const short& pin_id); - /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is the track id in a routing channel, - * Routing channel is a group of routing tracks, each of which has a unique index - * An example - * Routing Channel - * +------------------+ - * | | - * ---|----------------->|----> track_id: 0 - * | | - * ... More tracks ... - * | | - * ---|----------------->|----> track_id: 1 - * | | - * +------------------+ - */ + /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is + * the track id in a routing channel, + * Routing channel is a group of routing tracks, each of which has a unique + * index + * An example + * Routing Channel + * +------------------+ + * | | + * ---|----------------->|----> track_id: 0 + * | | + * ... More tracks ... + * | | + * ---|----------------->|----> track_id: 1 + * | | + * +------------------+ + */ void set_node_track_num(const RRNodeId& node, const short& track_id); - /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is the class number in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is + * the class number in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_class_num(const RRNodeId& node, const short& class_id); /* Set the routing cost index for node, see node_cost_index() for details */ @@ -703,38 +790,47 @@ class RRGraph { void set_node_R(const RRNodeId& node, const float& R); void set_node_C(const RRNodeId& node, const float& C); - /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ + /* Set the routing segment linked to a node, only applicable to CHANX and + * CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in one vector, - * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) - */ + /* Edge partitioning is performed for efficiency, + * so we can store configurable and non-configurable edge lists for a node in + * one vector, + * and efficiently iterate over all edges, or only the configurable or + * non-configurable subsets. + * This function will re-organize the incoming and outgoing edges of each + * node, + * i.e., node_in_edges() and node_out_edges(): + * 1. configurable edges (1st part of the vectors) + * 2. non-configurable edges (2nd part of the vectors) + */ void partition_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. - * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set - */ + * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if + * it was set + */ void compress(); /* top-level function to free, should be called when to delete a RRGraph */ void clear(); private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_node_in_edges(const RRNodeId& node); - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_node_out_edges(const RRNodeId& node); - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_in_edges(); - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and + * non-configurable (2nd part) */ void partition_out_edges(); private: /* Internal free functions */ @@ -780,8 +876,10 @@ class RRGraph { bool validate_node_edges(const RRNodeId& node) const; /* Edge-level checking */ - bool validate_node_is_edge_src(const RRNodeId& node, const RREdgeId& edge) const; - bool validate_node_is_edge_sink(const RRNodeId& node, const RREdgeId& edge) const; + bool validate_node_is_edge_src(const RRNodeId& node, + const RREdgeId& edge) const; + bool validate_node_is_edge_sink(const RRNodeId& node, + const RREdgeId& edge) const; bool validate_edge_switch(const RREdgeId& edge) const; bool validate_edge_src_node(const RREdgeId& edge) const; bool validate_edge_sink_node(const RREdgeId& edge) const; @@ -803,10 +901,11 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector node_ids_; /* Unique identifiers for the nodes */ + vtr::vector + node_ids_; /* Unique identifiers for the nodes */ vtr::vector node_types_; - vtr::vector> node_bounding_boxes_; + vtr::vector > node_bounding_boxes_; vtr::vector node_capacities_; vtr::vector node_ptc_nums_; @@ -815,13 +914,15 @@ class RRGraph { vtr::vector node_sides_; vtr::vector node_Rs_; vtr::vector node_Cs_; - vtr::vector node_segments_; /* Segment ids for each node */ - /* Record the dividing point between configurable and non-configurable edges for each node */ + vtr::vector node_segments_; /* Segment ids for each + node */ + /* Record the dividing point between configurable and non-configurable edges + * for each node */ vtr::vector node_num_non_configurable_in_edges_; vtr::vector node_num_non_configurable_out_edges_; - vtr::vector> node_in_edges_; - vtr::vector> node_out_edges_; + vtr::vector > node_in_edges_; + vtr::vector > node_out_edges_; /* Edge related data */ vtr::vector edge_ids_; /* unique identifiers for edges */ @@ -830,29 +931,40 @@ class RRGraph { vtr::vector edge_switches_; /* Switch related data - * Note that so far there has been no need to remove - * switches, so no such facility exists - */ + * Note that so far there has been no need to remove + * switches, so no such facility exists + */ /* Unique identifiers for switches which are used in the RRGraph */ vtr::vector switch_ids_; /* Detailed information about the switches, which are used in the RRGraph */ vtr::vector switches_; - /* Segment relatex data - * Segment info should be corrected annotated for each rr_node - * whose type is CHANX and CHANY - */ - vtr::vector segment_ids_; /* unique identifiers for routing segments which are used in the RRGraph */ - vtr::vector segments_; /* detailed information about the segments, which are used in the RRGraph */ + /* Segment relatex data + * Segment info should be corrected annotated for each rr_node + * whose type is CHANX and CHANY + */ + vtr::vector + segment_ids_; /* unique identifiers for routing + segments which are used in the + RRGraph */ + vtr::vector segments_; /* detailed information + about the segments, + which are used in the + RRGraph */ /* Misc. */ - /* A flag to indicate if the graph contains invalid elements (nodes/edges etc.) */ + /* A flag to indicate if the graph contains invalid elements (nodes/edges + * etc.) */ bool dirty_ = false; - /* Fast look-up to search a node by its type, coordinator and ptc_num - * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] - */ - typedef std::vector>>>> NodeLookup; + /* Fast look-up to search a node by its type, coordinator and ptc_num + * Indexing of fast look-up: + * [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] + */ + typedef std::vector > > > > + NodeLookup; mutable NodeLookup node_lookup_; }; From 9c1402a5fc967aeea1a92837e02740659d08d76d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 20 Nov 2019 23:46:11 -0700 Subject: [PATCH 37/58] fix broken code format --- vpr/src/device/rr_graph_obj.h | 938 +++++++++++++++------------------- 1 file changed, 413 insertions(+), 525 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 57f7130636a..f5611ce9b61 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -1,28 +1,25 @@ /************************************************************************ - * This file introduces a class to model a Routing Resource Graph (RRGraph or - *RRG) + * This file introduces a class to model a Routing Resource Graph (RRGraph or RRG) * which is widely used by placers, routers, analyzers etc. * * Overview * ======== * RRGraph aims to describe in a general way how routing resources are connected * in a FPGA fabric. - * It includes device-level information for routing resources, - * such as the physical location of nodes, - * routing segment information of each routing resource + * It includes device-level information for routing resources, + * such as the physical location of nodes, + * routing segment information of each routing resource * switch information of each routing resource. - * - * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many - *cycles), + * + * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many cycles), * which consists of a number of nodes and edges. * * Node * ---- - * Each node represents a routing resource, which could be - * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) - * 2. an input or an output of a logic block (IPIN or OPIN) - * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending - *points of routing trees. + * Each node represents a routing resource, which could be + * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) + * 2. an input or an output of a logic block (IPIN or OPIN) + * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending points of routing trees. * * Edge * ---- @@ -37,47 +34,42 @@ * * The switch information are categorized in the rr_switch_inf of RRGraph class. * rr_switch_inf is created to minimize memory footprint of RRGraph classs - * While the RRG could contain millions (even much larger) of edges, there are - *only + * While the RRG could contain millions (even much larger) of edges, there are only * a limited number of types of switches. - * Hence, we use a flyweight pattern to store switch-related information that - *differs + * Hence, we use a flyweight pattern to store switch-related information that differs * only for types of switches (switch type, drive strength, R, C, etc.). - * Each edge stores the ids of the switch that implements it so this additional - *information + * Each edge stores the ids of the switch that implements it so this additional information * can be easily looked up. * - * Note: All the switch-related information, such as R, C, should be placed in - *rr_switch_inf - * but NOT directly in the edge-related data of RRGraph. - * If you wish to create a new data structure to represent switches between - *routing resources, + * Note: All the switch-related information, such as R, C, should be placed in rr_switch_inf + * but NOT directly in the edge-related data of RRGraph. + * If you wish to create a new data structure to represent switches between routing resources, * please follow the flyweight pattern by linking your switch ids to edges only! * - * Guidlines on using the RRGraph data structure + * Guidlines on using the RRGraph data structure * ============================================= * * For those want to access data from RRGraph * ------------------------------------------ * Some examples for most frequent data query: - * + * * // Strongly suggest to use a read-only rr_graph object * const RRGraph& rr_graph; * * // Access type of a node with a given node id - * // Get the unique node id that you may get - * // from other data structures or functions - * RRNodeId node_id; + * // Get the unique node id that you may get + * // from other data structures or functions + * RRNodeId node_id; * t_rr_type node_type = rr_graph.node_type(node_id); * - * // Access all the fan-out edges from a given node + * // Access all the fan-out edges from a given node * for (const RREdgeId& out_edge_id : rr_graph.node_out_edges(node_id)) { * // Do something with out_edge * } * // If you only want to learn the number of fan-out edges * size_t num_out_edges = rr_graph.node_fan_out(node_id); * - * // Access all the switches connected to a given node + * // Access all the switches connected to a given node * for (const RREdgeId& in_edge_id : rr_graph.node_in_edges(node_id)) { * RRSwitchId edge_switch_id = rr_graph.edge_switch(in_edge_id); * // Do something with the switch @@ -92,75 +84,56 @@ * We suggest developers to create builders in separated C/C++ source files * outside the rr_graph header and source files * - * After build/modify a RRGraph, please do run a fundamental check, a public - *accessor. - * to ensure that your RRGraph does not include invalid - *nodes/edges/switches/segements + * After build/modify a RRGraph, please do run a fundamental check, a public accessor. + * to ensure that your RRGraph does not include invalid nodes/edges/switches/segements * as well as connections. - * The validate() function gurantees the consistency between internal data - *structures, + * The validate() function gurantees the consistency between internal data structures, * such as the id cross-reference between nodes and edges etc., * so failing it indicates a fatal bug! - * This is a must-do check! + * This is a must-do check! * - * Example: + * Example: * RRGraph rr_graph; * ... // Building RRGraph - * rr_graph.validate(); + * rr_graph.validate(); * - * Optionally, we strongly recommend developers to run an advance check in - *check_rr_graph() + * Optionally, we strongly recommend developers to run an advance check in check_rr_graph() * This guarantees legal and routable RRGraph for VPR routers. * - * This checks for connectivity or other information in the RRGraph that is - *unexpected - * or unusual in an FPGA, and likely indicates a problem in your graph - *generation. - * However, if you are intentionally creating an RRGraph with this unusual, - * buts still technically legal, behaviour, you can write your own - *check_rr_graph() with weaker assumptions. + * This checks for connectivity or other information in the RRGraph that is unexpected + * or unusual in an FPGA, and likely indicates a problem in your graph generation. + * However, if you are intentionally creating an RRGraph with this unusual, + * buts still technically legal, behaviour, you can write your own check_rr_graph() with weaker assumptions. * - * Note: Do NOT modify the coordinate system for nodes, they are designed for - *downstream drawers and routers + * Note: Do NOT modify the coordinate system for nodes, they are designed for downstream drawers and routers * * For those want to extend RRGraph data structure * -------------------------------------------------------------------------- * Please avoid modifying any existing public/private accessors/mutators * in order to keep a stable RRGraph object in the framework - * Developers may add more internal data to RRGraph as well as associate - *accessors/mutators - * Please update and comment on the added features properly to keep this data - *structure friendly to be extended. + * Developers may add more internal data to RRGraph as well as associate accessors/mutators + * Please update and comment on the added features properly to keep this data structure friendly to be extended. * - * Try to keep your extension within only graph-related internal data to - *RRGraph. - * In other words, extension is necessary when the new node/edge attributes are - *needed. - * RRGraph should NOT include other data which are shared by other data - *structures outside. + * Try to keep your extension within only graph-related internal data to RRGraph. + * In other words, extension is necessary when the new node/edge attributes are needed. + * RRGraph should NOT include other data which are shared by other data structures outside. * The rr-graph is the single largest data structure in VPR, - * so avoid adding unnecessary information per node or per edge to it, as it - *will impact memory footprint. - * Instead, using indices to point to the outside data source instead of - *embedding to RRGraph - * For example: - * For any placement/routing cost related information, try to extend - *t_rr_indexed_data, but not RRGraph - * For any placement/routing results, try to extend PlaceContext and - *RoutingContext, but not RRGraph - * + * so avoid adding unnecessary information per node or per edge to it, as it will impact memory footprint. + * Instead, using indices to point to the outside data source instead of embedding to RRGraph + * For example: + * For any placement/routing cost related information, try to extend t_rr_indexed_data, but not RRGraph + * For any placement/routing results, try to extend PlaceContext and RoutingContext, but not RRGraph + * * For those want to develop placers or routers * -------------------------------------------------------------------------- * The RRGraph is designed to be a read-only database/graph, once created. * Placement and routing should NOT change any attributes of RRGraph. - * Any placement and routing results should be stored in other data structures, - *such as PlaceContext and RoutingContext. + * Any placement and routing results should be stored in other data structures, such as PlaceContext and RoutingContext. * - * Tracing Cross-Reference + * Tracing Cross-Reference * ======================= * RRGraph is designed to a self-contained data structure as much as possible. - * It includes the switch information (rr_switch) and segment_information - *(rr_segment) + * It includes the switch information (rr_switch) and segment_information (rr_segment) * which are necessary to build-up any external data structures. * * Internal cross-reference @@ -190,14 +163,13 @@ * The only cross-reference to outside data structures is the cost_index * corresponding to the data structure t_rr_index_data * Details can be found in the definition of t_rr_index_data - * This allows rapid look up by the router of additional information it needs - *for this node, using a flyweight pattern. + * This allows rapid look up by the router of additional information it needs for this node, using a flyweight pattern. * * +---------+ cost_index +------------------------------+ - * | RRGraph |-------------->| cost_index_data[cost_index] | + * | RRGraph |-------------->| cost_index_data[cost_index] | * +---------+ +------------------------------+ * - * Note: if you wish to use a customized routing-cost data structure, + * Note: if you wish to use a customized routing-cost data structure, * please use the flyweigth pattern as we do for t_rr_index_data! * * Access to a node/edge/switch/segment, please use the StrongId created @@ -208,19 +180,18 @@ * For segment, use RRSegmentId * * These are the unique identifier for each data type. - * To check if your id is valid or not, use the INVALID() function of - *StrongId class. + * To check if your id is valid or not, use the INVALID() function of StrongId class. * Example: * if (node_id == RRNodeId::INVALID()) { - * } + * } * ***********************************************************************/ #ifndef RR_GRAPH_OBJ_H #define RR_GRAPH_OBJ_H /* - * Notes in include header files in a head file - * Only include the neccessary header files + * Notes in include header files in a head file + * Only include the neccessary header files * that is required by the data types in the function/class declarations! */ /* Header files should be included in a sequence */ @@ -240,13 +211,11 @@ class RRGraph { public: /* Types */ - /* Iterators used to create iterator-based loop for - * nodes/edges/switches/segments */ + /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; - typedef vtr::vector::const_iterator - segment_iterator; + typedef vtr::vector::const_iterator segment_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; @@ -256,234 +225,213 @@ class RRGraph { public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments - * To iterate over the nodes/edges/switches/segments in a RRGraph, - * using a range-based loop is suggested. - * ----------------------------------------------------------------- - * Example: iterate over all the nodes - * // Strongly suggest to use a read-only rr_graph object - * const RRGraph& rr_graph; - * for (const RRNodeId& node : rr_graph.nodes()) { - * // Do something with each node - * } - * - * for (const RREdgeId& edge : rr_graph.edges()) { - * // Do something with each edge - * } - * - * for (const RRSwitchId& switch : rr_graph.switches()) { - * // Do something with each switch - * } - * - * for (const RRSegmentId& segment : rr_graph.segments()) { - * // Do something with each segment - * } - */ + * To iterate over the nodes/edges/switches/segments in a RRGraph, + * using a range-based loop is suggested. + * ----------------------------------------------------------------- + * Example: iterate over all the nodes + * // Strongly suggest to use a read-only rr_graph object + * const RRGraph& rr_graph; + * for (const RRNodeId& node : rr_graph.nodes()) { + * // Do something with each node + * } + * + * for (const RREdgeId& edge : rr_graph.edges()) { + * // Do something with each edge + * } + * + * for (const RRSwitchId& switch : rr_graph.switches()) { + * // Do something with each switch + * } + * + * for (const RRSegmentId& segment : rr_graph.segments()) { + * // Do something with each segment + * } + */ node_range nodes() const; edge_range edges() const; switch_range switches() const; segment_range segments() const; /* Node-level attributes */ - size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this - accessor as outside - functions should use - RRNodeId */ - - /* get the type of a RRGraph node : types of each node, can be channel wires - * (CHANX or CHANY) or - * logic block pins(OPIN or IPIN) or virtual - * nodes (SOURCE or SINK) - * see t_rr_type definition for more details - */ + size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this accessor as outside functions should use RRNodeId */ + + /* get the type of a RRGraph node : types of each node, can be channel wires (CHANX or CHANY) or + * logic block pins(OPIN or IPIN) or virtual nodes (SOURCE or SINK) + * see t_rr_type definition for more details + */ t_rr_type node_type(const RRNodeId& node) const; /* Get coordinate of a node. (xlow, xhigh, ylow, yhigh): - * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh - * This is still the case when a logic block has a height > 1 - * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent - * where the routing segment starts and ends. - * Note that our convention alway keeps - * xlow <= xhigh and ylow <= yhigh - * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in - *INC_DIRECTION - * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION - * - * Note: there is only a single drive point for each routing segment (track) - * in the context of uni-directional wires - * - * Example : - * CHANX in INC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * ----------------------------> - * - * CHANX in DEC_DIRECTION - * (xlow, ylow) (xhigh, yhigh) - * | | - * \|/ \|/ - * <---------------------------- - * - * CHANY in INC_DIRECTION - * - * /|\ <-------(xhigh, yhigh) - * | - * | <-------(xlow, ylow) - * - * CHANY in DEC_DIRECTION - * - * | <-------(xhigh, yhigh) - * | - * \|/ <-------(xlow, ylow) - */ + * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh + * This is still the case when a logic block has a height > 1 + * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent + * where the routing segment starts and ends. + * Note that our convention alway keeps + * xlow <= xhigh and ylow <= yhigh + * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in INC_DIRECTION + * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION + * + * Note: there is only a single drive point for each routing segment (track) + * in the context of uni-directional wires + * + * Example : + * CHANX in INC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * ----------------------------> + * + * CHANX in DEC_DIRECTION + * (xlow, ylow) (xhigh, yhigh) + * | | + * \|/ \|/ + * <---------------------------- + * + * CHANY in INC_DIRECTION + * + * /|\ <-------(xhigh, yhigh) + * | + * | <-------(xlow, ylow) + * + * CHANY in DEC_DIRECTION + * + * | <-------(xhigh, yhigh) + * | + * \|/ <-------(xlow, ylow) + */ short node_xlow(const RRNodeId& node) const; short node_ylow(const RRNodeId& node) const; short node_xhigh(const RRNodeId& node) const; short node_yhigh(const RRNodeId& node) const; - /* Get the length of a routing track. - * Note that it is ONLY meaningful for CHANX and CHANY, which represents the - * number of logic blocks that a routing track spans - * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be - * always 0 - */ + /* Get the length of a routing track. + * Note that it is ONLY meaningful for CHANX and CHANY, which represents the number of logic blocks that a routing track spans + * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be always 0 + */ short node_length(const RRNodeId& node) const; /* A short-cut function to get coordinates of a node, - * where xmin of vtr::Rect = xlow, - * ymin of vtr::Rect = ylow, - * xmax of vtr::Rect = xhigh, - * ymax of vtr::Rect = yhigh. - */ + * where xmin of vtr::Rect = xlow, + * ymin of vtr::Rect = ylow, + * xmax of vtr::Rect = xhigh, + * ymax of vtr::Rect = yhigh. + */ vtr::Rect node_bounding_box(const RRNodeId& node) const; - /* Get node starting and ending points in routing channels. - * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and - *node_yhigh() - * For routing tracks in INC_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * For routing tracks in DEC_DIRECTION: - * node_start_coordinate() returns (xhigh, yhigh) as the starting point - * node_end_coordinate() returns (xlow, ylow) as the ending point - * - * For routing tracks in BI_DIRECTION: - * node_start_coordinate() returns (xlow, ylow) as the starting point - * node_end_coordinate() returns (xhigh, yhigh) as the ending point - * - * Applicable to routing track nodes only!!! - * This function will requires the types of node to be either CHANX or CHANY - */ + /* Get node starting and ending points in routing channels. + * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and node_yhigh() + * For routing tracks in INC_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * For routing tracks in DEC_DIRECTION: + * node_start_coordinate() returns (xhigh, yhigh) as the starting point + * node_end_coordinate() returns (xlow, ylow) as the ending point + * + * For routing tracks in BI_DIRECTION: + * node_start_coordinate() returns (xlow, ylow) as the starting point + * node_end_coordinate() returns (xhigh, yhigh) as the ending point + * + * Applicable to routing track nodes only!!! + * This function will requires the types of node to be either CHANX or CHANY + */ vtr::Point node_start_coordinate(const RRNodeId& node) const; vtr::Point node_end_coordinate(const RRNodeId& node) const; - /* Get the capacity of a node. - * Literally, how many nets can be mapped to the node. - * Typically, each node has a capacity of 1 but special nodes (SOURCE and - * SINK) will have a - * large number due to logic equivalent pins - * See Vaughn Betz's book for more details - */ + /* Get the capacity of a node. + * Literally, how many nets can be mapped to the node. + * Typically, each node has a capacity of 1 but special nodes (SOURCE and SINK) will have a + * large number due to logic equivalent pins + * See Vaughn Betz's book for more details + */ short node_capacity(const RRNodeId& node) const; /* Get the number of edges that drives a given node - * Note that each edge is typically driven by a node - * (true in VPR RRG that is currently supported, may not be true in customized - *RRG) - * This can also represent the number of drive nodes - * An example where fan-in of a node C is 2 - * - * edge A - * node A -------->+ - * | - * |-->node C - * edgeB | - * node B -------->+ - * - */ + * Note that each edge is typically driven by a node + * (true in VPR RRG that is currently supported, may not be true in customized RRG) + * This can also represent the number of drive nodes + * An example where fan-in of a node C is 2 + * + * edge A + * node A -------->+ + * | + * |-->node C + * edgeB | + * node B -------->+ + * + */ short node_fan_in(const RRNodeId& node) const; /* Get the number of edges that are driven a given node - * Note that each edge typically drives by a node - * (true in VPR RRG that is currently supported, may not be true in customized - *RRG) - * This can also represent the number of fan-out nodes - * An example where fan-out of a node A is 2 - * - * edge A - * node A -+--------> node B - * | - * | - * | edgeB - * +--------> node C - * - */ + * Note that each edge typically drives by a node + * (true in VPR RRG that is currently supported, may not be true in customized RRG) + * This can also represent the number of fan-out nodes + * An example where fan-out of a node A is 2 + * + * edge A + * node A -+--------> node B + * | + * | + * | edgeB + * +--------> node C + * + */ short node_fan_out(const RRNodeId& node) const; /* Get the ptc_num of a node - * The ptc (pin, track, or class) number is an integer - * that allows you to differentiate between wires, pins or sources/sinks with - *overlapping x,y coordinates or extent. - * This is useful for drawing rr-graphs nicely. - * For example, all the CHANX rr_nodes that have the same y coordinate and - *x-coordinates - * that overlap will have different ptc numbers, by convention starting at 0. - * This allows them to be drawn without overlapping, as the ptc num can be - *used as a track identifier. - * The main routing code does not care about ptc num. - * - * The ptc_num carries different meanings for different node types - * (true in VPR RRG that is currently supported, may not be true in customized - *RRG) - * CHANX or CHANY: the track id in routing channels - * OPIN or IPIN: the index of pins in the logic block data structure - * SOURCE and SINK: the class id of a pin (indicating logic equivalence of - *pins) in the logic block data structure - * - * To ease the access to ptc_num for different types of nodes: - * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes - * node_track_num() is designed for routing tracks, which are CHANX and CHANY - *nodes - * node_class_num() is designed for routing source and sinks, which are SOURCE - *and SINK nodes - * - * Due to a useful identifier, ptc_num is used in building fast look-up - */ + * The ptc (pin, track, or class) number is an integer + * that allows you to differentiate between wires, pins or sources/sinks with overlapping x,y coordinates or extent. + * This is useful for drawing rr-graphs nicely. + * For example, all the CHANX rr_nodes that have the same y coordinate and x-coordinates + * that overlap will have different ptc numbers, by convention starting at 0. + * This allows them to be drawn without overlapping, as the ptc num can be used as a track identifier. + * The main routing code does not care about ptc num. + * + * The ptc_num carries different meanings for different node types + * (true in VPR RRG that is currently supported, may not be true in customized RRG) + * CHANX or CHANY: the track id in routing channels + * OPIN or IPIN: the index of pins in the logic block data structure + * SOURCE and SINK: the class id of a pin (indicating logic equivalence of pins) in the logic block data structure + * + * To ease the access to ptc_num for different types of nodes: + * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes + * node_track_num() is designed for routing tracks, which are CHANX and CHANY nodes + * node_class_num() is designed for routing source and sinks, which are SOURCE and SINK nodes + * + * Due to a useful identifier, ptc_num is used in building fast look-up + */ short node_ptc_num(const RRNodeId& node) const; short node_pin_num(const RRNodeId& node) const; short node_track_num(const RRNodeId& node) const; short node_class_num(const RRNodeId& node) const; /* Get the index of cost data in the list of cost_indexed_data data structure - * It contains the routing cost for different nodes in the RRGraph - * when used in evaluate different routing paths - * See cross-reference section in this header file for more details - */ + * It contains the routing cost for different nodes in the RRGraph + * when used in evaluate different routing paths + * See cross-reference section in this header file for more details + */ short node_cost_index(const RRNodeId& node) const; /* Get the directionality of a node - * see node coordinate for details - * only matters the routing track nodes (CHANX and CHANY) - */ + * see node coordinate for details + * only matters the routing track nodes (CHANX and CHANY) + */ e_direction node_direction(const RRNodeId& node) const; - /* Get the side where the node physically locates on a logic block. - * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of - *logic block - * The side should be consistent to definition in architecture - *XML - * - * TOP - * +-----------+ - * | | - * LEFT | Logic | RIGHT - * | Block | - * | | - * +-----------+ - * BOTTOM - * - */ + /* Get the side where the node physically locates on a logic block. + * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of logic block + * The side should be consistent to definition in architecture XML + * + * TOP + * +-----------+ + * | | + * LEFT | Logic | RIGHT + * | Block | + * | | + * +-----------+ + * BOTTOM + * + */ e_side node_side(const RRNodeId& node) const; /* Get resistance of a node, used to built RC tree for timing analysis */ @@ -493,9 +441,8 @@ class RRGraph { float node_C(const RRNodeId& node) const; /* Get segment id of a node, containing the information of the routing - * segment that the node represents. See more details in the data structure - * t_segment_inf - */ + * segment that the node represents. See more details in the data structure t_segment_inf + */ RRSegmentId node_segment(const RRNodeId& node) const; /* Get the number of non-configurable incoming edges to a node */ @@ -522,120 +469,99 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; - /* Edge-related attributes - * An example to explain the terminology used in RRGraph - * edgeA - * nodeA --------> nodeB - * | edgeB - * +-------> nodeC - * - * +----------+----------------+----------------+ - * | Edge Id | edge_src_node | edge_sink_node | - * +----------+----------------+----------------+ - * | edgeA | nodeA | nodeB | - * +----------+----------------+----------------+ - * | edgeB | nodeA | nodeC | - * +----------+----------------+----------------+ - * - */ - size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this - accessor as outside - functions should use - RREdgeId */ + /* Edge-related attributes + * An example to explain the terminology used in RRGraph + * edgeA + * nodeA --------> nodeB + * | edgeB + * +-------> nodeC + * + * +----------+----------------+----------------+ + * | Edge Id | edge_src_node | edge_sink_node | + * +----------+----------------+----------------+ + * | edgeA | nodeA | nodeB | + * +----------+----------------+----------------+ + * | edgeB | nodeA | nodeC | + * +----------+----------------+----------------+ + * + */ + size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this accessor as outside functions should use RREdgeId */ /* Get the source node which drives a edge */ RRNodeId edge_src_node(const RREdgeId& edge) const; /* Get the sink node which a edge ends to */ RRNodeId edge_sink_node(const RREdgeId& edge) const; /* Get the switch id which a edge represents - * using switch id, timing and other information can be found - * for any node-to-node connection - */ + * using switch id, timing and other information can be found + * for any node-to-node connection + */ RRSwitchId edge_switch(const RREdgeId& edge) const; - /* Judge if a edge is configurable or not. - * A configurable edge is controlled by a programmable memory bit - * while a non-configurable edge is typically a hard-wired connection - */ + /* Judge if a edge is configurable or not. + * A configurable edge is controlled by a programmable memory bit + * while a non-configurable edge is typically a hard-wired connection + */ bool edge_is_configurable(const RREdgeId& edge) const; bool edge_is_non_configurable(const RREdgeId& edge) const; /* Switch Info */ - size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate - this accessor as - outside functions - should use - RRSwitchId */ + size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate this accessor as outside functions should use RRSwitchId */ /* Get the switch info of a switch used in this RRGraph */ const t_rr_switch_inf& get_switch(const RRSwitchId& switch_id) const; /* Segment Info */ - size_t segment_index(const RRSegmentId& segment_id) - const; /* TODO: deprecate this accessor as outside functions should use - RRSegmentId */ + size_t segment_index(const RRSegmentId& segment_id) const; /* TODO: deprecate this accessor as outside functions should use RRSegmentId */ /* Get the segment info of a routing segment used in this RRGraph */ const t_segment_inf& get_segment(const RRSegmentId& segment_id) const; /* Utilities */ /* Find the edges connecting two nodes */ - std::vector find_edges(const RRNodeId& src_node, - const RRNodeId& sink_node) const; + std::vector find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const; /* Find a node with given features from internal fast look-up */ - RRNodeId find_node(const short& x, - const short& y, - const t_rr_type& type, - const int& ptc, - const e_side& side = NUM_SIDES) const; - /* Find the number of routing tracks in a routing channel with a given - * coordinate */ - short chan_num_tracks(const short& x, - const short& y, - const t_rr_type& type) const; - - /* This flag is raised when the RRgraph contains invalid nodes/edges etc. - * Invalid nodes/edges exist when users remove nodes/edges from RRGraph - * RRGraph object will not immediately remove the nodes and edges but - * will mark them with invalid ids. - * Afterwards the is_dirty flag is raised as an indicator, to tell users - * that a clean-up process (invoked by compress() function)is required. - * After executing compress(), the is_dirty will be reset to false - * - * Example: - * RRGraph rr_graph; - * RRNodeId node_id; // Node id to be removed - * rr_graph.remove_node(node_id); - * // RRGraph is now dirty (rr_graph.is_dirty() == true) - * ... - * // During this period, when you perform data query, - * // You may encounter invalid nodes and edges - * // It may happen that - * // 1. their ids are invalid - * // 2. the cross-reference between nodes and edge, i.e., - * // node_in_edges(), node_out_edges() - * // 3. invalid node returned from find_node(), which use fast look-up - * ... - * rr_graph.compress(); - * // RRGraph is now clean (rr_graph.is_dirty() == false) - */ + RRNodeId find_node(const short& x, const short& y, const t_rr_type& type, const int& ptc, const e_side& side = NUM_SIDES) const; + /* Find the number of routing tracks in a routing channel with a given coordinate */ + short chan_num_tracks(const short& x, const short& y, const t_rr_type& type) const; + + /* This flag is raised when the RRgraph contains invalid nodes/edges etc. + * Invalid nodes/edges exist when users remove nodes/edges from RRGraph + * RRGraph object will not immediately remove the nodes and edges but + * will mark them with invalid ids. + * Afterwards the is_dirty flag is raised as an indicator, to tell users + * that a clean-up process (invoked by compress() function)is required. + * After executing compress(), the is_dirty will be reset to false + * + * Example: + * RRGraph rr_graph; + * RRNodeId node_id; // Node id to be removed + * rr_graph.remove_node(node_id); + * // RRGraph is now dirty (rr_graph.is_dirty() == true) + * ... + * // During this period, when you perform data query, + * // You may encounter invalid nodes and edges + * // It may happen that + * // 1. their ids are invalid + * // 2. the cross-reference between nodes and edge, i.e., + * // node_in_edges(), node_out_edges() + * // 3. invalid node returned from find_node(), which use fast look-up + * ... + * rr_graph.compress(); + * // RRGraph is now clean (rr_graph.is_dirty() == false) + */ bool is_dirty() const; - public: /* Echos */ - void print_node(const RRNodeId& node) - const; /* Print the detailed information of a node */ + public: /* Echos */ + void print_node(const RRNodeId& node) const; /* Print the detailed information of a node */ public: /* Public Validators */ - /* Check data structure for internal consistency - * This function will - * 1. re-build fast look-up for nodes - * 2. check all the edges and nodes are connected - * Literally, no invalid ids in fan-in/fan-out of edges/nodes - * 3. check that all the nodes representing routing tracks have valid id - *linked to its segment-related data structure - * 4. check that all the edges have valid id linked to its switch-related data - *structure - * - * Any valid and non-dirty RRGraph should pass this check - * It is highly recommended to run this function after building any RRGraph - *object - */ + /* Check data structure for internal consistency + * This function will + * 1. re-build fast look-up for nodes + * 2. check all the edges and nodes are connected + * Literally, no invalid ids in fan-in/fan-out of edges/nodes + * 3. check that all the nodes representing routing tracks have valid id linked to its segment-related data structure + * 4. check that all the edges have valid id linked to its switch-related data structure + * + * Any valid and non-dirty RRGraph should pass this check + * It is highly recommended to run this function after building any RRGraph object + */ bool validate() const; /* Validate is the node id does exist in the RRGraph */ @@ -645,87 +571,78 @@ class RRGraph { bool valid_edge_id(const RREdgeId& edge) const; public: /* Mutators */ - /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * For example: - * RRGraph rr_graph; - * // Add 1000 CHANX nodes to the RRGraph object - * rr_graph.reserve_nodes(1000); - * for (size_t i = 0; i < 1000; ++i) { - * rr_graph.create_node(CHANX); - * } - */ + /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * For example: + * RRGraph rr_graph; + * // Add 1000 CHANX nodes to the RRGraph object + * rr_graph.reserve_nodes(1000); + * for (size_t i = 0; i < 1000; ++i) { + * rr_graph.create_node(CHANX); + * } + */ void reserve_nodes(const unsigned long& num_nodes); - /* We use long data type for edges because the number of edges is very large - */ void reserve_edges(const unsigned long& num_edges); void reserve_switches(const size_t& num_switches); void reserve_segments(const size_t& num_segments); - /* Reserve the lists of input/output edges for a RR node to be memory - *efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * - * For example: - * RRGraph rr_graph; - * // Add 1 source node to the RRGraph object - * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the output edges for the source node - * rr_graph.reserve_node_out_edges(src_node, 5); - * // Add your edges - */ + /* Reserve the lists of input/output edges for a RR node to be memory efficient. + * This function is mainly used to reserve memory space inside RRGraph, + * when adding a large number of nodes/edge/switches/segments, + * in order to avoid memory fragements + * + * For example: + * RRGraph rr_graph; + * // Add 1 source node to the RRGraph object + * RRNodeId src_node = rr_graph.create_node(SOURCE); + * // Reserve the output edges for the source node + * rr_graph.reserve_node_out_edges(src_node, 5); + * // Add your edges + */ void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); - void reserve_node_out_edges(const RRNodeId& node, - const size_t& num_out_edges); + void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); /* Add new elements (node, edge, switch, etc.) to RRGraph */ - /* Add a node to the RRGraph with a deposited type - * Detailed node-level information should be added using the set_node_* - * functions - * For example: - * RRNodeId node = create_node(); - * set_node_xlow(node, 0); - */ + /* Add a node to the RRGraph with a deposited type + * Detailed node-level information should be added using the set_node_* functions + * For example: + * RRNodeId node = create_node(); + * set_node_xlow(node, 0); + */ RRNodeId create_node(const t_rr_type& type); - /* Add a edge to the RRGraph, by providing the source and sink node - * This function will automatically create a node and - * configure the nodes and edges in connection - */ - RREdgeId create_edge(const RRNodeId& source, - const RRNodeId& sink, - const RRSwitchId& switch_id); + /* Add a edge to the RRGraph, by providing the source and sink node + * This function will automatically create a node and + * configure the nodes and edges in connection + */ + RREdgeId create_edge(const RRNodeId& source, const RRNodeId& sink, const RRSwitchId& switch_id); RRSwitchId create_switch(const t_rr_switch_inf& switch_info); RRSegmentId create_segment(const t_segment_inf& segment_info); /* Remove elements from RRGraph - * This function just turn the nodes and edges to an invalid id without - * deletion - * This will cause the RRGraph to be marked as dirty (is_dirty(): false => - * true) - * To thoroughly remove the edges and nodes as well as clear the dirty flag, - * use compress() after the remove functions - * Example: - * RRGraph rr_graph; - * rr_graph.remove_node() - * .. // remove more nodes - * rr_graph.remove_edge() - * .. // remove more nodes - * // rr_graph.is_dirty() == true - * // If you want to access any node or edge - * // Check codes for ids should be intensively used - * // Such as, - * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { - * // if (RREdgeId::INVALID() != in_edge) { - * // ... - * // } - * // } - * rr_graph.compress() - * // rr_graph.is_dirty() == false - */ + * This function just turn the nodes and edges to an invalid id without deletion + * This will cause the RRGraph to be marked as dirty (is_dirty(): false => true) + * To thoroughly remove the edges and nodes as well as clear the dirty flag, + * use compress() after the remove functions + * Example: + * RRGraph rr_graph; + * rr_graph.remove_node() + * .. // remove more nodes + * rr_graph.remove_edge() + * .. // remove more nodes + * // rr_graph.is_dirty() == true + * // If you want to access any node or edge + * // Check codes for ids should be intensively used + * // Such as, + * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { + * // if (RREdgeId::INVALID() != in_edge) { + * // ... + * // } + * // } + * rr_graph.compress() + * // rr_graph.is_dirty() == false + */ void remove_node(const RRNodeId& node); void remove_edge(const RREdgeId& edge); @@ -736,9 +653,9 @@ class RRGraph { void set_node_yhigh(const RRNodeId& node, const short& yhigh); /* This is a short-cut function, set xlow/xhigh/ylow/yhigh for a node - * Please respect the following to configure the bb object: - * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; - */ + * Please respect the following to configure the bb object: + * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; + */ void set_node_bounding_box(const RRNodeId& node, const vtr::Rect& bb); void set_node_capacity(const RRNodeId& node, const short& capacity); @@ -746,34 +663,30 @@ class RRGraph { /* A generic function to set the ptc_num for a node */ void set_node_ptc_num(const RRNodeId& node, const short& ptc); - /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the - * pin id in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the pin id in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_pin_num(const RRNodeId& node, const short& pin_id); - /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is - * the track id in a routing channel, - * Routing channel is a group of routing tracks, each of which has a unique - * index - * An example - * Routing Channel - * +------------------+ - * | | - * ---|----------------->|----> track_id: 0 - * | | - * ... More tracks ... - * | | - * ---|----------------->|----> track_id: 1 - * | | - * +------------------+ - */ + /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is the track id in a routing channel, + * Routing channel is a group of routing tracks, each of which has a unique index + * An example + * Routing Channel + * +------------------+ + * | | + * ---|----------------->|----> track_id: 0 + * | | + * ... More tracks ... + * | | + * ---|----------------->|----> track_id: 1 + * | | + * +------------------+ + */ void set_node_track_num(const RRNodeId& node, const short& track_id); - /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is - * the class number in a logic block, - * See definition in t_type_descriptor data structure - */ + /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is the class number in a logic block, + * See definition in t_type_descriptor data structure + */ void set_node_class_num(const RRNodeId& node, const short& class_id); /* Set the routing cost index for node, see node_cost_index() for details */ @@ -790,47 +703,38 @@ class RRGraph { void set_node_R(const RRNodeId& node, const float& R); void set_node_C(const RRNodeId& node, const float& C); - /* Set the routing segment linked to a node, only applicable to CHANX and - * CHANY */ + /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in - * one vector, - * and efficiently iterate over all edges, or only the configurable or - * non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each - * node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) - */ + /* Edge partitioning is performed for efficiency, + * so we can store configurable and non-configurable edge lists for a node in one vector, + * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. + * This function will re-organize the incoming and outgoing edges of each node, + * i.e., node_in_edges() and node_out_edges(): + * 1. configurable edges (1st part of the vectors) + * 2. non-configurable edges (2nd part of the vectors) + */ void partition_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. - * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if - * it was set - */ + * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set + */ void compress(); /* top-level function to free, should be called when to delete a RRGraph */ void clear(); private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_node_in_edges(const RRNodeId& node); - /* classify the output edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_node_out_edges(const RRNodeId& node); - /* classify the input edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_in_edges(); - /* classify the output edges of each node to be configurable (1st part) and - * non-configurable (2nd part) */ + /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_out_edges(); private: /* Internal free functions */ @@ -876,10 +780,8 @@ class RRGraph { bool validate_node_edges(const RRNodeId& node) const; /* Edge-level checking */ - bool validate_node_is_edge_src(const RRNodeId& node, - const RREdgeId& edge) const; - bool validate_node_is_edge_sink(const RRNodeId& node, - const RREdgeId& edge) const; + bool validate_node_is_edge_src(const RRNodeId& node, const RREdgeId& edge) const; + bool validate_node_is_edge_sink(const RRNodeId& node, const RREdgeId& edge) const; bool validate_edge_switch(const RREdgeId& edge) const; bool validate_edge_src_node(const RREdgeId& edge) const; bool validate_edge_sink_node(const RREdgeId& edge) const; @@ -901,11 +803,10 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector - node_ids_; /* Unique identifiers for the nodes */ + vtr::vector node_ids_; /* Unique identifiers for the nodes */ vtr::vector node_types_; - vtr::vector > node_bounding_boxes_; + vtr::vector> node_bounding_boxes_; vtr::vector node_capacities_; vtr::vector node_ptc_nums_; @@ -914,15 +815,13 @@ class RRGraph { vtr::vector node_sides_; vtr::vector node_Rs_; vtr::vector node_Cs_; - vtr::vector node_segments_; /* Segment ids for each - node */ - /* Record the dividing point between configurable and non-configurable edges - * for each node */ + vtr::vector node_segments_; /* Segment ids for each node */ + /* Record the dividing point between configurable and non-configurable edges for each node */ vtr::vector node_num_non_configurable_in_edges_; vtr::vector node_num_non_configurable_out_edges_; - vtr::vector > node_in_edges_; - vtr::vector > node_out_edges_; + vtr::vector> node_in_edges_; + vtr::vector> node_out_edges_; /* Edge related data */ vtr::vector edge_ids_; /* unique identifiers for edges */ @@ -931,40 +830,29 @@ class RRGraph { vtr::vector edge_switches_; /* Switch related data - * Note that so far there has been no need to remove - * switches, so no such facility exists - */ + * Note that so far there has been no need to remove + * switches, so no such facility exists + */ /* Unique identifiers for switches which are used in the RRGraph */ vtr::vector switch_ids_; /* Detailed information about the switches, which are used in the RRGraph */ vtr::vector switches_; - /* Segment relatex data - * Segment info should be corrected annotated for each rr_node - * whose type is CHANX and CHANY - */ - vtr::vector - segment_ids_; /* unique identifiers for routing - segments which are used in the - RRGraph */ - vtr::vector segments_; /* detailed information - about the segments, - which are used in the - RRGraph */ + /* Segment relatex data + * Segment info should be corrected annotated for each rr_node + * whose type is CHANX and CHANY + */ + vtr::vector segment_ids_; /* unique identifiers for routing segments which are used in the RRGraph */ + vtr::vector segments_; /* detailed information about the segments, which are used in the RRGraph */ /* Misc. */ - /* A flag to indicate if the graph contains invalid elements (nodes/edges - * etc.) */ + /* A flag to indicate if the graph contains invalid elements (nodes/edges etc.) */ bool dirty_ = false; - /* Fast look-up to search a node by its type, coordinator and ptc_num - * Indexing of fast look-up: - * [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] - */ - typedef std::vector > > > > - NodeLookup; + /* Fast look-up to search a node by its type, coordinator and ptc_num + * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] + */ + typedef std::vector>>>> NodeLookup; mutable NodeLookup node_lookup_; }; From cdc0df9a602ac925eb0f86233843a8b1e510c705 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 00:05:03 -0700 Subject: [PATCH 38/58] further remove the large vector used temporarily when loading RRGraph --- vpr/src/device/create_rr_graph.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 99ccd5aab8c..3a2996adea8 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -56,7 +56,6 @@ void convert_rr_graph(std::vector& vpr_segments) { device_ctx.rr_graph.reserve_nodes((unsigned long)device_ctx.rr_nodes.size()); // Create the nodes - std::vector old_to_new_rr_node(device_ctx.rr_nodes.size(), RRNodeId::INVALID()); for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { auto& node = device_ctx.rr_nodes[inode]; RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); @@ -85,9 +84,6 @@ void convert_rr_graph(std::vector& vpr_segments) { short irc_data = node.cost_index(); short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); - - VTR_ASSERT(inode < old_to_new_rr_node.size()); - old_to_new_rr_node[inode] = rr_node; } /* Reserve list of edges to be memory efficient */ @@ -104,8 +100,8 @@ void convert_rr_graph(std::vector& vpr_segments) { /* Reserve input and output edges for the node: * this is very important to avoid memory fragments!!! */ - device_ctx.rr_graph.reserve_node_in_edges(old_to_new_rr_node[inode], node.fan_in()); - device_ctx.rr_graph.reserve_node_out_edges(old_to_new_rr_node[inode], node.num_edges()); + device_ctx.rr_graph.reserve_node_in_edges(RRNodeId(inode), node.fan_in()); + device_ctx.rr_graph.reserve_node_out_edges(RRNodeId(inode), node.num_edges()); } /* Add edges for each node */ @@ -115,11 +111,8 @@ void convert_rr_graph(std::vector& vpr_segments) { size_t isink_node = node.edge_sink_node(iedge); int iswitch = node.edge_switch(iedge); - VTR_ASSERT(inode < old_to_new_rr_node.size()); - VTR_ASSERT(isink_node < old_to_new_rr_node.size()); - - device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], - old_to_new_rr_node[isink_node], + device_ctx.rr_graph.create_edge(RRNodeId(inode), + RRNodeId(isink_node), RRSwitchId(iswitch)); } } From 9cc9bff9d658eec876d6016f83ed5414b7a5c514 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 17:08:24 -0700 Subject: [PATCH 39/58] change num_non_config in/out edges to short integer, for sake of memory footprint --- vpr/src/device/rr_graph_obj.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f5611ce9b61..957d701b945 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -817,8 +817,8 @@ class RRGraph { vtr::vector node_Cs_; vtr::vector node_segments_; /* Segment ids for each node */ /* Record the dividing point between configurable and non-configurable edges for each node */ - vtr::vector node_num_non_configurable_in_edges_; - vtr::vector node_num_non_configurable_out_edges_; + vtr::vector node_num_non_configurable_in_edges_; + vtr::vector node_num_non_configurable_out_edges_; vtr::vector> node_in_edges_; vtr::vector> node_out_edges_; From 02ed2adab14a5e84a29de7d5a086182681ee6bc9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 17:29:50 -0700 Subject: [PATCH 40/58] use NdMatrix in fast node lookup in RRGraph object --- vpr/src/device/rr_graph_obj.cpp | 31 ++++++++++++++----------------- vpr/src/device/rr_graph_obj.h | 3 ++- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 2a93c588ad8..f610f166682 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -393,21 +393,21 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ /* Check if x, y, type and ptc, side is valid */ if ((x < 0) /* See if x is smaller than the index of first element */ - || (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */ + || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ if ((y < 0) /* See if y is smaller than the index of first element */ - || (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */ + || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ /* itype is always larger than -1, we can skip checking */ - if (itype > node_lookup_[x][y].size() - 1) { /* See if type is large than the index of last element */ + if (itype > node_lookup_.dim_size(2) - 1) { /* See if type is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } @@ -438,20 +438,20 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& /* Check if x, y, type and ptc is valid */ if ((x < 0) /* See if x is smaller than the index of first element */ - || (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */ + || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ if ((y < 0) /* See if y is smaller than the index of first element */ - || (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */ + || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ - if ((size_t(type) > node_lookup_[x][y].size() - 1)) { /* See if type is large than the index of last element */ + if ((size_t(type) > node_lookup_.dim_size(2) - 1)) { /* See if type is large than the index of last element */ /* Return a zero range! */ return 0; } @@ -1136,21 +1136,18 @@ void RRGraph::build_fast_node_lookup() const { /* Free the current fast node look-up, we will rebuild a new one here */ invalidate_fast_node_lookup(); + /* Get the max (x,y) and then we can resize the ndmatrix */ + vtr::Point max_coord(0, 0); for (auto node : nodes()) { - size_t x = node_xlow(node); - if (x >= node_lookup_.size()) { - node_lookup_.resize(x + 1); - } + max_coord.set_x(std::max(max_coord.x(), node_xlow(node))); + max_coord.set_y(std::max(max_coord.y(), node_ylow(node))); + } + node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); + for (auto node : nodes()) { + size_t x = node_xlow(node); size_t y = node_ylow(node); - if (y >= node_lookup_[x].size()) { - node_lookup_[x].resize(y + 1); - } - size_t itype = node_type(node); - if (itype >= node_lookup_[x][y].size()) { - node_lookup_[x][y].resize(itype + 1); - } size_t ptc = node_ptc_num(node); if (ptc >= node_lookup_[x][y][itype].size()) { diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 957d701b945..0591675e135 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -200,6 +200,7 @@ #include /* EXTERNAL library header files go second*/ +#include "vtr_ndmatrix.h" #include "vtr_vector.h" #include "vtr_range.h" #include "vtr_geometry.h" @@ -852,7 +853,7 @@ class RRGraph { /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] */ - typedef std::vector>>>> NodeLookup; + typedef vtr::NdMatrix>,3> NodeLookup; mutable NodeLookup node_lookup_; }; From 679b06d38ba314aef7288fd66a06bdf37c67e9cd Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 18:49:41 -0700 Subject: [PATCH 41/58] replace full vector of edge ids which simple edge range --- vpr/src/device/rr_graph_obj.cpp | 83 +++++++++++++++++++++++---------- vpr/src/device/rr_graph_obj.h | 9 +++- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index f610f166682..2747be84f97 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -15,13 +15,35 @@ #include "rr_graph_obj.h" #include "rr_graph_obj_utils.h" +/******************************************************************** + * Constructors + *******************************************************************/ +RRGraph::RRGraph() { + /* Set edge range to be zero ! */ + edge_id_range_ = 0; +} + //Accessors RRGraph::node_range RRGraph::nodes() const { return vtr::make_range(node_ids_.begin(), node_ids_.end()); } -RRGraph::edge_range RRGraph::edges() const { - return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); +std::vector RRGraph::edges() const { + /* Create a list of valid edge ids */ + std::vector edge_ids; + /* Reserve the edge list, since it could be very last. Also exclude the invalid edge ids */ + edge_ids.reserve(edge_id_range_ - invalid_edge_ids_.size()); + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + edge_ids.push_back(RREdgeId(id)); + } + return edge_ids; } RRGraph::switch_range RRGraph::switches() const { @@ -789,7 +811,6 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve a list of edges */ void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ - this->edge_ids_.reserve(num_edges); this->edge_src_nodes_.reserve(num_edges); this->edge_sink_nodes_.reserve(num_edges); this->edge_switches_.reserve(num_edges); @@ -861,17 +882,17 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons VTR_ASSERT(valid_node_id(sink)); VTR_ASSERT(valid_switch_id(switch_id)); - //Allocate an ID - RREdgeId edge_id = RREdgeId(edge_ids_.size()); - - //Initialize the attributes - edge_ids_.push_back(edge_id); + /* Allocate an ID */ + RREdgeId edge_id = RREdgeId(edge_id_range_); + /* Expand range of edge ids */ + edge_id_range_++; + /* Initialize the attributes */ edge_src_nodes_.push_back(source); edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - //Add the edge to the nodes + /* Add the edge to the nodes */ node_out_edges_[source].push_back(edge_id); node_in_edges_[sink].push_back(edge_id); @@ -933,8 +954,9 @@ void RRGraph::remove_edge(const RREdgeId& edge) { RRNodeId src_node = edge_src_node(edge); RRNodeId sink_node = edge_sink_node(edge); - //Invalidate node to edge references - // TODO: consider making this optional (e.g. if called from remove_node) + /* Invalidate node to edge references + * TODO: consider making this optional (e.g. if called from remove_node) + */ for (size_t i = 0; i < node_out_edges_[src_node].size(); ++i) { if (node_out_edges_[src_node][i] == edge) { node_out_edges_[src_node][i] = RREdgeId::INVALID(); @@ -948,8 +970,8 @@ void RRGraph::remove_edge(const RREdgeId& edge) { } } - //Mark edge invalid - edge_ids_[edge] = RREdgeId::INVALID(); + /* Mark edge invalid */ + invalid_edge_ids_[edge] = true; set_dirty(); } @@ -1189,7 +1211,8 @@ bool RRGraph::valid_node_id(const RRNodeId& node) const { } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { - return size_t(edge) < edge_ids_.size() && edge_ids_[edge] == edge; + return (size_t(edge) < edge_id_range_) + && (invalid_edge_ids_.end() == invalid_edge_ids_.find(edge)); } /* check if a given switch id is valid or not */ @@ -1235,9 +1258,9 @@ bool RRGraph::validate_node_sizes() const { } bool RRGraph::validate_edge_sizes() const { - return edge_src_nodes_.size() == edge_ids_.size() - && edge_sink_nodes_.size() == edge_ids_.size() - && edge_switches_.size() == edge_ids_.size(); + return edge_src_nodes_.size() == edge_id_range_ + && edge_sink_nodes_.size() == edge_id_range_ + && edge_switches_.size() == edge_id_range_; } bool RRGraph::validate_switch_sizes() const { @@ -1250,7 +1273,7 @@ bool RRGraph::validate_segment_sizes() const { void RRGraph::compress() { vtr::vector node_id_map(node_ids_.size()); - vtr::vector edge_id_map(edge_ids_.size()); + vtr::vector edge_id_map(edge_id_range_); build_id_maps(node_id_map, edge_id_map); @@ -1267,7 +1290,22 @@ void RRGraph::compress() { void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { node_id_map = compress_ids(node_ids_); - edge_id_map = compress_ids(edge_ids_); + + /* Build edge ids including invalid ids and compress */ + vtr::vector edge_ids; + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Give and invalid id */ + edge_ids.push_back(RREdgeId::INVALID()); + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + edge_ids.push_back(RREdgeId(id)); + } + edge_id_map = compress_ids(edge_ids); + } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { @@ -1292,16 +1330,13 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { - edge_ids_ = clean_and_reorder_ids(edge_id_map); + edge_id_range_ = edge_id_map.size(); edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map); edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map); edge_switches_ = clean_and_reorder_values(edge_switches_, edge_id_map); VTR_ASSERT(validate_edge_sizes()); - - VTR_ASSERT_MSG(are_contiguous(edge_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(edge_ids_), "All Ids should be valid"); } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { @@ -1342,7 +1377,7 @@ void RRGraph::clear_nodes() { /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { - edge_ids_.clear(); + edge_id_range_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 0591675e135..1b088ffb8f0 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -198,6 +198,7 @@ /* Standard header files required go first */ #include #include +#include /* EXTERNAL library header files go second*/ #include "vtr_ndmatrix.h" @@ -224,6 +225,9 @@ class RRGraph { typedef vtr::Range switch_range; typedef vtr::Range segment_range; + public: /* Constructors */ + RRGraph(); + public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments * To iterate over the nodes/edges/switches/segments in a RRGraph, @@ -249,7 +253,7 @@ class RRGraph { * } */ node_range nodes() const; - edge_range edges() const; + std::vector edges() const; switch_range switches() const; segment_range segments() const; @@ -825,7 +829,8 @@ class RRGraph { vtr::vector> node_out_edges_; /* Edge related data */ - vtr::vector edge_ids_; /* unique identifiers for edges */ + size_t edge_id_range_; /* Range of edge ids */ + std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_switches_; From a6f8c49a51380f9f01076a542bdbad596a459166 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 20:33:06 -0700 Subject: [PATCH 42/58] replace node id vector with constant and minor bug fixing --- vpr/src/device/rr_graph_obj.cpp | 109 +++++++++++++++++++++----------- vpr/src/device/rr_graph_obj.h | 10 +-- 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 2747be84f97..b2dea1b0bf6 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -19,13 +19,31 @@ * Constructors *******************************************************************/ RRGraph::RRGraph() { + /* Set node range to be zero ! */ + node_id_range_ = 0; /* Set edge range to be zero ! */ edge_id_range_ = 0; } -//Accessors -RRGraph::node_range RRGraph::nodes() const { - return vtr::make_range(node_ids_.begin(), node_ids_.end()); +/******************************************************************** + * Accessors + *******************************************************************/ +std::vector RRGraph::nodes() const { + /* Create a list of valid node ids */ + std::vector node_ids; + /* Reserve the edge list, since it could be very last. Also exclude the invalid node ids */ + node_ids.reserve(node_id_range_ - invalid_node_ids_.size()); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + node_ids.push_back(RRNodeId(id)); + } + return node_ids; } std::vector RRGraph::edges() const { @@ -41,7 +59,7 @@ std::vector RRGraph::edges() const { continue; } /* Reach here, this is a valid id, push to the edge list */ - edge_ids.push_back(RREdgeId(id)); + edge_ids.push_back(RREdgeId(id)); } return edge_ids; } @@ -414,14 +432,14 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ size_t iside = side; /* Check if x, y, type and ptc, side is valid */ - if ((x < 0) /* See if x is smaller than the index of first element */ + if ((x < 0) /* See if x is smaller than the index of first element */ || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ - if ((y < 0) /* See if y is smaller than the index of first element */ + if ((y < 0) /* See if y is smaller than the index of first element */ || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); @@ -790,11 +808,11 @@ void RRGraph::clear_dirty() { void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ - this->node_ids_.reserve(num_nodes); this->node_types_.reserve(num_nodes); this->node_bounding_boxes_.reserve(num_nodes); this->node_capacities_.reserve(num_nodes); this->node_ptc_nums_.reserve(num_nodes); + this->node_cost_indices_.reserve(num_nodes); this->node_directions_.reserve(num_nodes); this->node_sides_.reserve(num_nodes); this->node_Rs_.reserve(num_nodes); @@ -846,11 +864,12 @@ void RRGraph::reserve_node_out_edges(const RRNodeId& node, const size_t& num_out /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { - //Allocate an ID - RRNodeId node_id = RRNodeId(node_ids_.size()); + /* Allocate an ID */ + RRNodeId node_id = RRNodeId(node_id_range_); + /* Expand range of node ids */ + node_id_range_++; - //Initialize the attributes - node_ids_.push_back(node_id); + /* Initialize the attributes */ node_types_.push_back(type); node_bounding_boxes_.emplace_back(-1, -1, -1, -1); @@ -938,7 +957,7 @@ void RRGraph::remove_node(const RRNodeId& node) { } //Mark node invalid - node_ids_[node] = RRNodeId::INVALID(); + invalid_node_ids_[node] = true; //Invalidate the node look-up invalidate_fast_node_lookup(); @@ -1207,7 +1226,8 @@ void RRGraph::initialize_fast_node_lookup() const { } bool RRGraph::valid_node_id(const RRNodeId& node) const { - return size_t(node) < node_ids_.size() && node_ids_[node] == node; + return (size_t(node) < node_id_range_) + && (invalid_node_ids_.end() == invalid_node_ids_.find(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { @@ -1241,20 +1261,20 @@ bool RRGraph::validate_sizes() const { } bool RRGraph::validate_node_sizes() const { - return node_types_.size() == node_ids_.size() - && node_bounding_boxes_.size() == node_ids_.size() - && node_capacities_.size() == node_ids_.size() - && node_ptc_nums_.size() == node_ids_.size() - && node_cost_indices_.size() == node_ids_.size() - && node_directions_.size() == node_ids_.size() - && node_sides_.size() == node_ids_.size() - && node_Rs_.size() == node_ids_.size() - && node_Cs_.size() == node_ids_.size() - && node_segments_.size() == node_ids_.size() - && node_num_non_configurable_in_edges_.size() == node_ids_.size() - && node_num_non_configurable_out_edges_.size() == node_ids_.size() - && node_in_edges_.size() == node_ids_.size() - && node_out_edges_.size() == node_ids_.size(); + return node_types_.size() == node_id_range_ + && node_bounding_boxes_.size() == node_id_range_ + && node_capacities_.size() == node_id_range_ + && node_ptc_nums_.size() == node_id_range_ + && node_cost_indices_.size() == node_id_range_ + && node_directions_.size() == node_id_range_ + && node_sides_.size() == node_id_range_ + && node_Rs_.size() == node_id_range_ + && node_Cs_.size() == node_id_range_ + && node_segments_.size() == node_id_range_ + && node_num_non_configurable_in_edges_.size() == node_id_range_ + && node_num_non_configurable_out_edges_.size() == node_id_range_ + && node_in_edges_.size() == node_id_range_ + && node_out_edges_.size() == node_id_range_; } bool RRGraph::validate_edge_sizes() const { @@ -1272,7 +1292,7 @@ bool RRGraph::validate_segment_sizes() const { } void RRGraph::compress() { - vtr::vector node_id_map(node_ids_.size()); + vtr::vector node_id_map(node_id_range_); vtr::vector edge_id_map(edge_id_range_); build_id_maps(node_id_map, edge_id_map); @@ -1284,12 +1304,31 @@ void RRGraph::compress() { invalidate_fast_node_lookup(); + /* Clear invalid node list */ + invalid_node_ids_.clear(); + + /* Clear invalid edge list */ + invalid_edge_ids_.clear(); + clear_dirty(); } void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { - node_id_map = compress_ids(node_ids_); + /* Build node ids including invalid ids and compress */ + vtr::vector node_ids; + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Give and invalid id */ + node_ids.push_back(RRNodeId::INVALID()); + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + node_ids.push_back(RRNodeId(id)); + } + node_id_map = compress_ids(node_ids); /* Build edge ids including invalid ids and compress */ vtr::vector edge_ids; @@ -1298,18 +1337,18 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); /* Give and invalid id */ - edge_ids.push_back(RREdgeId::INVALID()); + edge_ids.push_back(RREdgeId::INVALID()); continue; } /* Reach here, this is a valid id, push to the edge list */ - edge_ids.push_back(RREdgeId(id)); + edge_ids.push_back(RREdgeId(id)); } edge_id_map = compress_ids(edge_ids); } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { - node_ids_ = clean_and_reorder_ids(node_id_map); + node_id_range_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); @@ -1324,9 +1363,6 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map); VTR_ASSERT(validate_node_sizes()); - - VTR_ASSERT_MSG(are_contiguous(node_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(node_ids_), "All Ids should be valid"); } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { @@ -1351,8 +1387,7 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m /* Empty all the vectors related to nodes */ void RRGraph::clear_nodes() { - node_ids_.clear(); - + node_id_range_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 1b088ffb8f0..c5c1108c35e 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -252,7 +252,7 @@ class RRGraph { * // Do something with each segment * } */ - node_range nodes() const; + std::vector nodes() const; std::vector edges() const; switch_range switches() const; segment_range segments() const; @@ -808,7 +808,9 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector node_ids_; /* Unique identifiers for the nodes */ + size_t node_id_range_; /* Range of node ids */ + std::unordered_map invalid_node_ids_; /* Invalid edge ids */ + vtr::vector node_types_; vtr::vector> node_bounding_boxes_; @@ -829,7 +831,7 @@ class RRGraph { vtr::vector> node_out_edges_; /* Edge related data */ - size_t edge_id_range_; /* Range of edge ids */ + size_t edge_id_range_; /* Range of edge ids */ std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; @@ -858,7 +860,7 @@ class RRGraph { /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] */ - typedef vtr::NdMatrix>,3> NodeLookup; + typedef vtr::NdMatrix>, 3> NodeLookup; mutable NodeLookup node_lookup_; }; From 40cbe1949d49ac245bb5a7ba5a370785d7a77980 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 20:46:49 -0700 Subject: [PATCH 43/58] further remove using nodes() and edges() inside RRGraph methods to save memory footprint --- vpr/src/device/rr_graph_obj.cpp | 122 +++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index b2dea1b0bf6..df12f3144e4 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -477,14 +477,14 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& initialize_fast_node_lookup(); /* Check if x, y, type and ptc is valid */ - if ((x < 0) /* See if x is smaller than the index of first element */ + if ((x < 0) /* See if x is smaller than the index of first element */ || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ - if ((y < 0) /* See if y is smaller than the index of first element */ + if ((y < 0) /* See if y is smaller than the index of first element */ || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return 0; @@ -529,15 +529,21 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const { /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_segment(node)) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_node_segment(RRNodeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Node %d has an invalid segment id (%d)!\n", - size_t(node), size_t(node_segment(node))); + id, size_t(node_segment(RRNodeId(id)))); } return all_valid; } @@ -551,15 +557,21 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_switch(edge)) { + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_edge_switch(RREdgeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Edge %d has an invalid switch id (%d)!\n", - size_t(edge), size_t(edge_switch(edge))); + id, size_t(edge_switch(RREdgeId(id)))); } return all_valid; } @@ -663,8 +675,14 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const { /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_in_edges(node)) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_node_in_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! @@ -678,8 +696,14 @@ bool RRGraph::validate_nodes_in_edges() const { /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_out_edges(node)) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_node_out_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! @@ -717,15 +741,21 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_src_node(edge)) { + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_edge_src_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid source node %d!\n", - size_t(edge), size_t(edge_src_node(edge))); + id, size_t(edge_src_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -734,15 +764,21 @@ bool RRGraph::validate_edge_src_nodes() const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_sink_node(edge)) { + for (size_t id = 0; id < edge_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { + VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + /* Skip this id */ + continue; + } + if (true == validate_edge_sink_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid sink node %d!\n", - size_t(edge), size_t(edge_sink_node(edge))); + id, size_t(edge_sink_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -1147,8 +1183,14 @@ void RRGraph::partition_node_out_edges(const RRNodeId& node) { */ void RRGraph::partition_in_edges() { /* For each node */ - for (auto node : nodes()) { - this->partition_node_in_edges(node); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + this->partition_node_in_edges(RRNodeId(id)); } } @@ -1157,8 +1199,14 @@ void RRGraph::partition_in_edges() { */ void RRGraph::partition_out_edges() { /* For each node */ - for (auto node : nodes()) { - this->partition_node_out_edges(node); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + this->partition_node_out_edges(RRNodeId(id)); } } @@ -1179,13 +1227,26 @@ void RRGraph::build_fast_node_lookup() const { /* Get the max (x,y) and then we can resize the ndmatrix */ vtr::Point max_coord(0, 0); - for (auto node : nodes()) { - max_coord.set_x(std::max(max_coord.x(), node_xlow(node))); - max_coord.set_y(std::max(max_coord.y(), node_ylow(node))); + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + max_coord.set_x(std::max(max_coord.x(), node_xlow(RRNodeId(id)))); + max_coord.set_y(std::max(max_coord.y(), node_ylow(RRNodeId(id)))); } node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); - for (auto node : nodes()) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + RRNodeId node = RRNodeId(id); size_t x = node_xlow(node); size_t y = node_ylow(node); size_t itype = node_type(node); @@ -1376,7 +1437,14 @@ void RRGraph::clean_edges(const vtr::vector& edge_id_map) { } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { - for (const auto& node : nodes()) { + for (size_t id = 0; id < node_id_range_; ++id) { + /* Try to find if this is an invalid id or not */ + if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { + VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + /* Skip this id */ + continue; + } + RRNodeId node = RRNodeId(id); node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map); node_out_edges_[node] = update_valid_refs(node_out_edges_[node], edge_id_map); From 25d654040d994eef345ebcc5d9f078dd401472e4 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 21:19:35 -0700 Subject: [PATCH 44/58] move convert rr_graph to be close to build_rr_graph --- vpr/src/device/create_rr_graph.cpp | 2 +- vpr/src/device/rr_graph_obj.cpp | 1 - vpr/src/route/rr_graph.cpp | 9 ++++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 3a2996adea8..53baf9771a0 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -23,7 +23,7 @@ *routers ********************************************************************/ void convert_rr_graph(std::vector& vpr_segments) { - vtr::ScopedStartFinishTimer timer("Build routing resource graph object"); + vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); /* IMPORTANT: to build clock tree, * vpr added segments to the original arch segments diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index df12f3144e4..9e05494dcde 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -1405,7 +1405,6 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, edge_ids.push_back(RREdgeId(id)); } edge_id_map = compress_ids(edge_ids); - } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 733ac6e41a4..ca3bb370bc4 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -332,6 +332,9 @@ void create_rr_graph(const t_graph_type graph_type, base_cost_type, &det_routing_arch->wire_to_rr_ipin_switch, det_routing_arch->read_rr_graph_filename.c_str()); + + /* Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); } } else { if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) { @@ -370,15 +373,15 @@ void create_rr_graph(const t_graph_type graph_type, det_routing_arch->wire_to_rr_ipin_switch, base_cost_type); } + + /* Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); } process_non_config_sets(); print_rr_graph_stats(); - /* Create rr_graph object: load rr_nodes to the object */ - convert_rr_graph(segment_inf); - //Write out rr graph file if needed if (!det_routing_arch->write_rr_graph_filename.empty()) { write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf); From a96a1f0c172e96099ffbf17e479c857cbf80aed6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 21 Nov 2019 21:32:54 -0700 Subject: [PATCH 45/58] move clear RRGraph object to free_rr_graph() --- vpr/src/device/create_rr_graph.cpp | 3 --- vpr/src/route/rr_graph.cpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 53baf9771a0..20f79efd6c2 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -31,9 +31,6 @@ void convert_rr_graph(std::vector& vpr_segments) { */ auto& device_ctx = g_vpr_ctx.mutable_device(); - /* make sure we have a clean empty rr_graph */ - device_ctx.rr_graph.clear(); - /* The number of switches are in general small, * reserve switches may not bring significant memory efficiency * So, we just use create_switch to push_back each time diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index ca3bb370bc4..12b3a101401 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -1379,6 +1379,9 @@ void free_rr_graph() { * allocated, as ALL the chunk allocated data is already free! */ auto& device_ctx = g_vpr_ctx.mutable_device(); + /* Clear the RRGraph object */ + device_ctx.rr_graph.clear(); + device_ctx.read_rr_graph_filename.clear(); device_ctx.rr_node_indices.clear(); From 643f21ff112a1feab67a260c8b419d5dc19f6f97 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 22 Nov 2019 11:17:10 -0700 Subject: [PATCH 46/58] now node_in/out_edges are arranged in the same vector with delimeters to identify groups --- vpr/src/device/create_rr_graph.cpp | 3 +- vpr/src/device/rr_graph_obj.cpp | 139 +++++++++++++++-------------- vpr/src/device/rr_graph_obj.h | 23 +++-- 3 files changed, 88 insertions(+), 77 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 20f79efd6c2..a81ece928e7 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -97,8 +97,7 @@ void convert_rr_graph(std::vector& vpr_segments) { /* Reserve input and output edges for the node: * this is very important to avoid memory fragments!!! */ - device_ctx.rr_graph.reserve_node_in_edges(RRNodeId(inode), node.fan_in()); - device_ctx.rr_graph.reserve_node_out_edges(RRNodeId(inode), node.num_edges()); + device_ctx.rr_graph.reserve_node_inout_edges(RRNodeId(inode), node.fan_in() + node.num_edges()); } /* Add edges for each node */ diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 9e05494dcde..3f7cfb16555 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -158,11 +158,11 @@ vtr::Point RRGraph::node_end_coordinate(const RRNodeId& node) const { } short RRGraph::node_fan_in(const RRNodeId& node) const { - return node_in_edges(node).size(); + return node_num_in_edges_[node]; } short RRGraph::node_fan_out(const RRNodeId& node) const { - return node_out_edges(node).size(); + return node_inout_edges_[node].size() - node_num_in_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { @@ -232,42 +232,36 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { /* * Get the number of configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough */ short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { - return node_configurable_in_edges(node).size(); + return node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; } /* * Get the number of configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough */ short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_configurable_out_edges(node).size(); + return node_inout_edges_[node].size() - node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; } /* * Get the number of non-configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() + * Use the node_num_configurable_in_edges() * when the rr_graph edges have been partitioned * This can avoid unneccessary walkthrough */ short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const { - return node_non_configurable_in_edges(node).size(); + return node_num_non_configurable_in_edges_[node]; } /* * Get the number of non-configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() + * Use the node_num_configurable_out_edges() * when the rr_graph edges have been partitioned * This can avoid unneccessary walkthrough */ short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { - return node_non_configurable_out_edges(node).size(); + return node_num_non_configurable_out_edges_[node]; } /* Get the list of configurable edges from the input edges of a given node @@ -277,16 +271,16 @@ RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) co /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).begin(); + /* By default the configurable edges will be stored at the first part of the inputedge list (0 to XX) */ + auto begin = node_inout_edges_[node].begin(); - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; + /* By default the non-configurable edges will be stored at second part of the input edge list (XX to end) */ + auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; return vtr::make_range(begin, end); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of non configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const { @@ -294,15 +288,15 @@ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node VTR_ASSERT_SAFE(valid_node_id(node)); /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; + auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end(); + auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node]; return vtr::make_range(begin, end); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const { @@ -310,15 +304,15 @@ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) c VTR_ASSERT_SAFE(valid_node_id(node)); /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).begin(); + auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node]; /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; + auto end = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; return vtr::make_range(begin, end); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of non configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const { @@ -326,22 +320,22 @@ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& nod VTR_ASSERT_SAFE(valid_node_id(node)); /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; + auto begin = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end(); + auto end = node_inout_edges_[node].end(); return vtr::make_range(begin, end); } RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_out_edges_[node].begin(), node_out_edges_[node].end()); + return vtr::make_range(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end()); } RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_in_edges_[node].begin(), node_in_edges_[node].end()); + return vtr::make_range(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node]); } //Edge attributes @@ -845,7 +839,9 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ this->node_types_.reserve(num_nodes); + this->node_bounding_boxes_.reserve(num_nodes); + this->node_capacities_.reserve(num_nodes); this->node_ptc_nums_.reserve(num_nodes); this->node_cost_indices_.reserve(num_nodes); @@ -854,12 +850,13 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { this->node_Rs_.reserve(num_nodes); this->node_Cs_.reserve(num_nodes); this->node_segments_.reserve(num_nodes); + this->node_num_non_configurable_in_edges_.reserve(num_nodes); this->node_num_non_configurable_out_edges_.reserve(num_nodes); /* Edge-relate vectors */ - this->node_in_edges_.reserve(num_nodes); - this->node_out_edges_.reserve(num_nodes); + this->node_num_in_edges_.reserve(num_nodes); + this->node_inout_edges_.reserve(num_nodes); } /* Reserve a list of edges */ @@ -883,19 +880,11 @@ void RRGraph::reserve_segments(const size_t& num_segments) { } /* Reserve the input edges for a node */ -void RRGraph::reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges) { +void RRGraph::reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges) { /* Validate the node id */ VTR_ASSERT_SAFE(true == valid_node_id(node)); /* Reserve the input edge list */ - this->node_in_edges_[node].reserve(num_in_edges); -} - -/* Reserve the input edges for a node */ -void RRGraph::reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges) { - /* Validate the node id */ - VTR_ASSERT_SAFE(true == valid_node_id(node)); - /* Reserve the input edge list */ - this->node_out_edges_[node].reserve(num_out_edges); + this->node_inout_edges_[node].reserve(num_inout_edges); } /* Mutators */ @@ -919,12 +908,12 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_Cs_.push_back(0.); node_segments_.push_back(RRSegmentId::INVALID()); - node_in_edges_.emplace_back(); //Initially empty - node_out_edges_.emplace_back(); //Initially empty - node_num_non_configurable_in_edges_.emplace_back(); //Initially empty node_num_non_configurable_out_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(); //Initially empty + node_inout_edges_.emplace_back(); //Initially empty + invalidate_fast_node_lookup(); VTR_ASSERT(validate_sizes()); @@ -947,9 +936,17 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - /* Add the edge to the nodes */ - node_out_edges_[source].push_back(edge_id); - node_in_edges_[sink].push_back(edge_id); + /* Add the edge to the nodes: + * We use delimeter to split incoming and outgoing edges + * for a node into two groups + * When adding the new edge, + * we will add the edge id to the tail of node_inout_edge list of source node + * we will insert the edge id to the delimeter of node_inout_edge list of sink node + * the delimeter node_num_in_edges_ will be updated for the sink node! + */ + node_inout_edges_[source].push_back(edge_id); + node_inout_edges_[sink].insert(node_inout_edges_[sink].begin() + (size_t)node_num_in_edges_[sink], edge_id); + node_num_in_edges_[sink]++; VTR_ASSERT(validate_sizes()); @@ -1012,15 +1009,15 @@ void RRGraph::remove_edge(const RREdgeId& edge) { /* Invalidate node to edge references * TODO: consider making this optional (e.g. if called from remove_node) */ - for (size_t i = 0; i < node_out_edges_[src_node].size(); ++i) { - if (node_out_edges_[src_node][i] == edge) { - node_out_edges_[src_node][i] = RREdgeId::INVALID(); + for (size_t i = 0; i < node_inout_edges_[src_node].size(); ++i) { + if (node_inout_edges_[src_node][i] == edge) { + node_inout_edges_[src_node][i] = RREdgeId::INVALID(); break; } } - for (size_t i = 0; i < node_in_edges_[sink_node].size(); ++i) { - if (node_in_edges_[sink_node][i] == edge) { - node_in_edges_[sink_node][i] = RREdgeId::INVALID(); + for (size_t i = 0; i < node_inout_edges_[sink_node].size(); ++i) { + if (node_inout_edges_[sink_node][i] == edge) { + node_inout_edges_[sink_node][i] = RREdgeId::INVALID(); break; } } @@ -1145,15 +1142,15 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_ */ void RRGraph::partition_node_in_edges(const RRNodeId& node) { //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_in_edges_[node].begin(), node_in_edges_[node].end(), + auto first_non_config_edge = std::partition(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node], [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - size_t num_conf_edges = std::distance(node_in_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_in_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range + size_t num_conf_edges = std::distance(node_inout_edges_[node].begin(), first_non_config_edge); + size_t num_non_conf_edges = node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_in_edges_[node].size(), + VTR_ASSERT_MSG(num_non_conf_edges <= (size_t)node_num_in_edges_[node], "Exceeded RR node maximum number of non-configurable input edges"); node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing @@ -1164,15 +1161,15 @@ void RRGraph::partition_node_in_edges(const RRNodeId& node) { */ void RRGraph::partition_node_out_edges(const RRNodeId& node) { //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_out_edges_[node].begin(), node_out_edges_[node].end(), + auto first_non_config_edge = std::partition(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end(), [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - size_t num_conf_edges = std::distance(node_out_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_out_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range + size_t num_conf_edges = std::distance(node_inout_edges_[node].begin() + node_num_in_edges_[node], first_non_config_edge); + size_t num_non_conf_edges = node_inout_edges_[node].size() - node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_out_edges_[node].size(), + VTR_ASSERT_MSG(num_non_conf_edges <= node_inout_edges_[node].size() - node_num_in_edges_[node], "Exceeded RR node maximum number of non-configurable output edges"); node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing @@ -1334,8 +1331,8 @@ bool RRGraph::validate_node_sizes() const { && node_segments_.size() == node_id_range_ && node_num_non_configurable_in_edges_.size() == node_id_range_ && node_num_non_configurable_out_edges_.size() == node_id_range_ - && node_in_edges_.size() == node_id_range_ - && node_out_edges_.size() == node_id_range_; + && node_num_in_edges_.size() == node_id_range_ + && node_inout_edges_.size() == node_id_range_; } bool RRGraph::validate_edge_sizes() const { @@ -1422,6 +1419,12 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_Rs_ = clean_and_reorder_values(node_Rs_, node_id_map); node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map); + node_segments_ = clean_and_reorder_values(node_segments_, node_id_map); + node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map); + node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map); + node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map); + node_inout_edges_ = clean_and_reorder_values(node_inout_edges_, node_id_map); + VTR_ASSERT(validate_node_sizes()); } @@ -1444,11 +1447,9 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m continue; } RRNodeId node = RRNodeId(id); - node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map); - node_out_edges_[node] = update_valid_refs(node_out_edges_[node], edge_id_map); + node_inout_edges_[node] = update_valid_refs(node_inout_edges_[node], edge_id_map); - VTR_ASSERT_MSG(all_valid(node_in_edges_[node]), "All Ids should be valid"); - VTR_ASSERT_MSG(all_valid(node_out_edges_[node]), "All Ids should be valid"); + VTR_ASSERT_MSG(all_valid(node_inout_edges_[node]), "All Ids should be valid"); } } @@ -1470,8 +1471,8 @@ void RRGraph::clear_nodes() { node_num_non_configurable_in_edges_.clear(); node_num_non_configurable_out_edges_.clear(); - node_in_edges_.clear(); - node_out_edges_.clear(); + node_num_in_edges_.clear(); + node_inout_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index c5c1108c35e..dc3f3145876 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -602,12 +602,11 @@ class RRGraph { * RRGraph rr_graph; * // Add 1 source node to the RRGraph object * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the output edges for the source node - * rr_graph.reserve_node_out_edges(src_node, 5); + * // Reserve the input and output edges for the source node + * rr_graph.reserve_node_inout_edges(src_node, 5); * // Add your edges */ - void reserve_node_in_edges(const RRNodeId& node, const size_t& num_in_edges); - void reserve_node_out_edges(const RRNodeId& node, const size_t& num_out_edges); + void reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges); /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type @@ -827,8 +826,20 @@ class RRGraph { vtr::vector node_num_non_configurable_in_edges_; vtr::vector node_num_non_configurable_out_edges_; - vtr::vector> node_in_edges_; - vtr::vector> node_out_edges_; + /* Record the dividing point between input and output edges for each node + * Both input and output edges are stored in a list for memory efficiency + * We use a dividing point to identify the groups + * The edges are arranged in as the following format: + * Index in list: + * 0--------------------------------------------------------------------------------------------------->N + * + * |<----------------------->|^ |<------------------------->| + * node_num_non_cinfigurable_in_edges | node_num_non_configurable_out_edges + * | + * node_num_in_edges + */ + vtr::vector node_num_in_edges_; + vtr::vector> node_inout_edges_; /* Edge related data */ size_t edge_id_range_; /* Range of edge ids */ From 5342a7cc651f7b92edc6a7078ee33d2cbba90c97 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 22 Nov 2019 11:24:11 -0700 Subject: [PATCH 47/58] minor code format fix --- vpr/src/device/rr_graph_obj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 3f7cfb16555..1e8bacf8553 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -911,7 +911,7 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_num_non_configurable_in_edges_.emplace_back(); //Initially empty node_num_non_configurable_out_edges_.emplace_back(); //Initially empty - node_num_in_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(); //Initially empty node_inout_edges_.emplace_back(); //Initially empty invalidate_fast_node_lookup(); From 5e62b39fa4a54b95f971f302ecb8f7e08f868ffa Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:02:19 -0500 Subject: [PATCH 48/58] vpr: Rename RRGraph node/edge_id_range_ to num_nodes_/num_egdes_ --- vpr/src/device/rr_graph_obj.cpp | 95 ++++++++++++++++----------------- vpr/src/device/rr_graph_obj.h | 4 +- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 1e8bacf8553..696aedd15e0 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -20,9 +20,9 @@ *******************************************************************/ RRGraph::RRGraph() { /* Set node range to be zero ! */ - node_id_range_ = 0; + num_nodes_ = 0; /* Set edge range to be zero ! */ - edge_id_range_ = 0; + num_edges_ = 0; } /******************************************************************** @@ -32,8 +32,8 @@ std::vector RRGraph::nodes() const { /* Create a list of valid node ids */ std::vector node_ids; /* Reserve the edge list, since it could be very last. Also exclude the invalid node ids */ - node_ids.reserve(node_id_range_ - invalid_node_ids_.size()); - for (size_t id = 0; id < node_id_range_; ++id) { + node_ids.reserve(num_nodes_ - invalid_node_ids_.size()); + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -50,8 +50,8 @@ std::vector RRGraph::edges() const { /* Create a list of valid edge ids */ std::vector edge_ids; /* Reserve the edge list, since it could be very last. Also exclude the invalid edge ids */ - edge_ids.reserve(edge_id_range_ - invalid_edge_ids_.size()); - for (size_t id = 0; id < edge_id_range_; ++id) { + edge_ids.reserve(num_edges_ - invalid_edge_ids_.size()); + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -523,7 +523,7 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const { /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -551,7 +551,7 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -669,7 +669,7 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const { /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -690,7 +690,7 @@ bool RRGraph::validate_nodes_in_edges() const { /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -735,7 +735,7 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -758,7 +758,7 @@ bool RRGraph::validate_edge_src_nodes() const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -890,9 +890,9 @@ void RRGraph::reserve_node_inout_edges(const RRNodeId& node, const size_t& num_i /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { /* Allocate an ID */ - RRNodeId node_id = RRNodeId(node_id_range_); + RRNodeId node_id = RRNodeId(num_nodes_); /* Expand range of node ids */ - node_id_range_++; + num_nodes_++; /* Initialize the attributes */ node_types_.push_back(type); @@ -927,9 +927,9 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons VTR_ASSERT(valid_switch_id(switch_id)); /* Allocate an ID */ - RREdgeId edge_id = RREdgeId(edge_id_range_); + RREdgeId edge_id = RREdgeId(num_edges_); /* Expand range of edge ids */ - edge_id_range_++; + num_edges_++; /* Initialize the attributes */ edge_src_nodes_.push_back(source); @@ -1180,7 +1180,7 @@ void RRGraph::partition_node_out_edges(const RRNodeId& node) { */ void RRGraph::partition_in_edges() { /* For each node */ - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1196,7 +1196,7 @@ void RRGraph::partition_in_edges() { */ void RRGraph::partition_out_edges() { /* For each node */ - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1224,7 +1224,7 @@ void RRGraph::build_fast_node_lookup() const { /* Get the max (x,y) and then we can resize the ndmatrix */ vtr::Point max_coord(0, 0); - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1236,7 +1236,7 @@ void RRGraph::build_fast_node_lookup() const { } node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1284,12 +1284,12 @@ void RRGraph::initialize_fast_node_lookup() const { } bool RRGraph::valid_node_id(const RRNodeId& node) const { - return (size_t(node) < node_id_range_) + return (size_t(node) < num_nodes_) && (invalid_node_ids_.end() == invalid_node_ids_.find(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { - return (size_t(edge) < edge_id_range_) + return (size_t(edge) < num_edges_) && (invalid_edge_ids_.end() == invalid_edge_ids_.find(edge)); } @@ -1319,26 +1319,25 @@ bool RRGraph::validate_sizes() const { } bool RRGraph::validate_node_sizes() const { - return node_types_.size() == node_id_range_ - && node_bounding_boxes_.size() == node_id_range_ - && node_capacities_.size() == node_id_range_ - && node_ptc_nums_.size() == node_id_range_ - && node_cost_indices_.size() == node_id_range_ - && node_directions_.size() == node_id_range_ - && node_sides_.size() == node_id_range_ - && node_Rs_.size() == node_id_range_ - && node_Cs_.size() == node_id_range_ - && node_segments_.size() == node_id_range_ - && node_num_non_configurable_in_edges_.size() == node_id_range_ - && node_num_non_configurable_out_edges_.size() == node_id_range_ - && node_num_in_edges_.size() == node_id_range_ - && node_inout_edges_.size() == node_id_range_; + return node_types_.size() == num_nodes_ + && node_bounding_boxes_.size() == num_nodes_ + && node_capacities_.size() == num_nodes_ + && node_ptc_nums_.size() == num_nodes_ + && node_cost_indices_.size() == num_nodes_ + && node_directions_.size() == num_nodes_ + && node_sides_.size() == num_nodes_ + && node_Rs_.size() == num_nodes_ + && node_Cs_.size() == num_nodes_ + && node_segments_.size() == num_nodes_ + && node_num_non_configurable_in_edges_.size() == num_nodes_ + && node_num_non_configurable_out_edges_.size() == num_nodes_ + && node_inout_edges_.size() == num_nodes_; } bool RRGraph::validate_edge_sizes() const { - return edge_src_nodes_.size() == edge_id_range_ - && edge_sink_nodes_.size() == edge_id_range_ - && edge_switches_.size() == edge_id_range_; + return edge_src_nodes_.size() == num_edges_ + && edge_sink_nodes_.size() == num_edges_ + && edge_switches_.size() == num_edges_; } bool RRGraph::validate_switch_sizes() const { @@ -1350,8 +1349,8 @@ bool RRGraph::validate_segment_sizes() const { } void RRGraph::compress() { - vtr::vector node_id_map(node_id_range_); - vtr::vector edge_id_map(edge_id_range_); + vtr::vector node_id_map(num_nodes_); + vtr::vector edge_id_map(num_edges_); build_id_maps(node_id_map, edge_id_map); @@ -1375,7 +1374,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { /* Build node ids including invalid ids and compress */ vtr::vector node_ids; - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1390,7 +1389,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, /* Build edge ids including invalid ids and compress */ vtr::vector edge_ids; - for (size_t id = 0; id < edge_id_range_; ++id) { + for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); @@ -1405,7 +1404,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { - node_id_range_ = node_id_map.size(); + num_nodes_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); @@ -1429,7 +1428,7 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { - edge_id_range_ = edge_id_map.size(); + num_edges_ = edge_id_map.size(); edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map); edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map); @@ -1439,7 +1438,7 @@ void RRGraph::clean_edges(const vtr::vector& edge_id_map) { } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { - for (size_t id = 0; id < node_id_range_; ++id) { + for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); @@ -1455,7 +1454,7 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m /* Empty all the vectors related to nodes */ void RRGraph::clear_nodes() { - node_id_range_ = 0; + num_nodes_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); @@ -1480,7 +1479,7 @@ void RRGraph::clear_nodes() { /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { - edge_id_range_ = 0; + num_edges_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index dc3f3145876..56b4beae63d 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -807,7 +807,7 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - size_t node_id_range_; /* Range of node ids */ + size_t num_nodes_; /* Range of node ids */ std::unordered_map invalid_node_ids_; /* Invalid edge ids */ vtr::vector node_types_; @@ -842,7 +842,7 @@ class RRGraph { vtr::vector> node_inout_edges_; /* Edge related data */ - size_t edge_id_range_; /* Range of edge ids */ + size_t num_edges_; /* Range of edge ids */ std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; From 967d18fa21d26ba256c650715cf7e6afc21a1b23 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:11:41 -0500 Subject: [PATCH 49/58] vpr: Prefer using valid_node_id()/valid_edge_id() in RRGraph This avoids exposing the details of how we are tracking invalid edges through-out the RRGraph implementation code. --- vpr/src/device/rr_graph_obj.cpp | 45 +++++++++++---------------------- 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 696aedd15e0..82fee29dd57 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -35,8 +35,7 @@ std::vector RRGraph::nodes() const { node_ids.reserve(num_nodes_ - invalid_node_ids_.size()); for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -53,8 +52,7 @@ std::vector RRGraph::edges() const { edge_ids.reserve(num_edges_ - invalid_edge_ids_.size()); for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -525,8 +523,7 @@ bool RRGraph::validate_node_segments() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -553,8 +550,7 @@ bool RRGraph::validate_edge_switches() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -671,8 +667,7 @@ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -692,8 +687,7 @@ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -737,8 +731,7 @@ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -760,8 +753,7 @@ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } @@ -1182,8 +1174,7 @@ void RRGraph::partition_in_edges() { /* For each node */ for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1198,8 +1189,7 @@ void RRGraph::partition_out_edges() { /* For each node */ for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1226,8 +1216,7 @@ void RRGraph::build_fast_node_lookup() const { vtr::Point max_coord(0, 0); for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1238,8 +1227,7 @@ void RRGraph::build_fast_node_lookup() const { for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } @@ -1376,8 +1364,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector node_ids; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Give and invalid id */ node_ids.push_back(RRNodeId::INVALID()); continue; @@ -1391,8 +1378,7 @@ void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector edge_ids; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_edge_ids_.end() != invalid_edge_ids_.find(RREdgeId(id))) { - VTR_ASSERT_SAFE(true == invalid_edge_ids_.at(RREdgeId(id))); + if (!valid_edge_id(RREdgeId(id))) { /* Give and invalid id */ edge_ids.push_back(RREdgeId::INVALID()); continue; @@ -1440,8 +1426,7 @@ void RRGraph::clean_edges(const vtr::vector& edge_id_map) { void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ - if (invalid_node_ids_.end() != invalid_node_ids_.find(RRNodeId(id))) { - VTR_ASSERT_SAFE(true == invalid_node_ids_.at(RRNodeId(id))); + if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } From d0422467b24747e1ebeda6f727828a6bc2719bb0 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:13:53 -0500 Subject: [PATCH 50/58] vpr: Use std::unordered_set for tracking invalied IDs in RRGraph Previously used a std::unordered_map but the value was unused. --- vpr/src/device/rr_graph_obj.cpp | 8 ++++---- vpr/src/device/rr_graph_obj.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 82fee29dd57..2723650f089 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -982,7 +982,7 @@ void RRGraph::remove_node(const RRNodeId& node) { } //Mark node invalid - invalid_node_ids_[node] = true; + invalid_node_ids_.insert(node); //Invalidate the node look-up invalidate_fast_node_lookup(); @@ -1015,7 +1015,7 @@ void RRGraph::remove_edge(const RREdgeId& edge) { } /* Mark edge invalid */ - invalid_edge_ids_[edge] = true; + invalid_edge_ids_.insert(edge); set_dirty(); } @@ -1273,12 +1273,12 @@ void RRGraph::initialize_fast_node_lookup() const { bool RRGraph::valid_node_id(const RRNodeId& node) const { return (size_t(node) < num_nodes_) - && (invalid_node_ids_.end() == invalid_node_ids_.find(node)); + && (!invalid_node_ids_.count(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { return (size_t(edge) < num_edges_) - && (invalid_edge_ids_.end() == invalid_edge_ids_.find(edge)); + && (!invalid_edge_ids_.count(edge)); } /* check if a given switch id is valid or not */ diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 56b4beae63d..f9d0c4eada2 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -808,7 +808,7 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ size_t num_nodes_; /* Range of node ids */ - std::unordered_map invalid_node_ids_; /* Invalid edge ids */ + std::unordered_set invalid_node_ids_; /* Invalid edge ids */ vtr::vector node_types_; @@ -843,7 +843,7 @@ class RRGraph { /* Edge related data */ size_t num_edges_; /* Range of edge ids */ - std::unordered_map invalid_edge_ids_; /* Invalid edge ids */ + std::unordered_set invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_switches_; From 8f1fa62ab6103ff3b41f50ec49cef823b7e85a65 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:36:34 -0500 Subject: [PATCH 51/58] vpr: Use lazy iterators to iterate through RRGraph nodes/edges This should be more run-time and memory efficient than creating a vector of the entire range and returning it. --- vpr/src/device/rr_graph_obj.cpp | 36 ++++------------------ vpr/src/device/rr_graph_obj.h | 53 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 2723650f089..12c7d7efc1f 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -28,38 +28,14 @@ RRGraph::RRGraph() { /******************************************************************** * Accessors *******************************************************************/ -std::vector RRGraph::nodes() const { - /* Create a list of valid node ids */ - std::vector node_ids; - /* Reserve the edge list, since it could be very last. Also exclude the invalid node ids */ - node_ids.reserve(num_nodes_ - invalid_node_ids_.size()); - for (size_t id = 0; id < num_nodes_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_node_id(RRNodeId(id))) { - /* Skip this id */ - continue; - } - /* Reach here, this is a valid id, push to the edge list */ - node_ids.push_back(RRNodeId(id)); - } - return node_ids; +RRGraph::lazy_node_range RRGraph::nodes() const { + return vtr::make_range(lazy_node_iterator(RRNodeId(0), invalid_node_ids_), + lazy_node_iterator(RRNodeId(num_nodes_), invalid_node_ids_)); } -std::vector RRGraph::edges() const { - /* Create a list of valid edge ids */ - std::vector edge_ids; - /* Reserve the edge list, since it could be very last. Also exclude the invalid edge ids */ - edge_ids.reserve(num_edges_ - invalid_edge_ids_.size()); - for (size_t id = 0; id < num_edges_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_edge_id(RREdgeId(id))) { - /* Skip this id */ - continue; - } - /* Reach here, this is a valid id, push to the edge list */ - edge_ids.push_back(RREdgeId(id)); - } - return edge_ids; +RRGraph::lazy_edge_range RRGraph::edges() const { + return vtr::make_range(lazy_edge_iterator(RREdgeId(0), invalid_edge_ids_), + lazy_edge_iterator(RREdgeId(num_edges_), invalid_edge_ids_)); } RRGraph::switch_range RRGraph::switches() const { diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f9d0c4eada2..6c726492624 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -213,6 +213,53 @@ class RRGraph { public: /* Types */ + class lazy_node_iterator : public std::iterator { + public: + lazy_node_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} + iterator operator++() { + value_ = RRNodeId(size_t(value_) + 1); + return *this; + } + iterator operator--() { + value_ = RRNodeId(size_t(value_) - 1); + return *this; + } + value_type operator*() const { return (invalid_ids_.count(value_)) ? RRNodeId::INVALID() : value_; } + + friend bool operator==(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + + class lazy_edge_iterator : public std::iterator { + public: + lazy_edge_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} + iterator operator++() { + value_ = RREdgeId(size_t(value_) + 1); + return *this; + } + iterator operator--() { + value_ = RREdgeId(size_t(value_) - 1); + return *this; + } + value_type operator*() const { return (invalid_ids_.count(value_)) ? RREdgeId::INVALID() : value_; } + + friend bool operator==(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + + /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; @@ -225,6 +272,8 @@ class RRGraph { typedef vtr::Range switch_range; typedef vtr::Range segment_range; + typedef vtr::Range lazy_node_range; + typedef vtr::Range lazy_edge_range; public: /* Constructors */ RRGraph(); @@ -252,8 +301,8 @@ class RRGraph { * // Do something with each segment * } */ - std::vector nodes() const; - std::vector edges() const; + lazy_node_range nodes() const; + lazy_edge_range edges() const; switch_range switches() const; segment_range segments() const; From 52d696c780bed7a83415ab39e2e7ba29429f39e6 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 10:49:37 -0500 Subject: [PATCH 52/58] vpr: Refactor lazy RRGraph node/edge iterators into a common template class --- vpr/src/device/rr_graph_obj.cpp | 9 +++---- vpr/src/device/rr_graph_obj.h | 43 ++++++++++----------------------- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 12c7d7efc1f..dcabffe5176 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -18,11 +18,10 @@ /******************************************************************** * Constructors *******************************************************************/ -RRGraph::RRGraph() { - /* Set node range to be zero ! */ - num_nodes_ = 0; - /* Set edge range to be zero ! */ - num_edges_ = 0; +RRGraph::RRGraph() + : num_nodes_(0) + , num_edges_(0) { + //Pass } /******************************************************************** diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 6c726492624..aa8d08be33f 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -213,52 +213,35 @@ class RRGraph { public: /* Types */ - class lazy_node_iterator : public std::iterator { - public: - lazy_node_iterator(value_type init, const std::unordered_set& invalid_ids) - : value_(init) - , invalid_ids_(invalid_ids) {} - iterator operator++() { - value_ = RRNodeId(size_t(value_) + 1); - return *this; - } - iterator operator--() { - value_ = RRNodeId(size_t(value_) - 1); - return *this; - } - value_type operator*() const { return (invalid_ids_.count(value_)) ? RRNodeId::INVALID() : value_; } - - friend bool operator==(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return lhs.value_ == rhs.value_; } - friend bool operator!=(const lazy_node_iterator lhs, const lazy_node_iterator rhs) { return !(lhs == rhs); } - - private: - value_type value_; - const std::unordered_set& invalid_ids_; - }; - class lazy_edge_iterator : public std::iterator { + template + class lazy_id_iterator : public std::iterator { public: - lazy_edge_iterator(value_type init, const std::unordered_set& invalid_ids) + typedef typename std::iterator::value_type value_type; + typedef typename std::iterator::iterator iterator; + lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) : value_(init) , invalid_ids_(invalid_ids) {} iterator operator++() { - value_ = RREdgeId(size_t(value_) + 1); + value_ = ID(size_t(value_) + 1); return *this; } iterator operator--() { - value_ = RREdgeId(size_t(value_) - 1); + value_ = ID(size_t(value_) - 1); return *this; } - value_type operator*() const { return (invalid_ids_.count(value_)) ? RREdgeId::INVALID() : value_; } + value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } - friend bool operator==(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return lhs.value_ == rhs.value_; } - friend bool operator!=(const lazy_edge_iterator lhs, const lazy_edge_iterator rhs) { return !(lhs == rhs); } + friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } private: value_type value_; - const std::unordered_set& invalid_ids_; + const std::unordered_set& invalid_ids_; }; + typedef lazy_id_iterator lazy_node_iterator; + typedef lazy_id_iterator lazy_edge_iterator; /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; From 0907cc4194f669fd4dd7d54aaa10df3c4751190a Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 11:01:07 -0500 Subject: [PATCH 53/58] vpr: Use forward declaration to move lazy_id_iterator implementation Users of the RRGraph shouldn't care how the edge/node iteration is implemented so move the implementation below the public methods to improve readability. --- vpr/src/device/rr_graph_obj.h | 81 +++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index aa8d08be33f..7a0461a6728 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -214,49 +214,26 @@ class RRGraph { public: /* Types */ + //Lazy iterator utility forward declaration template - class lazy_id_iterator : public std::iterator { - public: - typedef typename std::iterator::value_type value_type; - typedef typename std::iterator::iterator iterator; - lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) - : value_(init) - , invalid_ids_(invalid_ids) {} - iterator operator++() { - value_ = ID(size_t(value_) + 1); - return *this; - } - iterator operator--() { - value_ = ID(size_t(value_) - 1); - return *this; - } - value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } - - friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } - friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } - - private: - value_type value_; - const std::unordered_set& invalid_ids_; - }; - - typedef lazy_id_iterator lazy_node_iterator; - typedef lazy_id_iterator lazy_edge_iterator; + class lazy_id_iterator; /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; typedef vtr::vector::const_iterator segment_iterator; + typedef lazy_id_iterator lazy_node_iterator; + typedef lazy_id_iterator lazy_edge_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; typedef vtr::Range edge_range; typedef vtr::Range switch_range; typedef vtr::Range segment_range; - typedef vtr::Range lazy_node_range; typedef vtr::Range lazy_edge_range; + public: /* Constructors */ RRGraph(); @@ -760,6 +737,54 @@ class RRGraph { /* top-level function to free, should be called when to delete a RRGraph */ void clear(); + public: /* Type implementations */ + + /* + * This class (forward delcared above) is a template used to represent a lazily calculated + * iterator of the specified ID type. The key assumption made is that the ID space is + * contiguous and can be walked by incrementing the underlying ID value. To account for + * invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for + * ID values in the set. + * + * It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes()) + * just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_), + * and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_). + */ + template + class lazy_id_iterator : public std::iterator { + public: + //Since we pass ID as a template to std::iterator we need to use an explicit 'typename' + //to bring the value_type and iterator names into scope + typedef typename std::iterator::value_type value_type; + typedef typename std::iterator::iterator iterator; + + lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} + + //Advance to the next ID value + iterator operator++() { + value_ = ID(size_t(value_) + 1); + return *this; + } + + //Advance to the previous ID value + iterator operator--() { + value_ = ID(size_t(value_) - 1); + return *this; + } + + //Dereference the iterator + value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } + + friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + private: /* Internal Mutators to perform edge partitioning */ /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ void partition_node_in_edges(const RRNodeId& node); From 88cd88c6eac98f75a02cd52a682df20d152edc3c Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 13:33:20 -0500 Subject: [PATCH 54/58] vpr: Reduce RRGraph memory usage by merging node edge arrays We now use a single array to store the edges associated with a node. The array is sorted into sub-ranges (e.g. incoming/outgoing, configurable/nonconfigurable) which still allows efficient iteration through the edge subranges. We store the sizes of the various sub-ranges to enable quickly determination of the delimiters between sub-ranges. We also use a raw pointer for the edge array (rather than a vtr::vector) which further saves memory. The create_edge() routine now no longer inserts the edge into the node data. Instead a single call is made to rebuild_node_edges() which will walk the various RRGraph::edge_* members to precisely allocate the relevant node_edges_ and node_num*edges_ data members. The trade-off of this change is that the various node_*_edges() will not work properly after an edge is added to the RR graph until rebuild_node_edges() is called. Currently it rebuilds the node edges from scratch, and so calls to it should be minimized (the preferred approach is to add all edges and then call rebuild_node_edges() once). If needed, support for incrementally rebuilding node_edges could be added (while the use of a single array per node type in general require insertion not at the end of the array, an O(n) operation, the number of edges per node is typically bounded by a small constant, so it would still be reasonably efficient); it is not currently required and so is left as *potential* future work should the need for it arise. --- vpr/src/device/create_rr_graph.cpp | 11 +- vpr/src/device/rr_graph_obj.cpp | 319 +++++++++++++++------------- vpr/src/device/rr_graph_obj.h | 118 +++++----- vpr/src/device/rr_graph_obj_utils.h | 26 +++ 4 files changed, 248 insertions(+), 226 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index a81ece928e7..6faced34b31 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -91,15 +91,6 @@ void convert_rr_graph(std::vector& vpr_segments) { } device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); - // Create the edges - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - const auto& node = device_ctx.rr_nodes[inode]; - /* Reserve input and output edges for the node: - * this is very important to avoid memory fragments!!! - */ - device_ctx.rr_graph.reserve_node_inout_edges(RRNodeId(inode), node.fan_in() + node.num_edges()); - } - /* Add edges for each node */ for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { const auto& node = device_ctx.rr_nodes[inode]; @@ -121,7 +112,7 @@ void convert_rr_graph(std::vector& vpr_segments) { * See how the router will use the edges and determine the strategy * if we want to partition the edges first or depends on the routing needs */ - device_ctx.rr_graph.partition_edges(); + device_ctx.rr_graph.rebuild_node_edges(); /* Essential check for rr_graph, build look-up and */ if (false == device_ctx.rr_graph.validate()) { diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index dcabffe5176..59907c4cdec 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -135,7 +135,7 @@ short RRGraph::node_fan_in(const RRNodeId& node) const { } short RRGraph::node_fan_out(const RRNodeId& node) const { - return node_inout_edges_[node].size() - node_num_in_edges_[node]; + return node_num_out_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { @@ -214,7 +214,7 @@ short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { * Get the number of configurable output edges of a node */ short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_inout_edges_[node].size() - node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; + return node_num_out_edges_[node] - node_num_non_configurable_in_edges_[node]; } /* @@ -237,78 +237,65 @@ short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { return node_num_non_configurable_out_edges_[node]; } +RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node]); +} + +RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node]); +} + +RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); +} + /* Get the list of configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the inputedge list (0 to XX) */ - auto begin = node_inout_edges_[node].begin(); - - /* By default the non-configurable edges will be stored at second part of the input edge list (XX to end) */ - auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]); } /* Get the list of non configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_inout_edges_[node].begin() + node_num_in_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range(node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node], + node_edges_[node].get() + node_num_in_edges_[node]); } /* Get the list of configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_inout_edges_[node].begin() + node_num_in_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]); } /* Get the list of non configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ - VTR_ASSERT_SAFE(valid_node_id(node)); - - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_inout_edges_[node].end() - node_num_non_configurable_out_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_inout_edges_[node].end(); - - return vtr::make_range(begin, end); -} - -RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end()); -} -RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { - VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node]); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node], + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); } //Edge attributes @@ -818,12 +805,12 @@ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { this->node_Cs_.reserve(num_nodes); this->node_segments_.reserve(num_nodes); + /* Edge-related vectors */ + this->node_num_in_edges_.reserve(num_nodes); + this->node_num_out_edges_.reserve(num_nodes); this->node_num_non_configurable_in_edges_.reserve(num_nodes); this->node_num_non_configurable_out_edges_.reserve(num_nodes); - - /* Edge-relate vectors */ - this->node_num_in_edges_.reserve(num_nodes); - this->node_inout_edges_.reserve(num_nodes); + this->node_edges_.reserve(num_nodes); } /* Reserve a list of edges */ @@ -846,14 +833,6 @@ void RRGraph::reserve_segments(const size_t& num_segments) { this->segments_.reserve(num_segments); } -/* Reserve the input edges for a node */ -void RRGraph::reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges) { - /* Validate the node id */ - VTR_ASSERT_SAFE(true == valid_node_id(node)); - /* Reserve the input edge list */ - this->node_inout_edges_[node].reserve(num_inout_edges); -} - /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { /* Allocate an ID */ @@ -875,11 +854,12 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_Cs_.push_back(0.); node_segments_.push_back(RRSegmentId::INVALID()); - node_num_non_configurable_in_edges_.emplace_back(); //Initially empty - node_num_non_configurable_out_edges_.emplace_back(); //Initially empty + node_edges_.emplace_back(); //Initially empty - node_num_in_edges_.emplace_back(); //Initially empty - node_inout_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(0); + node_num_out_edges_.emplace_back(0); + node_num_non_configurable_in_edges_.emplace_back(0); + node_num_non_configurable_out_edges_.emplace_back(0); invalidate_fast_node_lookup(); @@ -903,17 +883,10 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - /* Add the edge to the nodes: - * We use delimeter to split incoming and outgoing edges - * for a node into two groups - * When adding the new edge, - * we will add the edge id to the tail of node_inout_edge list of source node - * we will insert the edge id to the delimeter of node_inout_edge list of sink node - * the delimeter node_num_in_edges_ will be updated for the sink node! - */ - node_inout_edges_[source].push_back(edge_id); - node_inout_edges_[sink].insert(node_inout_edges_[sink].begin() + (size_t)node_num_in_edges_[sink], edge_id); - node_num_in_edges_[sink]++; + //We do not create the entry in node_edges_ here! + //For memory efficiency this is done when + //rebuild_node_edges() is called (i.e. after all + //edges have been created). VTR_ASSERT(validate_sizes()); @@ -976,15 +949,15 @@ void RRGraph::remove_edge(const RREdgeId& edge) { /* Invalidate node to edge references * TODO: consider making this optional (e.g. if called from remove_node) */ - for (size_t i = 0; i < node_inout_edges_[src_node].size(); ++i) { - if (node_inout_edges_[src_node][i] == edge) { - node_inout_edges_[src_node][i] = RREdgeId::INVALID(); + for (size_t i = 0; i < node_num_in_edges_[src_node]; ++i) { + if (node_edges_[src_node][i] == edge) { + node_edges_[src_node][i] = RREdgeId::INVALID(); break; } } - for (size_t i = 0; i < node_inout_edges_[sink_node].size(); ++i) { - if (node_inout_edges_[sink_node][i] == edge) { - node_inout_edges_[sink_node][i] = RREdgeId::INVALID(); + for (size_t i = node_num_in_edges_[sink_node]; i < node_num_in_edges_[sink_node] + node_num_out_edges_[sink_node]; ++i) { + if (node_edges_[sink_node][i] == edge) { + node_edges_[sink_node][i] = RREdgeId::INVALID(); break; } } @@ -1103,84 +1076,121 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_ node_segments_[node] = segment_id; } +void RRGraph::rebuild_node_edges() { + node_edges_.resize(nodes().size()); + node_num_in_edges_.resize(nodes().size(), 0); + node_num_out_edges_.resize(nodes().size(), 0); + node_num_non_configurable_in_edges_.resize(nodes().size(), 0); + node_num_non_configurable_out_edges_.resize(nodes().size(), 0); + + //Count the number of edges of each type + for (RREdgeId edge : edges()) { + if (!edge) continue; + + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); + bool config = edge_is_configurable(edge); + + ++node_num_out_edges_[src_node]; + ++node_num_in_edges_[sink_node]; + if (!config) { + ++node_num_non_configurable_out_edges_[src_node]; + ++node_num_non_configurable_in_edges_[sink_node]; + } + } -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_in_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_inout_edges_[node].begin(), node_inout_edges_[node].begin() + node_num_in_edges_[node], - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - - size_t num_conf_edges = std::distance(node_inout_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range - - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= (size_t)node_num_in_edges_[node], - "Exceeded RR node maximum number of non-configurable input edges"); - - node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing -} - -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_out_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_inout_edges_[node].begin() + node_num_in_edges_[node], node_inout_edges_[node].end(), - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - - size_t num_conf_edges = std::distance(node_inout_edges_[node].begin() + node_num_in_edges_[node], first_non_config_edge); - size_t num_non_conf_edges = node_inout_edges_[node].size() - node_num_in_edges_[node] - num_conf_edges; //Note we calculate using the size_t to get full range + //Allocate precisely the correct space for each nodes edge list + for (RRNodeId node : nodes()) { + if (!node) continue; - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_inout_edges_[node].size() - node_num_in_edges_[node], - "Exceeded RR node maximum number of non-configurable output edges"); + node_edges_[node] = std::make_unique(node_num_in_edges_[node] + node_num_out_edges_[node]); + } - node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing -} + //Insert the edges into the node lists + { + vtr::vector inserted_edge_cnt(nodes().size(), 0); + for (RREdgeId edge : edges()) { + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); -/* For all nodes in a rr_graph - * classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_in_edges() { - /* For each node */ - for (size_t id = 0; id < num_nodes_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_node_id(RRNodeId(id))) { - /* Skip this id */ - continue; + node_edges_[src_node][inserted_edge_cnt[src_node]++] = edge; + node_edges_[sink_node][inserted_edge_cnt[sink_node]++] = edge; } - this->partition_node_in_edges(RRNodeId(id)); } -} -/* For all nodes in a rr_graph - * classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_out_edges() { - /* For each node */ - for (size_t id = 0; id < num_nodes_; ++id) { - /* Try to find if this is an invalid id or not */ - if (!valid_node_id(RRNodeId(id))) { - /* Skip this id */ - continue; +#if 0 + //TODO: Sanity Check remove! + for (RRNodeId node : nodes()) { + for (size_t iedge = 0; iedge < node_num_in_edges_[node] + node_num_out_edges_[node]; ++iedge) { + RREdgeId edge = node_edges_[node][iedge]; + VTR_ASSERT(edge_src_node(edge) == node || edge_sink_node(edge) == node); } - this->partition_node_out_edges(RRNodeId(id)); } -} - -/* For all nodes in a rr_graph - * classify both input and output edges of each node - * to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_edges() { - /* Partition input edges */ - this->partition_in_edges(); - /* Partition output edges */ - this->partition_out_edges(); +#endif + + //Partition each node's edge lists according to their type to line up with the counts + + auto is_configurable_edge = [&](const RREdgeId edge) { + return edge_is_configurable(edge); + }; + + for (RRNodeId node : nodes()) { + if (!node) continue; + + //We partition the nodes first by incoming/outgoing: + // + // +---------------------------+-----------------------------+ + // | in | out | + // +---------------------------+-----------------------------+ + // + //and then the two subsets by configurability. So the final ordering is: + // + // +-----------+---------------+------------+----------------+ + // | in_config | in_non_config | out_config | out_non_config | + // +-----------+---------------+------------+----------------+ + // + + //Partition first into incoming/outgoing + auto is_incoming_edge = [&](const RREdgeId edge) { + return edge_sink_node(edge) == node; + }; + std::partition(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], + is_incoming_edge); + + //Partition incoming by configurable/non-configurable + std::partition(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node], + is_configurable_edge); + + //Partition outgoing by configurable/non-configurable + std::partition(node_edges_[node].get() + node_num_in_edges_[node], + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], + is_configurable_edge); + +#if 0 + //TODO: Sanity check remove! + size_t nedges = node_num_in_edges_[node] + node_num_out_edges_[node]; + for (size_t iedge = 0; iedge < nedges; ++iedge) { + RREdgeId edge = node_edges_[node][iedge]; + if (iedge < node_num_in_edges_[node]) { //Incoming + VTR_ASSERT(edge_sink_node(edge) == node); + if (iedge < node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]) { + VTR_ASSERT(edge_is_configurable(edge)); + } else { + VTR_ASSERT(!edge_is_configurable(edge)); + } + } else { //Outgoing + VTR_ASSERT(edge_src_node(edge) == node); + if (iedge < node_num_in_edges_[node] + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]) { + VTR_ASSERT(edge_is_configurable(edge)); + } else { + VTR_ASSERT(!edge_is_configurable(edge)); + } + } + } +#endif + } } void RRGraph::build_fast_node_lookup() const { @@ -1294,7 +1304,7 @@ bool RRGraph::validate_node_sizes() const { && node_segments_.size() == num_nodes_ && node_num_non_configurable_in_edges_.size() == num_nodes_ && node_num_non_configurable_out_edges_.size() == num_nodes_ - && node_inout_edges_.size() == num_nodes_; + && node_edges_.size() == num_nodes_; } bool RRGraph::validate_edge_sizes() const { @@ -1383,7 +1393,8 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map); node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map); node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map); - node_inout_edges_ = clean_and_reorder_values(node_inout_edges_, node_id_map); + node_num_out_edges_ = clean_and_reorder_values(node_num_out_edges_, node_id_map); + //node_edges_ = clean_and_reorder_values(node_edges_, node_id_map); VTR_ASSERT(validate_node_sizes()); } @@ -1406,9 +1417,12 @@ void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_m continue; } RRNodeId node = RRNodeId(id); - node_inout_edges_[node] = update_valid_refs(node_inout_edges_[node], edge_id_map); - VTR_ASSERT_MSG(all_valid(node_inout_edges_[node]), "All Ids should be valid"); + auto begin = node_edges_[node].get(); + auto end = begin + node_num_in_edges_[node] + node_num_out_edges_[node]; + update_valid_refs(begin, end, edge_id_map); + + VTR_ASSERT_MSG(all_valid(begin, end), "All Ids should be valid"); } } @@ -1427,11 +1441,12 @@ void RRGraph::clear_nodes() { node_Cs_.clear(); node_segments_.clear(); + node_num_in_edges_.clear(); + node_num_out_edges_.clear(); node_num_non_configurable_in_edges_.clear(); node_num_non_configurable_out_edges_.clear(); - node_num_in_edges_.clear(); - node_inout_edges_.clear(); + node_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index 7a0461a6728..d20203bf920 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -213,7 +213,6 @@ class RRGraph { public: /* Types */ - //Lazy iterator utility forward declaration template class lazy_id_iterator; @@ -228,7 +227,7 @@ class RRGraph { /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; - typedef vtr::Range edge_range; + typedef vtr::Range edge_range; typedef vtr::Range switch_range; typedef vtr::Range segment_range; typedef vtr::Range lazy_node_range; @@ -471,11 +470,9 @@ class RRGraph { /* Get the number of non-configurable output edges of a node */ short node_num_non_configurable_out_edges(const RRNodeId& node) const; - /* Get the range (list) of edges related to a given node */ - edge_range node_configurable_in_edges(const RRNodeId& node) const; - edge_range node_non_configurable_in_edges(const RRNodeId& node) const; - edge_range node_configurable_out_edges(const RRNodeId& node) const; - edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + //Returns an iterable range of all edges (incoming & outgoing) for + //the specified node + edge_range node_edges(const RRNodeId& node) const; /* Get a list of edge ids, which are incoming edges to a node */ edge_range node_in_edges(const RRNodeId& node) const; @@ -483,6 +480,12 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; + /* Get the range (list) of edges related to a given node */ + edge_range node_configurable_in_edges(const RRNodeId& node) const; + edge_range node_non_configurable_in_edges(const RRNodeId& node) const; + edge_range node_configurable_out_edges(const RRNodeId& node) const; + edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + /* Edge-related attributes * An example to explain the terminology used in RRGraph * edgeA @@ -602,21 +605,6 @@ class RRGraph { void reserve_switches(const size_t& num_switches); void reserve_segments(const size_t& num_segments); - /* Reserve the lists of input/output edges for a RR node to be memory efficient. - * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements - * - * For example: - * RRGraph rr_graph; - * // Add 1 source node to the RRGraph object - * RRNodeId src_node = rr_graph.create_node(SOURCE); - * // Reserve the input and output edges for the source node - * rr_graph.reserve_node_inout_edges(src_node, 5); - * // Add your edges - */ - void reserve_node_inout_edges(const RRNodeId& node, const size_t& num_inout_edges); - /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type * Detailed node-level information should be added using the set_node_* functions @@ -625,6 +613,7 @@ class RRGraph { * set_node_xlow(node, 0); */ RRNodeId create_node(const t_rr_type& type); + /* Add a edge to the RRGraph, by providing the source and sink node * This function will automatically create a node and * configure the nodes and edges in connection @@ -719,15 +708,14 @@ class RRGraph { /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in one vector, - * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) + /* + * Build the node to edge references to allow iteration through + * a node's in/out edges. + * + * Must be called before any node_*_in_edges() or node_*_out_edges() member + * functions can be called. */ - void partition_edges(); + void rebuild_node_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set @@ -738,7 +726,6 @@ class RRGraph { void clear(); public: /* Type implementations */ - /* * This class (forward delcared above) is a template used to represent a lazily calculated * iterator of the specified ID type. The key assumption made is that the ID space is @@ -785,19 +772,6 @@ class RRGraph { const std::unordered_set& invalid_ids_; }; - private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_in_edges(const RRNodeId& node); - - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_out_edges(const RRNodeId& node); - - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_in_edges(); - - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_out_edges(); - private: /* Internal free functions */ void clear_nodes(); void clear_edges(); @@ -864,7 +838,7 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - size_t num_nodes_; /* Range of node ids */ + size_t num_nodes_; /* Range of node ids */ std::unordered_set invalid_node_ids_; /* Invalid edge ids */ vtr::vector node_types_; @@ -879,27 +853,43 @@ class RRGraph { vtr::vector node_Rs_; vtr::vector node_Cs_; vtr::vector node_segments_; /* Segment ids for each node */ - /* Record the dividing point between configurable and non-configurable edges for each node */ - vtr::vector node_num_non_configurable_in_edges_; - vtr::vector node_num_non_configurable_out_edges_; - - /* Record the dividing point between input and output edges for each node - * Both input and output edges are stored in a list for memory efficiency - * We use a dividing point to identify the groups - * The edges are arranged in as the following format: - * Index in list: - * 0--------------------------------------------------------------------------------------------------->N - * - * |<----------------------->|^ |<------------------------->| - * node_num_non_cinfigurable_in_edges | node_num_non_configurable_out_edges - * | - * node_num_in_edges - */ - vtr::vector node_num_in_edges_; - vtr::vector> node_inout_edges_; + + /* + * We store the edges assoicated with each node in a single array per node (for memory efficiency). + * + * The array of edges is sorted into sub-ranges to allow for easy iteration (with node_in_edges(), + * node_non_configurable_out_edges() etc.). + * + * For a particular 'node' we store the sizes of the various sub-ranges in the node_num_* members, + * from which the delimiters for each sub-range can be calculated. + * + * + * node_edges_[node]: + * + * + * node_num_non_configurable_in_edges_[node] node_num_non_configurable_out_edges_[node] + * <-------------------> <--------------------> + * + * +------------------+---------------------+------------------+----------------------+ + * | in_edges_config | in_edges_non_config | out_edges_config | out_edges_non_config | + * +------------------+---------------------+------------------+----------------------+ + * + * <--------------------------------------> <---------------------------------------> + * node_num_in_edges_[node] node_num_out_edges_[node] + * + * All elements of node_edges_ should be initialized after all edges have been created (with create_edge()), + * by calling rebuild_node_edges(), which will allocate node_edges_, add the relevant edges and partition + * each node's arrays into the appropriate. rebuild_node_edges() also initializes all the node_num_* members + * based on the edges (created with create_edge()) in the edge_* members. + */ + vtr::vector node_num_in_edges_; + vtr::vector node_num_out_edges_; + vtr::vector node_num_non_configurable_in_edges_; + vtr::vector node_num_non_configurable_out_edges_; + vtr::vector> node_edges_; /* Edge related data */ - size_t num_edges_; /* Range of edge ids */ + size_t num_edges_; /* Range of edge ids */ std::unordered_set invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; diff --git a/vpr/src/device/rr_graph_obj_utils.h b/vpr/src/device/rr_graph_obj_utils.h index 910b0ce3acd..5c3a8f6d6a6 100644 --- a/vpr/src/device/rr_graph_obj_utils.h +++ b/vpr/src/device/rr_graph_obj_utils.h @@ -38,6 +38,16 @@ bool all_valid(const Container& values) { return true; } +template +bool all_valid(Iterator begin, Iterator end) { + for (auto itr = begin; itr != end; ++itr) { + if (!*itr) { + return false; + } + } + return true; +} + //Builds a mapping from old to new ids by skipping values marked invalid template Container compress_ids(const Container& ids) { @@ -162,4 +172,20 @@ ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer return updated; } +template +void update_valid_refs(Iterator begin, Iterator end, const IdContainer& id_map) { + for (auto itr = begin; itr != end; ++itr) { + auto orig_val = *itr; + if (orig_val) { + //Original item valid + + auto new_val = id_map[orig_val]; + if (new_val) { + //The original item exists in the new mapping + *itr = new_val; + } + } + } +} + #endif From 763b22de730fa83d839758831811b39e5e2e28a5 Mon Sep 17 00:00:00 2001 From: kmurray Date: Fri, 22 Nov 2019 13:37:49 -0500 Subject: [PATCH 55/58] vpr: Remove RRGraph::node_num_*edge() data members. Instead clients should use the .size() member of the relevant range. --- vpr/src/device/rr_graph_obj.cpp | 34 --------------------------------- vpr/src/device/rr_graph_obj.h | 12 ------------ 2 files changed, 46 deletions(-) diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 59907c4cdec..2df4a77bfa5 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -203,40 +203,6 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { return node_segments_[node]; } -/* - * Get the number of configurable input edges of a node - */ -short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { - return node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]; -} - -/* - * Get the number of configurable output edges of a node - */ -short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_num_out_edges_[node] - node_num_non_configurable_in_edges_[node]; -} - -/* - * Get the number of non-configurable input edges of a node - * Use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const { - return node_num_non_configurable_in_edges_[node]; -} - -/* - * Get the number of non-configurable output edges of a node - * Use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { - return node_num_non_configurable_out_edges_[node]; -} - RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index d20203bf920..4ffbe3daf2d 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -458,18 +458,6 @@ class RRGraph { */ RRSegmentId node_segment(const RRNodeId& node) const; - /* Get the number of non-configurable incoming edges to a node */ - short node_num_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable outgoing edges from a node */ - short node_num_non_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of configurable output edges of a node */ - short node_num_configurable_out_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable output edges of a node */ - short node_num_non_configurable_out_edges(const RRNodeId& node) const; - //Returns an iterable range of all edges (incoming & outgoing) for //the specified node edge_range node_edges(const RRNodeId& node) const; From 0e8163245caf658067db6af2fefdcb6cc2e2811a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 25 Nov 2019 21:20:12 -0700 Subject: [PATCH 56/58] add malloc_trim to have clean memory stats when building rr_graph --- vpr/src/device/create_rr_graph.cpp | 4 ++++ vpr/src/route/rr_graph.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index 6faced34b31..ecd9501a6c1 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -4,6 +4,7 @@ /* EXTERNAL library header files go second*/ #include "vtr_assert.h" #include "vtr_time.h" +#include "vtr_memory.h" /* VPR header files go then */ #include "vpr_types.h" @@ -25,6 +26,9 @@ void convert_rr_graph(std::vector& vpr_segments) { vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); + /* Release freed memory before start building rr_graph */ + vtr::malloc_trim(0); + /* IMPORTANT: to build clock tree, * vpr added segments to the original arch segments * This is why to use vpr_segments as an inputs!!! diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 12b3a101401..a50c7da7fe4 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -437,6 +437,9 @@ static void build_rr_graph(const t_graph_type graph_type, int* Warnings) { vtr::ScopedStartFinishTimer timer("Build routing resource graph"); + /* Release freed memory before start building rr_graph */ + vtr::malloc_trim(0); + /* Reset warning flag */ *Warnings = RR_GRAPH_NO_WARN; From 88473d93aea12e54db0fdfae4bf67a0bc175858b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 26 Nov 2019 13:39:10 -0700 Subject: [PATCH 57/58] move malloc_trim ahead of timer to gain more accurate memory stats --- vpr/src/device/create_rr_graph.cpp | 4 ++-- vpr/src/route/rr_graph.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp index ecd9501a6c1..4ec054a52ed 100644 --- a/vpr/src/device/create_rr_graph.cpp +++ b/vpr/src/device/create_rr_graph.cpp @@ -24,11 +24,11 @@ *routers ********************************************************************/ void convert_rr_graph(std::vector& vpr_segments) { - vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); - /* Release freed memory before start building rr_graph */ vtr::malloc_trim(0); + vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); + /* IMPORTANT: to build clock tree, * vpr added segments to the original arch segments * This is why to use vpr_segments as an inputs!!! diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index a50c7da7fe4..799d46550f2 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -435,11 +435,11 @@ static void build_rr_graph(const t_graph_type graph_type, const int num_directs, int* wire_to_rr_ipin_switch, int* Warnings) { - vtr::ScopedStartFinishTimer timer("Build routing resource graph"); - /* Release freed memory before start building rr_graph */ vtr::malloc_trim(0); + vtr::ScopedStartFinishTimer timer("Build routing resource graph"); + /* Reset warning flag */ *Warnings = RR_GRAPH_NO_WARN; From 441f55a358cb02dda4f8c0639f25b3c30e605139 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 26 Nov 2019 14:54:42 -0700 Subject: [PATCH 58/58] comment out the create_device memory stats to have clean memory stats on rr_graph --- vpr/src/base/vpr_api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 348545f58ea..90c70d7657c 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -374,7 +374,7 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) { } void vpr_create_device(t_vpr_setup& vpr_setup, const t_arch& arch) { - vtr::ScopedStartFinishTimer timer("Create Device"); + //vtr::ScopedStartFinishTimer timer("Create Device"); vpr_create_device_grid(vpr_setup, arch); vpr_setup_clock_networks(vpr_setup, arch);