From 281681fffbc9edaec80bdd7bea62794b39453b31 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 28 Apr 2021 22:51:00 +0200 Subject: [PATCH] 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