From f49cabeeda673bb31cee9bba61d4412ab5510e6a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 30 Jun 2020 11:33:06 -0600 Subject: [PATCH] optimize memory efficiency for module net id storage --- openfpga/src/fabric/module_manager.cpp | 16 +++---- openfpga/src/fabric/module_manager.h | 59 +++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/openfpga/src/fabric/module_manager.cpp b/openfpga/src/fabric/module_manager.cpp index afb9c3425..b1d503211 100644 --- a/openfpga/src/fabric/module_manager.cpp +++ b/openfpga/src/fabric/module_manager.cpp @@ -35,7 +35,8 @@ ModuleManager::module_port_range ModuleManager::module_ports(const ModuleId& mod ModuleManager::module_net_range ModuleManager::module_nets(const ModuleId& module) const { /* Validate the module_id */ VTR_ASSERT(valid_module_id(module)); - return vtr::make_range(net_ids_[module].begin(), net_ids_[module].end()); + return vtr::make_range(module_net_iterator(ModuleNetId(0), invalid_net_ids_[module]), + module_net_iterator(ModuleNetId(num_nets_[module]), invalid_net_ids_[module])); } /* Find all the child modules under a parent module */ @@ -108,7 +109,7 @@ size_t ModuleManager::num_modules() const { size_t ModuleManager::num_nets(const ModuleId& module) const { /* Validate the module_id */ VTR_ASSERT(valid_module_id(module)); - return net_ids_[module].size(); + return num_nets_[module]; } /* Find the name of a module */ @@ -458,7 +459,8 @@ ModuleId ModuleManager::add_module(const std::string& name) { port_is_register_.emplace_back(); port_preproc_flags_.emplace_back(); - net_ids_.emplace_back(); + num_nets_.emplace_back(0); + invalid_net_ids_.emplace_back(); net_names_.emplace_back(); net_src_ids_.emplace_back(); net_src_module_ids_.emplace_back(); @@ -643,8 +645,6 @@ void ModuleManager::reserve_module_nets(const ModuleId& module, /* Validate the module id */ VTR_ASSERT ( valid_module_id(module) ); - net_ids_[module].reserve(num_nets); - net_names_[module].reserve(num_nets); net_src_ids_[module].reserve(num_nets); net_src_module_ids_[module].reserve(num_nets); @@ -665,8 +665,8 @@ ModuleNetId ModuleManager::create_module_net(const ModuleId& module) { VTR_ASSERT ( valid_module_id(module) ); /* Create an new id */ - ModuleNetId net = ModuleNetId(net_ids_[module].size()); - net_ids_[module].push_back(net); + ModuleNetId net = ModuleNetId(num_nets_[module]); + num_nets_[module]++; /* Allocate net-related data structures */ net_names_[module].emplace_back(); @@ -832,7 +832,7 @@ bool ModuleManager::valid_module_net_id(const ModuleId& module, const ModuleNetI if (false == valid_module_id(module)) { return false; } - return ( size_t(net) < net_ids_[module].size() ) && ( net == net_ids_[module][net] ); + return ( size_t(net) < num_nets_[module] ); } void ModuleManager::invalidate_name2id_map() { diff --git a/openfpga/src/fabric/module_manager.h b/openfpga/src/fabric/module_manager.h index 4736d2783..792c790d9 100644 --- a/openfpga/src/fabric/module_manager.h +++ b/openfpga/src/fabric/module_manager.h @@ -3,6 +3,9 @@ #include #include +#include +#include + #include "vtr_vector.h" #include "module_manager_fwd.h" #include "openfpga_port.h" @@ -40,10 +43,61 @@ class ModuleManager { public: /* Public Constructors */ + 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_; + }; + public: /* Types and ranges */ + //Lazy iterator utility forward declaration + template + class lazy_id_iterator; + typedef vtr::vector::const_iterator module_iterator; typedef vtr::vector::const_iterator module_port_iterator; - typedef vtr::vector::const_iterator module_net_iterator; + typedef lazy_id_iterator module_net_iterator; typedef vtr::vector::const_iterator module_net_src_iterator; typedef vtr::vector::const_iterator module_net_sink_iterator; @@ -239,7 +293,8 @@ class ModuleManager { * To avoid large memory footprint, we do NOT create pins, * To enable fast look-up on pins, we create a fast look-up */ - vtr::vector> net_ids_; /* List of nets for each Module */ + vtr::vector num_nets_; /* List of nets for each Module */ + vtr::vector> invalid_net_ids_; /* Invalid net ids */ vtr::vector> net_names_; /* Name of net */ vtr::vector>> net_src_ids_; /* Unique id of the source that drive the net */