From 6e52e6f0c6d219da33fcf64b81b6666a39a99b60 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 26 Apr 2021 22:26:31 +0200 Subject: [PATCH 1/5] WIP: introducing memory metrics for netlist/l2n --- src/db/db/dbCell.cc | 10 +-- src/db/db/dbCircuit.h | 35 +++++++++ src/db/db/dbDevice.h | 26 +++++++ src/db/db/dbDeviceAbstract.h | 22 ++++++ src/db/db/dbDeviceClass.h | 66 +++++++++++++++++ src/db/db/dbHierNetworkProcessor.cc | 83 ++++++++++++++++++--- src/db/db/dbHierNetworkProcessor.h | 107 +++++++++++++++++++++++++++- src/db/db/dbLayoutToNetlist.cc | 34 +++++++++ src/db/db/dbLayoutToNetlist.h | 13 ++++ src/db/db/dbMemStatistics.cc | 18 ++--- src/db/db/dbMemStatistics.h | 83 +++++++++++++++++---- src/db/db/dbNet.h | 24 +++++++ src/db/db/dbNetlist.cc | 18 +++++ src/db/db/dbNetlist.h | 13 ++++ src/db/db/dbNetlistUtils.h | 31 ++++++++ src/db/db/dbPin.h | 21 ++++++ src/db/db/dbSubCircuit.h | 23 ++++++ 17 files changed, 583 insertions(+), 44 deletions(-) diff --git a/src/db/db/dbCell.cc b/src/db/db/dbCell.cc index c2e362906..c4a81f4f5 100644 --- a/src/db/db/dbCell.cc +++ b/src/db/db/dbCell.cc @@ -598,15 +598,7 @@ Cell::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, } db::mem_stat (stat, purpose, cat, m_bboxes, true, (void *) this); db::mem_stat (stat, MemStatistics::Instances, cat, m_instances, true, (void *) this); - - // iterate the shapes separately so we can use the layer for the category - for (shapes_map::const_iterator i = m_shapes_map.begin (); i != m_shapes_map.end (); ++i) { - db::mem_stat (stat, MemStatistics::ShapesInfo, (int) i->first, i->first, false, (void *) this); - db::mem_stat (stat, MemStatistics::ShapesInfo, (int) i->first, i->second, false, (void *) this); -#ifdef __GNUCC__ - stat->add (std::_Rb_tree_node_base, (void *) &i->first, sizeof (std::_Rb_tree_node_base), sizeof (std::_Rb_tree_node_base), (void *) &v, purpose, cat); -#endif - } + db::mem_stat (stat, MemStatistics::ShapesInfo, cat, m_shapes_map, true, (void *) this); } void diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index a33be121f..b1124a6cf 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -31,6 +31,7 @@ #include "dbSubCircuit.h" #include "dbNetlistUtils.h" #include "dbPolygon.h" +#include "dbMemStatistics.h" #include "tlObject.h" #include "tlObjectCollection.h" @@ -749,6 +750,32 @@ public: */ void blank (); + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_boundary, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_nets, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_pins, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_pin_by_id, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_devices, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_subcircuits, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_pin_refs, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_device_by_id, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_subcircuit_by_id, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_net_by_cluster_id, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_device_by_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_subcircuit_by_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_net_by_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_refs, true, (void *) this); + } + private: friend class Netlist; friend class Net; @@ -798,6 +825,14 @@ private: void nets_changed (); }; +/** + * @brief Memory statistics for Circuit + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Circuit &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h index 8746fbe8e..336411b1b 100644 --- a/src/db/db/dbDevice.h +++ b/src/db/db/dbDevice.h @@ -28,6 +28,7 @@ #include "dbPoint.h" #include "dbVector.h" #include "dbTrans.h" +#include "dbMemStatistics.h" #include "tlObject.h" @@ -349,6 +350,23 @@ public: return m_other_abstracts; } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_trans, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_terminal_refs, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_parameters, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_other_abstracts, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_reconnected_terminals, true, (void *) this); + } + private: friend class Circuit; friend class Net; @@ -396,6 +414,14 @@ private: void init_terminal_routes (); }; +/** + * @brief Memory statistics for Device + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Device &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif diff --git a/src/db/db/dbDeviceAbstract.h b/src/db/db/dbDeviceAbstract.h index 00cbc45cc..d6ba95713 100644 --- a/src/db/db/dbDeviceAbstract.h +++ b/src/db/db/dbDeviceAbstract.h @@ -26,6 +26,7 @@ #include "dbCommon.h" #include "dbNet.h" #include "dbPoint.h" +#include "dbMemStatistics.h" #include "tlObject.h" @@ -144,6 +145,19 @@ public: */ void set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id); + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_terminal_cluster_ids, true, (void *) this); + } + private: friend class Netlist; @@ -159,6 +173,14 @@ private: void set_netlist (Netlist *netlist); }; +/** + * @brief Memory statistics for LayoutToNetlist + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const DeviceAbstract &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index d77048e2b..66ba8d5f6 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -24,6 +24,7 @@ #define _HDR_dbDeviceClass #include "dbCommon.h" +#include "dbMemStatistics.h" #include "gsiObject.h" #include "tlObject.h" @@ -102,6 +103,19 @@ public: return m_id; } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_description, true, (void *) this); + } + private: friend class DeviceClass; @@ -114,6 +128,14 @@ private: } }; +/** + * @brief Memory statistics for DeviceTerminalDefinition + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const DeviceTerminalDefinition &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + /** * @brief A device parameter definition */ @@ -224,6 +246,19 @@ public: return m_id; } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_description, true, (void *) this); + } + private: friend class DeviceClass; @@ -239,6 +274,14 @@ private: } }; +/** + * @brief Memory statistics for DeviceParameterDefinition + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const DeviceParameterDefinition &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + /** * @brief A device parameter compare delegate * @@ -598,6 +641,21 @@ public: return mp_pc_delegate.get (); } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_description, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_terminal_definitions, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_parameter_definitions, true, (void *) this); + } + private: friend class Netlist; @@ -614,6 +672,14 @@ private: } }; +/** + * @brief Memory statistics for DeviceClass + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const DeviceClass &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + /** * @brief A device class template * diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 07b88bf11..9f05c3746 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -414,6 +414,19 @@ local_cluster::ensure_sorted () m_needs_update = false; } +template +void +local_cluster::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_shapes, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_attrs, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_global_nets, true, (void *) this); +} + template class DB_PUBLIC hnp_interaction_receiver : public box_scanner_receiver2 @@ -786,6 +799,20 @@ local_clusters::ensure_sorted () m_needs_update = false; } +template +void +local_clusters::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_needs_update, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_bbox, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_clusters, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_next_dummy_id, true, (void *) this); +} + namespace { @@ -1210,6 +1237,21 @@ connected_clusters::find_cluster_with_connection (const ClusterInstance &inst } } +template +void +connected_clusters::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + local_clusters::mem_stat (stat, purpose, cat, true, parent); + + db::mem_stat (stat, purpose, cat, m_connections, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_rev_connections, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_connected_clusters, true, (void *) this); +} + // explicit instantiations template class DB_PUBLIC connected_clusters; template class DB_PUBLIC connected_clusters; @@ -1290,6 +1332,17 @@ void hier_clusters::clear () m_per_cell_clusters.clear (); } +template +void +hier_clusters::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_per_cell_clusters, true, (void *) this); +} + template void hier_clusters::build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells) @@ -1467,7 +1520,7 @@ private: join_set_list m_cm2join_sets; std::list m_ci_interactions; std::map > > m_interaction_cache_for_clusters; - instance_interaction_cache_type *mp_instance_interaction_cache; + typename hier_clusters::instance_interaction_cache_type *mp_instance_interaction_cache; /** * @brief Investigate a pair of instances @@ -1488,7 +1541,7 @@ private: void consider_instance_pair (const box_type &common, const db::Instance &i1, const db::ICplxTrans &t1, const db::CellInstArray::iterator &i1element, const db::Instance &i2, const db::ICplxTrans &t2, const db::CellInstArray::iterator &i2element, - std::list > &interacting_clusters) + cluster_instance_pair_list_type &interacting_clusters) { if (is_breakout_cell (mp_breakout_cells, i1.cell_index ()) || is_breakout_cell (mp_breakout_cells, i2.cell_index ())) { return; @@ -1510,9 +1563,13 @@ private: db::ICplxTrans i1t, i2t; bool fill_cache = false; - // Cache is only used for single instances, non-iterated, simple or regular arrays. - if ((! i1element.at_end () || i1.size () == 1 || ! i1.is_iterated_array ()) && - (! i2element.at_end () || i2.size () == 1 || ! i2.is_iterated_array ())) { + // Cache is only used for single instances or simple arrays. + // Other schemes make the cache taking a lot of memory - because array vs. array testing may result in + // N x N cache entries when the arrayed cells contain child cells. + // We still allow the case of array vs. array when i1.size == i2.size as this efficiently caches + // array/array interactions. + if ((! i1element.at_end () || i1.size () == 1 || i1.size () == i2.size ()) && + (! i2element.at_end () || i2.size () == 1 || i1.size () == i2.size ())) { i1t = i1element.at_end () ? i1.complex_trans () : i1.complex_trans (*i1element); db::ICplxTrans tt1 = t1 * i1t; @@ -1525,12 +1582,12 @@ private: i2.cell_index (), (! i2element.at_end () || i2.size () == 1) ? 0 : i2.cell_inst ().delegate (), cache_norm, cache_norm * tt2); - instance_interaction_cache_type::iterator ii = mp_instance_interaction_cache->find (ii_key); - if (ii != mp_instance_interaction_cache->end ()) { + const cluster_instance_pair_list_type *cached = mp_instance_interaction_cache->find (ii_key); + if (cached) { // use cached interactions - interacting_clusters = ii->second; - for (std::list >::iterator i = interacting_clusters.begin (); i != interacting_clusters.end (); ++i) { + interacting_clusters = *cached; + for (cluster_instance_pair_list_type::iterator i = interacting_clusters.begin (); i != interacting_clusters.end (); ++i) { // translate the property IDs i->first.set_inst_prop_id (i1.prop_id ()); i->first.transform (i1t); @@ -1653,7 +1710,7 @@ private: i->second.transform (i2ti); } - cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key]; + cluster_instance_pair_list_type &cached = mp_instance_interaction_cache->insert (ii_key); cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ()); } @@ -2187,6 +2244,12 @@ hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layou build_hier_connections_for_cells (cbc, layout, todo, conn, breakout_cells, progress, instance_interaction_cache); } + + // @@@ + if (tl::verbosity () >= 0) { + tl::info << "Cluster build cache statistics: size=" << instance_interaction_cache.size () << ", hits=" << instance_interaction_cache.hits () << ", misses=" << instance_interaction_cache.misses (); + } + // @@@ } template diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 75455440b..aeb41b006 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -365,6 +365,11 @@ public: */ void set_global_nets (const global_nets &gn); + /** + * @brief Collect memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const; + private: template friend class local_clusters; template friend class hnp_interaction_receiver; @@ -392,6 +397,15 @@ private: size_t m_size; }; +/** + * @brief Memory statistics for local_cluster + */ +template +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const local_cluster &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + /** * @brief A box converter for the local_cluster class */ @@ -533,6 +547,19 @@ public: return id > m_clusters.size (); } + /** + * @brief Gets the number of clusters + */ + size_t size () const + { + return m_clusters.size (); + } + + /** + * @brief Collect memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const; + private: void ensure_sorted (); @@ -544,6 +571,15 @@ private: void apply_attr_equivalences (const tl::equivalence_clusters &attr_equivalence); }; +/** + * @brief Memory statistics for local_clusters + */ +template +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const local_clusters &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + /** * @brief The instance information for a cluster */ @@ -859,8 +895,6 @@ struct InstanceToInstanceInteraction db::ICplxTrans t21; }; -typedef std::map instance_interaction_cache_type; - template class hier_clusters; template class connected_clusters; @@ -1013,6 +1047,11 @@ public: m_connected_clusters.insert (id); } + /** + * @brief Collect memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const; + private: template friend class connected_clusters_iterator; @@ -1021,6 +1060,15 @@ private: std::set m_connected_clusters; }; +/** + * @brief Memory statistics for connected_clusters + */ +template +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const connected_clusters &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + template class cell_clusters_box_converter; /** @@ -1034,7 +1082,55 @@ class DB_PUBLIC_TEMPLATE hier_clusters { public: typedef typename local_cluster::box_type box_type; - typedef std::map instance_interaction_cache_type; + + /** + * @brief An object representing the instance interaction cache + */ + class instance_interaction_cache + { + public: + instance_interaction_cache () + : m_hits (0), m_misses (0) + { } + + size_t size () const + { + return m_map.size (); + } + + size_t hits () const + { + return m_hits; + } + + size_t misses () const + { + return m_misses; + } + + const cluster_instance_pair_list_type *find (const InstanceToInstanceInteraction &key) const + { + std::map::const_iterator i = m_map.find (key); + if (i == m_map.end ()) { + ++m_misses; + return 0; + } else { + ++m_hits; + return &i->second; + } + } + + cluster_instance_pair_list_type &insert (const InstanceToInstanceInteraction &key) + { + return m_map [key]; + } + + private: + mutable size_t m_hits, m_misses; + std::map m_map; + }; + + typedef instance_interaction_cache instance_interaction_cache_type; /** * @brief Creates an empty set of clusters @@ -1094,6 +1190,11 @@ public: */ size_t propagate_cluster_inst (const db::Layout &layout, const Cell &cell, const ClusterInstance &ci, db::cell_index_type parent_ci, bool with_self); + /** + * @brief Collect memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const; + private: void build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence); void build_hier_connections (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::set *breakout_cells, instance_interaction_cache_type &instance_interaction_cache); diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 4f3331992..0dbeac6cc 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -397,9 +397,43 @@ void LayoutToNetlist::extract_netlist () netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); + // @@@ + if (tl::verbosity () >= 0) { + MemStatisticsCollector m (false); + mem_stat (&m, db::MemStatistics::None, 0); + m.print (); + } + // @@@ + m_netlist_extracted = true; } +void LayoutToNetlist::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_description, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_original_file, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_filename, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_net_clusters, true, (void *) this); + db::mem_stat (stat, purpose, cat, mp_netlist, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_dlrefs, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_named_regions, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_name_of_layer, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_joined_net_names, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_joined_net_names_per_cell, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_joined_nets, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_joined_nets_per_cell, true, (void *) this); + + m_net_clusters.mem_stat (stat, MemStatistics::LayoutToNetlist, cat, true, (void *) this); + if (mp_netlist.get ()) { + db::mem_stat (stat, MemStatistics::Netlist, cat, *mp_netlist, false, (void *) this); + } +} + void LayoutToNetlist::set_netlist_extracted () { m_netlist_extracted = true; diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index a1bf8716f..08cb3eb46 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -893,6 +893,11 @@ public: */ static db::LayoutToNetlist *create_from_file (const std::string &path); + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const; + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); @@ -971,6 +976,14 @@ private: virtual void link_nets (const db::Net *net, const db::Net *with); }; +/** + * @brief Memory statistics for LayoutToNetlist + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const LayoutToNetlist &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } namespace tl diff --git a/src/db/db/dbMemStatistics.cc b/src/db/db/dbMemStatistics.cc index 1160f0b10..0995c01b8 100644 --- a/src/db/db/dbMemStatistics.cc +++ b/src/db/db/dbMemStatistics.cc @@ -100,14 +100,16 @@ void MemStatisticsCollector::print () { std::map p2s; - p2s[None] = "(none) "; - p2s[LayoutInfo] = "Layout info "; - p2s[CellInfo] = "Cell info "; - p2s[Instances] = "Instances "; - p2s[InstTrees] = "Instance trees "; - p2s[ShapesInfo] = "Shapes info "; - p2s[ShapesCache] = "Shapes cache "; - p2s[ShapeTrees] = "Shape trees "; + p2s[None] = "(none) "; + p2s[LayoutInfo] = "Layout info "; + p2s[CellInfo] = "Cell info "; + p2s[Instances] = "Instances "; + p2s[InstTrees] = "Instance trees "; + p2s[ShapesInfo] = "Shapes info "; + p2s[ShapesCache] = "Shapes cache "; + p2s[ShapeTrees] = "Shape trees "; + p2s[Netlist] = "Netlist "; + p2s[LayoutToNetlist] = "Netlist layout "; if (m_detailed) { diff --git a/src/db/db/dbMemStatistics.h b/src/db/db/dbMemStatistics.h index 72dfc85f8..8293c85bf 100644 --- a/src/db/db/dbMemStatistics.h +++ b/src/db/db/dbMemStatistics.h @@ -26,6 +26,7 @@ #define HDR_dbMemStatistics #include "dbCommon.h" +#include "tlObjectCollection.h" #include #include @@ -33,6 +34,8 @@ #include #include #include +#include +#include #include #include "tlReuseVector.h" @@ -64,7 +67,9 @@ public: InstTrees, ShapesInfo, ShapesCache, - ShapeTrees + ShapeTrees, + Netlist, + LayoutToNetlist }; /** @@ -120,7 +125,7 @@ template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const tl::reuse_vector &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (tl::reuse_vector), (void *) &v, sizeof (tl::reuse_vector), sizeof (tl::reuse_vector), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } if (! v.empty ()) { stat->add (typeid (X[]), (void *) v.begin ().operator-> (), sizeof (X) * v.capacity (), sizeof (X) * v.size (), (void *) &v, purpose, cat); @@ -137,7 +142,7 @@ template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const tl::vector &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (tl::vector), (void *) &v, sizeof (tl::vector), sizeof (tl::vector), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } if (! v.empty ()) { stat->add (typeid (X[]), (void *) &v.front (), sizeof (X) * v.capacity (), sizeof (X) * v.size (), (void *) &v, purpose, cat); @@ -151,7 +156,7 @@ template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::vector &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (std::vector), (void *) &v, sizeof (std::vector), sizeof (std::vector), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } if (! v.empty ()) { stat->add (typeid (X[]), (void *) &v.front (), sizeof (X) * v.capacity (), sizeof (X) * v.size (), (void *) &v, purpose, cat); @@ -167,41 +172,68 @@ template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::map &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (std::map), (void *) &v, sizeof (std::map), sizeof (std::map), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } for (typename std::map::const_iterator i = v.begin (); i != v.end (); ++i) { mem_stat (stat, purpose, cat, i->first, false, (void *) &v); mem_stat (stat, purpose, cat, i->second, false, (void *) &v); -#ifdef __GNUCC__ - stat->add (std::_Rb_tree_node_base, (void *) &i->first, sizeof (std::_Rb_tree_node_base), sizeof (std::_Rb_tree_node_base), (void *) &v, purpose, cat); +#ifdef __GLIBCXX__ + stat->add (typeid (std::_Rb_tree_node_base), (void *) &i->first, sizeof (std::_Rb_tree_node_base), sizeof (std::_Rb_tree_node_base), (void *) &v, purpose, cat); #endif } } +template +void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::unordered_map &v, bool no_self = false, void *parent = 0) +{ + if (! no_self) { + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); + } + for (typename std::unordered_map::const_iterator i = v.begin (); i != v.end (); ++i) { + mem_stat (stat, purpose, cat, i->first, false, (void *) &v); + mem_stat (stat, purpose, cat, i->second, false, (void *) &v); + // TODO: add intrinsic overhead + } +} + template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::set &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (std::set), (void *) &v, sizeof (std::set), sizeof (std::set), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } for (typename std::set::const_iterator i = v.begin (); i != v.end (); ++i) { mem_stat (stat, purpose, cat, *i, false, (void *) &v); -#ifdef __GNUCC__ - stat->add (std::_Rb_tree_node_base, (void *) &i.operator-> (), sizeof (std::_Rb_tree_node_base), sizeof (std::_Rb_tree_node_base), (void *) &v, purpose, cat); +#ifdef __GLIBCXX__ + // NOTE: the pointer is only an approximation + stat->add (typeid (std::_Rb_tree_node_base), (void *) i.operator-> (), sizeof (std::_Rb_tree_node_base), sizeof (std::_Rb_tree_node_base), (void *) &v, purpose, cat); #endif } } +template +void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::unordered_set &v, bool no_self = false, void *parent = 0) +{ + if (! no_self) { + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); + } + for (typename std::unordered_set::const_iterator i = v.begin (); i != v.end (); ++i) { + mem_stat (stat, purpose, cat, *i, false, (void *) &v); + // TODO: add intrinsic overhead + } +} + template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::list &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (std::list), (void *) &v, sizeof (std::list), sizeof (std::list), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } for (typename std::list::const_iterator i = v.begin (); i != v.end (); ++i) { mem_stat (stat, purpose, cat, *i, false, (void *) &v); -#ifdef __GNUCC__ - stat->add (std::_List_node_base, (void *) &i.operator-> (), sizeof (std::_List_node_base), sizeof (std::_List_node_base), (void *) &v, purpose, cat); +#ifdef __GLIBCXX__ + // NOTE: the pointer is only an approximation + stat->add (typeid (std::__detail::_List_node_base), (void *) i.operator-> (), sizeof (std::__detail::_List_node_base), sizeof (std::__detail::_List_node_base), (void *) &v, purpose, cat); #endif } } @@ -210,12 +242,35 @@ template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const std::pair &v, bool no_self = false, void *parent = 0) { if (! no_self) { - stat->add (typeid (std::pair), (void *) &v, sizeof (std::pair), sizeof (std::pair), parent, purpose, cat); + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); } mem_stat (stat, purpose, cat, v.first, true, (void *) &v); mem_stat (stat, purpose, cat, v.second, true, (void *) &v); } +template +void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const tl::shared_collection &v, bool no_self = false, void *parent = 0) +{ + if (! no_self) { + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); + } + size_t intrinsic = sizeof (typename tl::shared_collection::holder_type) * v.size (); + stat->add (typeid (typename tl::shared_collection::holder_type), (void *) &v, intrinsic, intrinsic, (void *) &v, purpose, cat); + for (typename tl::shared_collection::const_iterator i = v.begin (); i != v.end (); ++i) { + mem_stat (stat, purpose, cat, *i, false, (void *) &v); + } +} + +template +void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const tl::weak_collection &v, bool no_self = false, void *parent = 0) +{ + if (! no_self) { + stat->add (typeid (v), (void *) &v, sizeof (v), sizeof (v), parent, purpose, cat); + } + size_t intrinsic = sizeof (typename tl::weak_collection::holder_type) * v.size (); + stat->add (typeid (typename tl::weak_collection::holder_type), (void *) &v, intrinsic, intrinsic, (void *) &v, purpose, cat); +} + } #endif diff --git a/src/db/db/dbNet.h b/src/db/db/dbNet.h index 66cf97d36..f2e97c373 100644 --- a/src/db/db/dbNet.h +++ b/src/db/db/dbNet.h @@ -25,6 +25,7 @@ #include "dbCommon.h" #include "dbNetlistObject.h" +#include "dbMemStatistics.h" #include "tlObject.h" @@ -664,6 +665,21 @@ public: return m_terminals.size (); } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_terminals, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_pins, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_subcircuit_pins, true, (void *) this); + } + private: friend class Circuit; @@ -677,6 +693,14 @@ private: void set_circuit (Circuit *circuit); }; +/** + * @brief Memory statistics for Net + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Net &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index c369b4c47..47a226961 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -103,6 +103,24 @@ Netlist &Netlist::operator= (const Netlist &other) return *this; } +void Netlist::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_circuits, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_device_classes, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_device_abstracts, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_top_down_circuits, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_child_circuits, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_parent_circuits, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_circuit_by_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_circuit_by_cell_index, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_device_abstract_by_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_device_abstract_by_cell_index, true, (void *) this); +} + void Netlist::set_case_sensitive (bool f) { m_case_sensitive = f; diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index bfac2d402..20a714d06 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -533,6 +533,11 @@ public: return normalize_name (is_case_sensitive (), n); } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const; + private: friend class Circuit; friend class DeviceAbstract; @@ -567,6 +572,14 @@ private: const tl::vector &parent_circuits (Circuit *circuit); }; +/** + * @brief Memory statistics for LayoutToNetlist + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Netlist &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + /** * @brief A helper class using RAII for safe locking/unlocking */ diff --git a/src/db/db/dbNetlistUtils.h b/src/db/db/dbNetlistUtils.h index da35bb546..aeb00961e 100644 --- a/src/db/db/dbNetlistUtils.h +++ b/src/db/db/dbNetlistUtils.h @@ -24,6 +24,12 @@ #define _HDR_dbNetlistUtils #include "dbCommon.h" +#include "dbTypes.h" +#include "dbMemStatistics.h" + +#include +#include +#include namespace db { @@ -102,6 +108,22 @@ public: return m == m_map.end () ? 0 : m->second; } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_map, true, (void *) this); + + for (typename std::map::const_iterator i = m_map.begin (); i != m_map.end (); ++i) { + db::mem_stat (stat, purpose, cat, *i->second, false, (void *) this); + } + } + private: T *mp_self; I (T::*m_bi) (); @@ -122,6 +144,15 @@ private: } }; +/** + * @brief Memory statistics for object_by_attr + */ +template +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const object_by_attr &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif diff --git a/src/db/db/dbPin.h b/src/db/db/dbPin.h index c07371046..c95c9966b 100644 --- a/src/db/db/dbPin.h +++ b/src/db/db/dbPin.h @@ -25,6 +25,7 @@ #include "dbCommon.h" #include "dbNetlistObject.h" +#include "dbMemStatistics.h" #include @@ -81,6 +82,18 @@ public: m_name = name; } + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + } + private: friend class Circuit; @@ -93,6 +106,14 @@ private: } }; +/** + * @brief Memory statistics for Pin + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Pin &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif diff --git a/src/db/db/dbSubCircuit.h b/src/db/db/dbSubCircuit.h index 7a5cfaa29..af9e561c7 100644 --- a/src/db/db/dbSubCircuit.h +++ b/src/db/db/dbSubCircuit.h @@ -26,6 +26,7 @@ #include "dbCommon.h" #include "dbTrans.h" #include "dbNet.h" +#include "dbMemStatistics.h" #include "tlObject.h" @@ -194,6 +195,20 @@ public: */ void connect_pin (size_t pin_id, Net *net); + /** + * @brief Generate memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const + { + if (! no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_name, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_trans, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_pin_refs, true, (void *) this); + } + private: friend class Circuit; friend class Net; @@ -232,6 +247,14 @@ private: } }; +/** + * @brief Memory statistics for SubCircuit + */ +inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const SubCircuit &x, bool no_self, void *parent) +{ + x.mem_stat (stat, purpose, cat, no_self, parent); +} + } #endif From 2f204eaa21a94918e9b7bf0ef22a7ea2dcf9eff1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 26 Apr 2021 23:15:27 +0200 Subject: [PATCH 2/5] Some refactoring of the instance-to-instance test in hier processor: gives some performance improvement with less memory for cache. --- src/db/db/dbHierNetworkProcessor.cc | 51 +++++++----------- src/db/db/dbLayoutToNetlist.cc | 4 +- ...ice_extract_au1_dup_inst_with_rec_nets.gds | Bin 55954 -> 54738 bytes 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 9f05c3746..d3eac046f 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1563,13 +1563,9 @@ private: db::ICplxTrans i1t, i2t; bool fill_cache = false; - // Cache is only used for single instances or simple arrays. - // Other schemes make the cache taking a lot of memory - because array vs. array testing may result in - // N x N cache entries when the arrayed cells contain child cells. - // We still allow the case of array vs. array when i1.size == i2.size as this efficiently caches - // array/array interactions. - if ((! i1element.at_end () || i1.size () == 1 || i1.size () == i2.size ()) && - (! i2element.at_end () || i2.size () == 1 || i1.size () == i2.size ())) { + // Cache is only used for single instances or simple and regular arrays. + if ((! i1element.at_end () || i1.size () == 1 || ! i1.is_iterated_array ()) && + (! i2element.at_end () || i2.size () == 1 || ! i2.is_iterated_array ())) { i1t = i1element.at_end () ? i1.complex_trans () : i1.complex_trans (*i1element); db::ICplxTrans tt1 = t1 * i1t; @@ -1653,6 +1649,22 @@ private: } + // dive into cell of ii1 + const db::Cell &cell1 = mp_layout->cell (i1.cell_index ()); + for (db::Cell::touching_iterator jj1 = cell1.begin_touching (common12.transformed (tt1.inverted ())); ! jj1.at_end (); ++jj1) { + + std::list > ii_interactions; + consider_instance_pair (common12, *jj1, tt1, db::CellInstArray::iterator (), i2, t2, ii2, ii_interactions); + + for (std::list >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { + propagate_cluster_inst (i->first, i1.cell_index (), i1t, i1.prop_id ()); + } + + ii_interactions.unique (); + interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); + + } + } if (! i2element.at_end ()) { @@ -1661,27 +1673,6 @@ private: } - box_type common1 = ib1 & b2 & common; - if (! common1.empty ()) { - - // dive into cell of ii1 - const db::Cell &cell1 = mp_layout->cell (i1.cell_index ()); - for (db::Cell::touching_iterator jj1 = cell1.begin_touching (common1.transformed (tt1.inverted ())); ! jj1.at_end (); ++jj1) { - - std::list > ii_interactions; - consider_instance_pair (common1, *jj1, tt1, db::CellInstArray::iterator (), i2, t2, i2element, ii_interactions); - - for (std::list >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { - propagate_cluster_inst (i->first, i1.cell_index (), i1t, i1.prop_id ()); - } - - ii_interactions.unique (); - interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); - - } - - } - if (! i1element.at_end ()) { break; } @@ -2245,11 +2236,9 @@ hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layou build_hier_connections_for_cells (cbc, layout, todo, conn, breakout_cells, progress, instance_interaction_cache); } - // @@@ - if (tl::verbosity () >= 0) { + if (tl::verbosity () >= 51) { tl::info << "Cluster build cache statistics: size=" << instance_interaction_cache.size () << ", hits=" << instance_interaction_cache.hits () << ", misses=" << instance_interaction_cache.misses (); } - // @@@ } template diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 0dbeac6cc..ac8d0adfe 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -397,13 +397,11 @@ void LayoutToNetlist::extract_netlist () netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); - // @@@ - if (tl::verbosity () >= 0) { + if (tl::verbosity () >= 41) { MemStatisticsCollector m (false); mem_stat (&m, db::MemStatistics::None, 0); m.print (); } - // @@@ m_netlist_extracted = true; } diff --git a/testdata/algo/device_extract_au1_dup_inst_with_rec_nets.gds b/testdata/algo/device_extract_au1_dup_inst_with_rec_nets.gds index 639924e76841d6230304f2cda52d171ef7ec1686..8df8f437445d59cdfd38867405d027dc41ac6b44 100644 GIT binary patch delta 1361 zcmbQVmHE1}3Hm1{p>s_NNRi3{ni@3_J|%$ZQ4{WCk6%)W>!1LPIK>L z%RgAU?9g8@J1T@hh83s2iBXZ_IELxC!$-5YF%57f7B*}Vq>L z$x9x1B)9nDk(?H^8@GcpqI%hIx|S#LEbegokcvBIH$Tb3BY7hqkK~yWJdy`0=W^n7 zZAr7VB2LL=OYlhEINHsOQ)ku5**Jr5vd+cXI5pn8h`ZpJ%y;<+qv7O-CSsFcUOs`- Kh!a;%u>t_x>-13o delta 1396 zcmcb#nt9Sz<|qa>1}3Hm1{p>s_QyarFAz#Im>{zmIGEUcJe?RAM3`Ca96Qauk1hXT z>9RwA!R)9I1{qeI`X)w2isLYH;;Easq$clT#3{FV6_X?*E{&USG2@ZsV&%lGQ;Y2; zPRYqq9Jt-X#TklIp$WJgu;$teoOllP19 z0_o3_?ZtUFKT-J1IJq9kNKq_in!H~UD57M{IC-r*kfE%@IQf{U$Yd3j&p5p(rvHY0 zvXi;P$SAae6K`6k~=G@2~O#Wz{Q(0H=8 zAot{mB$LTnf;^LFfN8$TFAQ}i8(6X9w9L;6Pk0*GZ z4X0~;V$R}>zs&}TxMP2_N*W$XiEKQQJO#KVHg;T5mcn$|b From c17d251d6e6df5490bb8241b4e3b8ec8961c7782 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 27 Apr 2021 07:41:35 +0200 Subject: [PATCH 3/5] Updated Changelog to make Debian package build pass --- Changelog.Debian | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.Debian b/Changelog.Debian index 4f8419b5b..7c46d7c0a 100644 --- a/Changelog.Debian +++ b/Changelog.Debian @@ -2,7 +2,7 @@ klayout (0.27-1) unstable; urgency=low * NOT RELEASED YET - -- Matthias Köfferlein Wed, 21 Apr 2021 21:39:50 +0200 + -- Matthias Köfferlein Tue, 27 Apr 2021 07:38:15 +0200 klayout (0.26.12-1) unstable; urgency=low From 855e8a3518f2cb75c1d163463b2516e2544b04a0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 27 Apr 2021 22:27:22 +0200 Subject: [PATCH 4/5] WIP: some enhancements with the effect of reducing instance interaction caching overhead and improving performance. More memory and cache metrics. --- src/db/db/dbHierNetworkProcessor.cc | 159 +++++++++++++++++++++++----- src/db/db/dbHierNetworkProcessor.h | 20 +++- src/db/db/dbMemStatistics.h | 39 +++++++ 3 files changed, 193 insertions(+), 25 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index d3eac046f..31f68314c 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -44,6 +44,11 @@ namespace db // ------------------------------------------------------------------------------ +// Don't cache instance to instance interaction sets beyond this size +const size_t instance_to_instance_cache_set_size_threshold = 10000; + +// ------------------------------------------------------------------------------ + template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t); template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t) @@ -311,6 +316,54 @@ bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned } } +bool Connectivity::interacts (const std::set &la, const std::set &lb) const +{ + for (std::set::const_iterator i = la.begin (); i != la.end (); ++i) { + db::Connectivity::layer_iterator je = end_connected (*i); + for (db::Connectivity::layer_iterator j = begin_connected (*i); j != je; ++j) { + if (lb.find (*j) != lb.end ()) { + return true; + } + } + } + + return false; +} + +bool Connectivity::interact (const db::Cell &a, const db::Cell &b) const +{ + for (std::map::const_iterator i = m_connected.begin (); i != m_connected.end (); ++i) { + if (! a.bbox (i->first).empty ()) { + for (layers_type::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { + if (! b.bbox (*j).empty ()) { + return true; + } + } + } + } + + return false; +} + +template +bool Connectivity::interact (const db::Cell &a, const T &ta, const db::Cell &b, const T &tb) const +{ + for (std::map::const_iterator i = m_connected.begin (); i != m_connected.end (); ++i) { + db::Box ba = a.bbox (i->first); + if (! ba.empty ()) { + ba.transform (ta); + for (layers_type::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { + db::Box bb = b.bbox (*j); + if (! bb.empty () && bb.transformed (tb).touches (ba)) { + return true; + } + } + } + } + + return false; +} + // explicit instantiations template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::UnitTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::ICplxTrans &trans) const; @@ -318,6 +371,7 @@ template DB_PUBLIC bool Connectivity::interacts (const db::Polyg template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::ICplxTrans &trans) const; +template DB_PUBLIC bool Connectivity::interact (const db::Cell &a, const db::ICplxTrans &ta, const db::Cell &b, const db::ICplxTrans &tb) const; // ------------------------------------------------------------------------------ // local_cluster implementation @@ -556,15 +610,7 @@ local_cluster::interacts (const local_cluster &other, const db::ICplxTrans return false; } - bool any = false; - - for (std::set::const_iterator i = ll1.begin (); i != ll1.end () && !any; ++i) { - db::Connectivity::layer_iterator je = conn.end_connected (*i); - for (db::Connectivity::layer_iterator j = conn.begin_connected (*i); j != je && !any; ++j) { - any = (ll2.find (*j) != ll2.end ()); - } - } - if (! any) { + if (! conn.interacts (ll1, ll2)) { return false; } @@ -1392,11 +1438,37 @@ public: * @brief Constructor */ hc_receiver (const db::Layout &layout, const db::Cell &cell, db::connected_clusters &cell_clusters, hier_clusters &tree, const cell_clusters_box_converter &cbc, const db::Connectivity &conn, const std::set *breakout_cells, typename hier_clusters::instance_interaction_cache_type *instance_interaction_cache) - : mp_layout (&layout), mp_cell (&cell), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn), mp_breakout_cells (breakout_cells), mp_instance_interaction_cache (instance_interaction_cache) + : mp_layout (&layout), mp_cell (&cell), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn), mp_breakout_cells (breakout_cells), m_cluster_cache_misses (0), m_cluster_cache_hits (0), mp_instance_interaction_cache (instance_interaction_cache) { mp_cell_clusters = &cell_clusters; } + /** + * @brief Gets the cache size + */ + size_t cluster_cache_size () const + { + db::MemStatisticsSimple ms; + ms << m_interaction_cache_for_clusters; + return ms.used (); + } + + /** + * @brief Gets the cache hits + */ + size_t cluster_cache_hits () const + { + return m_cluster_cache_hits; + } + + /** + * @brief Gets the cache misses + */ + size_t cluster_cache_misses () const + { + return m_cluster_cache_misses; + } + /** * @brief Receiver main event for instance-to-instance interactions */ @@ -1519,7 +1591,8 @@ private: std::map m_cm2join_map; join_set_list m_cm2join_sets; std::list m_ci_interactions; - std::map > > m_interaction_cache_for_clusters; + std::map > > m_interaction_cache_for_clusters; + size_t m_cluster_cache_misses, m_cluster_cache_hits; typename hier_clusters::instance_interaction_cache_type *mp_instance_interaction_cache; /** @@ -1559,13 +1632,21 @@ private: return; } + // gross shortcut: the cells do no comprise a constallation which will ever interact + if (! mp_conn->interact (mp_layout->cell (i1.cell_index ()), mp_layout->cell (i2.cell_index ()))) { + return; + } + InstanceToInstanceInteraction ii_key; db::ICplxTrans i1t, i2t; bool fill_cache = false; + size_t n1 = i1element.at_end () ? i1.size () : 1; + size_t n2 = i2element.at_end () ? i2.size () : 1; + // Cache is only used for single instances or simple and regular arrays. - if ((! i1element.at_end () || i1.size () == 1 || ! i1.is_iterated_array ()) && - (! i2element.at_end () || i2.size () == 1 || ! i2.is_iterated_array ())) { + if ((n1 == 1 || ! i1.is_iterated_array ()) && + (n2 == 1 || ! i2.is_iterated_array ())) { i1t = i1element.at_end () ? i1.complex_trans () : i1.complex_trans (*i1element); db::ICplxTrans tt1 = t1 * i1t; @@ -1595,10 +1676,35 @@ private: } + // avoid caching few-to-many interactions as this typically does not contribute anything fill_cache = true; } + // shortcut: if the instances cannot interact because their bounding boxes do no comprise a valid constellation, + // reject the pair + + bool any = false; + for (db::Connectivity::layer_iterator la = mp_conn->begin_layers (); la != mp_conn->end_layers () && ! any; ++la) { + db::box_convert bca (*mp_layout, *la); + box_type bb1 = i1.cell_inst ().bbox (bca).transformed (t1); + if (! bb1.empty ()) { + db::Connectivity::layer_iterator lbe = mp_conn->end_connected (*la); + for (db::Connectivity::layer_iterator lb = mp_conn->begin_connected (*la); lb != lbe && ! any; ++lb) { + db::box_convert bcb (*mp_layout, *lb); + box_type bb2 = i2.cell_inst ().bbox (bcb).transformed (t2); + any = bb1.touches (bb2); + } + } + } + + if (! any) { + if (fill_cache) { + mp_instance_interaction_cache->insert (ii_key); + } + return; + } + // array interactions db::ICplxTrans t1i = t1.inverted (); @@ -1625,9 +1731,9 @@ private: box_type common12 = ib1 & ib2 & common; if (! common12.empty ()) { - const std::vector > &i2i_interactions = compute_instance_interactions (common12, i1.cell_index (), tt1, i2.cell_index (), tt2); + const std::list > &i2i_interactions = compute_instance_interactions (common12, i1.cell_index (), tt1, i2.cell_index (), tt2); - for (std::vector >::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { + for (std::list >::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { ClusterInstance k1 (ii->first, i1.cell_index (), i1t, i1.prop_id ()); ClusterInstance k2 (ii->second, i2.cell_index (), i2t, i2.prop_id ()); interacting_clusters.push_back (std::make_pair (k1, k2)); @@ -1692,7 +1798,7 @@ private: // return the list of unique interactions interacting_clusters.insert (interacting_clusters.end (), sorted_interactions.begin (), sorted_interactions.end ()); - if (fill_cache) { + if (fill_cache && sorted_interactions.size () < instance_to_instance_cache_set_size_threshold) { // normalize transformations for cache db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted (); @@ -1710,13 +1816,13 @@ private: /** * @brief Computes a list of interacting clusters for two instances */ - const std::vector > & + const std::list > & compute_instance_interactions (const box_type &common, db::cell_index_type ci1, const db::ICplxTrans &t1, db::cell_index_type ci2, const db::ICplxTrans &t2) { if (is_breakout_cell (mp_breakout_cells, ci1) || is_breakout_cell (mp_breakout_cells, ci2)) { - static const std::vector > empty; + static const std::list > empty; return empty; } @@ -1728,7 +1834,7 @@ private: InteractionKeyForClustersType ikey (ci1, ci2, t1i, t21, common2); - typename std::map > >::const_iterator ici = m_interaction_cache_for_clusters.find (ikey); + typename std::map > >::const_iterator ici = m_interaction_cache_for_clusters.find (ikey); if (ici != m_interaction_cache_for_clusters.end ()) { return ici->second; @@ -1740,7 +1846,7 @@ private: const db::local_clusters &cl1 = mp_tree->clusters_per_cell (ci1); const db::local_clusters &cl2 = mp_tree->clusters_per_cell (ci2); - std::vector > &new_interactions = m_interaction_cache_for_clusters [ikey]; + std::list > &new_interactions = m_interaction_cache_for_clusters [ikey]; db::ICplxTrans t12 = t2i * t1; for (typename db::local_clusters::touching_iterator i = cl1.begin_touching (common2.transformed (t21)); ! i.at_end (); ++i) { @@ -1806,8 +1912,8 @@ private: cluster_instance_pair_list_type interacting_clusters; box_type common = (ib & ib2); - const std::vector > &i2i_interactions = compute_instance_interactions (common, i.cell_index (), tt, i.cell_index (), tt2); - for (std::vector >::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { + const std::list > &i2i_interactions = compute_instance_interactions (common, i.cell_index (), tt, i.cell_index (), tt2); + for (std::list >::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { ClusterInstance k1 (ii->first, i.cell_index (), tt, i.prop_id ()); ClusterInstance k2 (ii->second, i.cell_index (), tt2, i.prop_id ()); interacting_clusters.push_back (std::make_pair (k1, k2)); @@ -2236,8 +2342,8 @@ hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layou build_hier_connections_for_cells (cbc, layout, todo, conn, breakout_cells, progress, instance_interaction_cache); } - if (tl::verbosity () >= 51) { - tl::info << "Cluster build cache statistics: size=" << instance_interaction_cache.size () << ", hits=" << instance_interaction_cache.hits () << ", misses=" << instance_interaction_cache.misses (); + if (tl::verbosity () >= m_base_verbosity + 20) { + tl::info << "Cluster build cache statistics (instance to instance cache): size=" << instance_interaction_cache.size () << ", hits=" << instance_interaction_cache.hits () << ", misses=" << instance_interaction_cache.misses (); } } @@ -2430,6 +2536,11 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // join local clusters which got connected by child clusters rec->finish_cluster_to_instance_interactions (); + + if (tl::verbosity () >= m_base_verbosity + 20) { + tl::info << "Cluster build cache statistics (instance to shape cache): size=" << rec->cluster_cache_size () << ", hits=" << rec->cluster_cache_hits () << ", misses=" << rec->cluster_cache_misses (); + } + rec.reset (0); // finally connect global nets diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index aeb41b006..1db70a89a 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -187,6 +187,22 @@ public: return interacts (a, la, b, lb, UnitTrans ()); } + /** + * @brief Returns true, if two sets of layers interact + */ + bool interacts (const std::set &la, const std::set &lb) const; + + /** + * @brief Returns true, if two cells basically (without considering transformation) interact + */ + bool interact (const db::Cell &a, const db::Cell &b) const; + + /** + * @brief Returns true, if two cells with the given transformations interact + */ + template + bool interact (const db::Cell &a, const T &ta, const db::Cell &b, const T &tb) const; + private: layers_type m_all_layers; std::map m_connected; @@ -1095,7 +1111,9 @@ public: size_t size () const { - return m_map.size (); + MemStatisticsSimple ms; + ms << m_map; + return ms.used (); } size_t hits () const diff --git a/src/db/db/dbMemStatistics.h b/src/db/db/dbMemStatistics.h index 8293c85bf..4ed03a805 100644 --- a/src/db/db/dbMemStatistics.h +++ b/src/db/db/dbMemStatistics.h @@ -108,6 +108,45 @@ private: std::map > m_per_purpose; }; +/** + * @brief A simple memory statistics collector + * This collector will simply add the size required + */ +class DB_PUBLIC MemStatisticsSimple + : public MemStatistics +{ +public: + MemStatisticsSimple () + : m_size (0), m_used (0) + { } + + size_t size () const + { + return m_size; + } + + size_t used () const + { + return m_used; + } + + virtual void add (const std::type_info & /*ti*/, void * /*ptr*/, size_t size, size_t used, void * /*parent*/, purpose_t /*purpose*/, int /*cat*/) + { + m_size += size; + m_used += used; + } + + template + MemStatisticsSimple &operator<< (const T &x) + { + mem_stat (this, None, 0, x); + return *this; + } + +private: + size_t m_size, m_used; +}; + // Some standard templates to collect the information template void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const X &x, bool no_self = false, void *parent = 0) From 281681fffbc9edaec80bdd7bea62794b39453b31 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 28 Apr 2021 22:51:00 +0200 Subject: [PATCH 5/5] Limit hier processor instance/instance and instance/cluster cache depth to 20 entries per cell pair to avoid memory explosion --- src/db/db/dbHierNetworkProcessor.cc | 49 ++------ src/db/db/dbHierNetworkProcessor.h | 174 +++++++++++++++++----------- 2 files changed, 119 insertions(+), 104 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 31f68314c..c3ad9bc85 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1554,32 +1554,6 @@ public: void finalize (bool) { } private: - struct InteractionKeyForClustersType - : public InstanceToInstanceInteraction - { - InteractionKeyForClustersType (db::cell_index_type _ci1, db::cell_index_type _ci2, const db::ICplxTrans &_t1, const db::ICplxTrans &_t21, const box_type &_box) - : InstanceToInstanceInteraction (_ci1, 0, _ci2, 0, _t1, _t21), box (_box) - { } - - bool operator== (const InteractionKeyForClustersType &other) const - { - return InstanceToInstanceInteraction::operator== (other) && box == other.box; - } - - bool operator< (const InteractionKeyForClustersType &other) const - { - if (! InstanceToInstanceInteraction::operator== (other)) { - return InstanceToInstanceInteraction::operator< (other); - } - if (box != other.box) { - return box < other.box; - } - return false; - } - - box_type box; - }; - const db::Layout *mp_layout; const db::Cell *mp_cell; db::connected_clusters *mp_cell_clusters; @@ -1591,7 +1565,7 @@ private: std::map m_cm2join_map; join_set_list m_cm2join_sets; std::list m_ci_interactions; - std::map > > m_interaction_cache_for_clusters; + instance_interaction_cache, std::list > > m_interaction_cache_for_clusters; size_t m_cluster_cache_misses, m_cluster_cache_hits; typename hier_clusters::instance_interaction_cache_type *mp_instance_interaction_cache; @@ -1655,11 +1629,11 @@ private: db::ICplxTrans tt2 = t2 * i2t; db::ICplxTrans cache_norm = tt1.inverted (); - ii_key = InstanceToInstanceInteraction (i1.cell_index (), (! i1element.at_end () || i1.size () == 1) ? 0 : i1.cell_inst ().delegate (), - i2.cell_index (), (! i2element.at_end () || i2.size () == 1) ? 0 : i2.cell_inst ().delegate (), + ii_key = InstanceToInstanceInteraction ((! i1element.at_end () || i1.size () == 1) ? 0 : i1.cell_inst ().delegate (), + (! i2element.at_end () || i2.size () == 1) ? 0 : i2.cell_inst ().delegate (), cache_norm, cache_norm * tt2); - const cluster_instance_pair_list_type *cached = mp_instance_interaction_cache->find (ii_key); + const cluster_instance_pair_list_type *cached = mp_instance_interaction_cache->find (i1.cell_index (), i2.cell_index (), ii_key); if (cached) { // use cached interactions @@ -1700,7 +1674,7 @@ private: if (! any) { if (fill_cache) { - mp_instance_interaction_cache->insert (ii_key); + mp_instance_interaction_cache->insert (i1.cell_index (), i2.cell_index (), ii_key); } return; } @@ -1807,7 +1781,7 @@ private: i->second.transform (i2ti); } - cluster_instance_pair_list_type &cached = mp_instance_interaction_cache->insert (ii_key); + cluster_instance_pair_list_type &cached = mp_instance_interaction_cache->insert (i1.cell_index (), i2.cell_index (), ii_key); cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ()); } @@ -1832,12 +1806,12 @@ private: box_type common2 = common.transformed (t2i); - InteractionKeyForClustersType ikey (ci1, ci2, t1i, t21, common2); + interaction_key_for_clusters ikey (t1i, t21, common2); - typename std::map > >::const_iterator ici = m_interaction_cache_for_clusters.find (ikey); - if (ici != m_interaction_cache_for_clusters.end ()) { + const std::list > *ici = m_interaction_cache_for_clusters.find (ci1, ci2, ikey); + if (ici) { - return ici->second; + return *ici; } else { @@ -1846,7 +1820,7 @@ private: const db::local_clusters &cl1 = mp_tree->clusters_per_cell (ci1); const db::local_clusters &cl2 = mp_tree->clusters_per_cell (ci2); - std::list > &new_interactions = m_interaction_cache_for_clusters [ikey]; + std::list > &new_interactions = m_interaction_cache_for_clusters.insert (ci1, ci2, ikey); db::ICplxTrans t12 = t2i * t1; for (typename db::local_clusters::touching_iterator i = cl1.begin_touching (common2.transformed (t21)); ! i.at_end (); ++i) { @@ -2156,6 +2130,7 @@ private: // for instance-to-instance interactions the number of connections is more important for the // cost of the join operation: make the one with more connections the target + // TODO: this will be SLOW for STL's not providing a fast size() if (mp_cell_clusters->connections_for_cluster (x1).size () < mp_cell_clusters->connections_for_cluster (x2).size ()) { std::swap (x1, x2); } diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 1db70a89a..9475783c6 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -812,10 +812,10 @@ inline bool less_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b /** * @brief A helper struct to describe a pair of cell instances with a specific relative transformation */ -struct InstanceToInstanceInteraction +struct DB_PUBLIC InstanceToInstanceInteraction { - InstanceToInstanceInteraction (db::cell_index_type _ci1, const db::ArrayBase *_array1, db::cell_index_type _ci2, const db::ArrayBase *_array2, const db::ICplxTrans &_tn, const db::ICplxTrans &_t21) - : ci1 (_ci1), ci2 (_ci2), array1 (0), array2 (0), t21 (_t21) + InstanceToInstanceInteraction (const db::ArrayBase *_array1, const db::ArrayBase *_array2, const db::ICplxTrans &_tn, const db::ICplxTrans &_t21) + : array1 (0), array2 (0), t21 (_t21) { if (_array1) { array1 = _array1->basic_clone (); @@ -829,14 +829,13 @@ struct InstanceToInstanceInteraction } InstanceToInstanceInteraction () - : ci1 (0), ci2 (0), array1 (0), array2 (0) + : array1 (0), array2 (0) { // .. nothing yet .. } InstanceToInstanceInteraction (const InstanceToInstanceInteraction &other) - : ci1 (other.ci1), ci2 (other.ci2), - array1 (other.array1 ? other.array1->basic_clone () : 0), + : array1 (other.array1 ? other.array1->basic_clone () : 0), array2 (other.array2 ? other.array2->basic_clone () : 0), t21 (other.t21) { @@ -847,9 +846,6 @@ struct InstanceToInstanceInteraction { if (this != &other) { - ci1 = other.ci1; - ci2 = other.ci2; - if (array1) { delete array1; } @@ -882,19 +878,13 @@ struct InstanceToInstanceInteraction bool operator== (const InstanceToInstanceInteraction &other) const { - return ci1 == other.ci1 && ci2 == other.ci2 && t21.equal (other.t21) && + return t21.equal (other.t21) && equal_array_delegates (array1, other.array1) && equal_array_delegates (array2, other.array2); } bool operator< (const InstanceToInstanceInteraction &other) const { - if (ci1 != other.ci1) { - return ci1 < other.ci1; - } - if (ci2 != other.ci2) { - return ci2 < other.ci2; - } if (! t21.equal (other.t21)) { return t21.less (other.t21); } @@ -906,11 +896,110 @@ struct InstanceToInstanceInteraction return less_array_delegates (array2, other.array2); } - db::cell_index_type ci1, ci2; db::ArrayBase *array1, *array2; db::ICplxTrans t21; }; +template +struct DB_PUBLIC_TEMPLATE interaction_key_for_clusters + : public InstanceToInstanceInteraction +{ + interaction_key_for_clusters (const db::ICplxTrans &_t1, const db::ICplxTrans &_t21, const Box &_box) + : InstanceToInstanceInteraction (0, 0, _t1, _t21), box (_box) + { } + + bool operator== (const interaction_key_for_clusters &other) const + { + return InstanceToInstanceInteraction::operator== (other) && box == other.box; + } + + bool operator< (const interaction_key_for_clusters &other) const + { + if (! InstanceToInstanceInteraction::operator== (other)) { + return InstanceToInstanceInteraction::operator< (other); + } + if (box != other.box) { + return box < other.box; + } + return false; + } + + Box box; +}; + +/** + * @brief An object representing the instance interaction cache + */ +template +class DB_PUBLIC_TEMPLATE instance_interaction_cache +{ +public: + instance_interaction_cache () + : m_hits (0), m_misses (0) + { } + + size_t size () const + { + MemStatisticsSimple ms; + ms << m_map; + return ms.used (); + } + + size_t hits () const + { + return m_hits; + } + + size_t misses () const + { + return m_misses; + } + + const Value *find (db::cell_index_type ci1, db::cell_index_type ci2, const Key &key) const + { + typename std::map , std::list > >::iterator i1 = m_map.find (std::make_pair (ci1, ci2)); + if (i1 == m_map.end ()) { + ++m_misses; + return 0; + } + + // NOTE: the number of entries is low, so we can afford a linear search + typename std::list >::iterator i = i1->second.begin (); + while (i != i1->second.end () && ! (i->first == key)) { + ++i; + } + + if (i == i1->second.end ()) { + ++m_misses; + return 0; + } else { + // move the element to the front so the most frequently used ones are at the front + if (i != i1->second.begin ()) { + i1->second.splice (i1->second.begin(), i1->second, i, std::next (i)); + } + ++m_hits; + return &i->second; + } + } + + Value &insert (db::cell_index_type ci1, db::cell_index_type ci2, const Key &key) + { + const size_t instance_cache_variant_threshold = 20; + + std::list > &m = m_map [std::make_pair (ci1, ci2)]; + if (m.size () >= instance_cache_variant_threshold) { + m.pop_back (); + } + + m.push_front (std::make_pair (key, Value ())); + return m.front ().second; + } + +private: + mutable size_t m_hits, m_misses; + mutable std::map , std::list > > m_map; +}; + template class hier_clusters; template class connected_clusters; @@ -1099,56 +1188,7 @@ class DB_PUBLIC_TEMPLATE hier_clusters public: typedef typename local_cluster::box_type box_type; - /** - * @brief An object representing the instance interaction cache - */ - class instance_interaction_cache - { - public: - instance_interaction_cache () - : m_hits (0), m_misses (0) - { } - - size_t size () const - { - MemStatisticsSimple ms; - ms << m_map; - return ms.used (); - } - - size_t hits () const - { - return m_hits; - } - - size_t misses () const - { - return m_misses; - } - - const cluster_instance_pair_list_type *find (const InstanceToInstanceInteraction &key) const - { - std::map::const_iterator i = m_map.find (key); - if (i == m_map.end ()) { - ++m_misses; - return 0; - } else { - ++m_hits; - return &i->second; - } - } - - cluster_instance_pair_list_type &insert (const InstanceToInstanceInteraction &key) - { - return m_map [key]; - } - - private: - mutable size_t m_hits, m_misses; - std::map m_map; - }; - - typedef instance_interaction_cache instance_interaction_cache_type; + typedef instance_interaction_cache instance_interaction_cache_type; /** * @brief Creates an empty set of clusters