Limit hier processor instance/instance and instance/cluster cache depth to 20 entries per cell pair to avoid memory explosion

This commit is contained in:
Matthias Koefferlein 2021-04-28 22:51:00 +02:00
parent 855e8a3518
commit 281681fffb
2 changed files with 119 additions and 104 deletions

View File

@ -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<T> *mp_cell_clusters;
@ -1591,7 +1565,7 @@ private:
std::map<id_type, typename join_set_list::iterator> m_cm2join_map;
join_set_list m_cm2join_sets;
std::list<ClusterInstanceInteraction> m_ci_interactions;
std::map<InteractionKeyForClustersType, std::list<std::pair<size_t, size_t> > > m_interaction_cache_for_clusters;
instance_interaction_cache<interaction_key_for_clusters<box_type>, std::list<std::pair<size_t, size_t> > > m_interaction_cache_for_clusters;
size_t m_cluster_cache_misses, m_cluster_cache_hits;
typename hier_clusters<T>::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<box_type> ikey (t1i, t21, common2);
typename std::map<InteractionKeyForClustersType, std::list<std::pair<size_t, size_t> > >::const_iterator ici = m_interaction_cache_for_clusters.find (ikey);
if (ici != m_interaction_cache_for_clusters.end ()) {
const std::list<std::pair<size_t, size_t> > *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<T> &cl1 = mp_tree->clusters_per_cell (ci1);
const db::local_clusters<T> &cl2 = mp_tree->clusters_per_cell (ci2);
std::list<std::pair<size_t, size_t> > &new_interactions = m_interaction_cache_for_clusters [ikey];
std::list<std::pair<size_t, size_t> > &new_interactions = m_interaction_cache_for_clusters.insert (ci1, ci2, ikey);
db::ICplxTrans t12 = t2i * t1;
for (typename db::local_clusters<T>::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);
}

View File

@ -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 <class Box>
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 Key, class Value>
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::pair<db::cell_index_type, db::cell_index_type>, std::list <std::pair<Key, Value> > >::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 <std::pair<Key, Value> >::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 <std::pair<Key, Value> > &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::pair<db::cell_index_type, db::cell_index_type>, std::list <std::pair<Key, Value> > > m_map;
};
template <class T> class hier_clusters;
template <class T> class connected_clusters;
@ -1099,56 +1188,7 @@ class DB_PUBLIC_TEMPLATE hier_clusters
public:
typedef typename local_cluster<T>::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<InstanceToInstanceInteraction, cluster_instance_pair_list_type>::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<InstanceToInstanceInteraction, cluster_instance_pair_list_type> m_map;
};
typedef instance_interaction_cache instance_interaction_cache_type;
typedef instance_interaction_cache<InstanceToInstanceInteraction, cluster_instance_pair_list_type> instance_interaction_cache_type;
/**
* @brief Creates an empty set of clusters