From 712a390f52a7241e3deee8845effc90156de2f8e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 21 Nov 2018 00:17:14 +0100 Subject: [PATCH] WIP: added ref counting for deep shape layers and layouts --- src/db/db/dbDeepShapeStore.cc | 131 +++++++++++++++--- src/db/db/dbDeepShapeStore.h | 35 ++++- src/db/unit_tests/dbDeepShapeStoreTests.cc | 151 +++++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 3 +- 4 files changed, 294 insertions(+), 26 deletions(-) create mode 100644 src/db/unit_tests/dbDeepShapeStoreTests.cc diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 51d275f23..41f3909b9 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -41,18 +41,42 @@ DeepLayer::DeepLayer () DeepLayer::DeepLayer (const DeepLayer &x) : mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer) { - // .. nothing yet .. + if (mp_store.get ()) { + mp_store->add_ref (m_layout, m_layer); + } } DeepLayer::DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer) : mp_store (store), m_layout (layout), m_layer (layer) { - // .. nothing yet .. + if (store) { + store->add_ref (layout, layer); + } } +DeepLayer &DeepLayer::operator= (const DeepLayer &other) +{ + if (this != &other) { + if (mp_store.get ()) { + mp_store->remove_ref (m_layout, m_layer); + } + mp_store = other.mp_store; + m_layout = other.m_layout; + m_layer = other.m_layer; + if (mp_store.get ()) { + mp_store->add_ref (m_layout, m_layer); + } + } + + return *this; +} + + DeepLayer::~DeepLayer () { - // .. nothing yet .. + if (mp_store.get ()) { + mp_store->remove_ref (m_layout, m_layer); + } } DeepLayer @@ -121,6 +145,35 @@ DeepLayer::check_dss () const // ---------------------------------------------------------------------------------- +struct DeepShapeStore::LayoutHolder +{ + LayoutHolder () + : refs (0), layout (), builder (&layout) + { + // .. nothing yet .. + } + + void add_layer_ref (unsigned int layer) + { + layer_refs[layer] += 1; + } + + void remove_layer_ref (unsigned int layer) + { + if ((layer_refs[layer] -= 1) <= 0) { + layout.clear_layer (layer); + layer_refs.erase (layer); + } + } + + int refs; + db::Layout layout; + db::HierarchyBuilder builder; + std::map layer_refs; +}; + +// ---------------------------------------------------------------------------------- + static size_t s_instance_count = 0; DeepShapeStore::DeepShapeStore () @@ -132,6 +185,28 @@ DeepShapeStore::DeepShapeStore () DeepShapeStore::~DeepShapeStore () { --s_instance_count; + + for (std::vector::iterator h = m_layouts.begin (); h != m_layouts.end (); ++h) { + delete *h; + } + m_layouts.clear (); +} + +bool DeepShapeStore::is_valid_layout_index (unsigned int n) const +{ + return (n < (unsigned int) m_layouts.size () && m_layouts[n] != 0); +} + +const db::Layout *DeepShapeStore::const_layout (unsigned int n) const +{ + tl_assert (is_valid_layout_index (n)); + return &(m_layouts [n]->layout); +} + +db::Layout *DeepShapeStore::layout (unsigned int n) +{ + tl_assert (is_valid_layout_index (n)); + return &(m_layouts [n]->layout); } size_t DeepShapeStore::instance_count () @@ -144,35 +219,55 @@ void DeepShapeStore::set_threads (int n) m_threads = n; } +void DeepShapeStore::add_ref (unsigned int layout, unsigned int layer) +{ + tl::MutexLocker locker (&m_lock); + + tl_assert (layout < (unsigned int) m_layouts.size () && m_layouts[layout] != 0); + + m_layouts[layout]->refs += 1; + m_layouts[layout]->add_layer_ref (layer); +} + +void DeepShapeStore::remove_ref (unsigned int layout, unsigned int layer) +{ + tl::MutexLocker locker (&m_lock); + + tl_assert (layout < (unsigned int) m_layouts.size () && m_layouts[layout] != 0); + + m_layouts[layout]->remove_layer_ref (layer); + + if ((m_layouts[layout]->refs -= 1) <= 0) { + delete m_layouts[layout]; + m_layouts[layout] = 0; + } +} + DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) { unsigned int layout_index = 0; - unsigned int layer_index = 0; layout_map_type::iterator l = m_layout_map.find (si); if (l == m_layout_map.end ()) { layout_index = (unsigned int) m_layouts.size (); - m_layouts.push_back (new db::Layout ()); - m_layouts.back ().dbu (si.layout ()->dbu ()); - layer_index = m_layouts.back ().insert_layer (); - - m_builders.push_back (new db::HierarchyBuilder (&m_layouts.back (), layer_index)); + m_layouts.push_back (new LayoutHolder ()); + m_layouts.back ()->layout.dbu (si.layout ()->dbu ()); m_layout_map[si] = layout_index; } else { layout_index = l->second; - layer_index = m_layouts[layout_index].insert_layer (); - - m_builders[layout_index].set_target_layer (layer_index); } + unsigned int layer_index = m_layouts[layout_index]->layout.insert_layer (); + m_layouts[layout_index]->builder.set_target_layer (layer_index); + // The chain of operators for producing clipped and reduced polygon references - db::PolygonReferenceHierarchyBuilderShapeReceiver refs (& m_layouts[layout_index]); + db::PolygonReferenceHierarchyBuilderShapeReceiver refs (& m_layouts[layout_index]->layout); db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count); db::ClippingHierarchyBuilderShapeReceiver clip (&red); @@ -181,12 +276,12 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator tl::SelfTimer timer (tl::to_string (tr ("Building working hierarchy"))); - m_builders[layout_index].set_shape_receiver (&clip); - db::RecursiveShapeIterator (si).push (& m_builders[layout_index]); - m_builders[layout_index].set_shape_receiver (0); + m_layouts[layout_index]->builder.set_shape_receiver (&clip); + db::RecursiveShapeIterator (si).push (& m_layouts[layout_index]->builder); + m_layouts[layout_index]->builder.set_shape_receiver (0); } catch (...) { - m_builders[layout_index].set_shape_receiver (0); + m_layouts[layout_index]->builder.set_shape_receiver (0); throw; } @@ -204,7 +299,7 @@ DeepShapeStore::insert (const DeepLayer &deep_layer, db::Layout *into_layout, db db::cell_index_type source_top = *source_layout->begin_top_down(); - db::HierarchyBuilder &original_builder = m_builders [deep_layer.layout_index ()]; + db::HierarchyBuilder &original_builder = m_layouts [deep_layer.layout_index ()]->builder; // derive a cell mapping for source to target. We employ a diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 9607815b0..c4ee8cd0c 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -28,6 +28,7 @@ #include "tlObject.h" #include "tlStableVector.h" +#include "tlThreads.h" #include "dbLayout.h" #include "dbRecursiveShapeIterator.h" #include "dbHierarchyBuilder.h" @@ -197,7 +198,7 @@ public: DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16); /** - * @brief Inserts the deep layer's into some target layout + * @brief Inserts the deep layer's shapes into some target layout */ void insert (const DeepLayer &layer, db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer); @@ -206,6 +207,24 @@ public: */ static size_t instance_count (); + /** + * @brief Gets the nth layout (const version) + */ + const db::Layout *const_layout (unsigned int n) const; + + /** + * @brief Gets the number of layouts + */ + unsigned int layouts () const + { + return (unsigned int) m_layouts.size (); + } + + /** + * @brief Gets a value indicating whether the given index is a valid layout index + */ + bool is_valid_layout_index (unsigned int n) const; + /** * @brief The deep shape store also keeps the number of threads to allocate for the hierarchical processor * @@ -224,10 +243,12 @@ public: private: friend class DeepLayer; - db::Layout *layout (unsigned int n) - { - return &m_layouts [n]; - } + struct LayoutHolder; + + db::Layout *layout (unsigned int n); + + void add_ref (unsigned int layout, unsigned int layer); + void remove_ref (unsigned int layout, unsigned int layer); typedef std::map layout_map_type; @@ -235,10 +256,10 @@ private: DeepShapeStore (const DeepShapeStore &); DeepShapeStore &operator= (const DeepShapeStore &); - tl::stable_vector m_layouts; - tl::stable_vector m_builders; + std::vector m_layouts; layout_map_type m_layout_map; int m_threads; + tl::Mutex m_lock; struct DeliveryMappingCacheKey { diff --git a/src/db/unit_tests/dbDeepShapeStoreTests.cc b/src/db/unit_tests/dbDeepShapeStoreTests.cc new file mode 100644 index 000000000..eb21e8020 --- /dev/null +++ b/src/db/unit_tests/dbDeepShapeStoreTests.cc @@ -0,0 +1,151 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbDeepShapeStore.h" +#include "tlUnitTest.h" +#include "tlStream.h" + +TEST(1) +{ + db::DeepShapeStore store; + db::Layout layout; + + unsigned int l1 = layout.insert_layer (); + unsigned int l2 = layout.insert_layer (); + db::cell_index_type c1 = layout.add_cell ("C1"); + db::cell_index_type c2 = layout.add_cell ("C2"); + + EXPECT_EQ (store.layouts (), (unsigned int) 0); + + db::DeepLayer dl1 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l1)); + db::DeepLayer dl2 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l2)); + + EXPECT_EQ (dl1.layer (), l1); + EXPECT_EQ (dl2.layer (), l2); + EXPECT_EQ (dl1.layout (), dl2.layout ()); + EXPECT_EQ (store.layouts (), (unsigned int) 1); + + db::DeepLayer dl3 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c2), l1)); + EXPECT_EQ (dl3.layer (), l1); + EXPECT_NE (dl1.layout (), dl3.layout ()); + EXPECT_EQ (store.layouts (), (unsigned int) 2); + + db::DeepLayer dl4 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l1, db::Box (0, 1, 2, 3))); + db::DeepLayer dl5 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l2, db::Box (0, 1, 2, 3))); + EXPECT_EQ (dl4.layer (), l1); + EXPECT_EQ (dl5.layer (), l1); // not l2, because it's a new layout + EXPECT_EQ (store.layouts (), (unsigned int) 4); + + db::DeepLayer dl6 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l1, db::Box (0, 1, 2, 3))); + EXPECT_EQ (dl6.layer (), l2); // a new layer (a copy) + EXPECT_EQ (dl6.layout (), dl4.layout ()); + EXPECT_EQ (store.layouts (), (unsigned int) 4); +} + +static size_t shapes_in_top (const db::Layout *layout, unsigned int layer) +{ + const db::Cell &top = layout->cell (*layout->begin_top_down ()); + return top.shapes (layer).size (); +} + +TEST(2_RefCounting) +{ + db::DeepShapeStore store; + db::Layout layout; + + unsigned int l1 = layout.insert_layer (); + unsigned int l2 = layout.insert_layer (); + db::cell_index_type c1 = layout.add_cell ("C1"); + db::cell_index_type c2 = layout.add_cell ("C2"); + layout.cell (c1).shapes (l1).insert (db::Box (0, 1, 2, 3)); + layout.cell (c1).shapes (l2).insert (db::Box (0, 1, 2, 3)); + + EXPECT_EQ (store.layouts (), (unsigned int) 0); + + db::DeepLayer dl1 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l1)); + db::DeepLayer dl2 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l2)); + db::DeepLayer dl3 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c2), l1)); + db::DeepLayer dl4 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l1, db::Box (0, 1, 2, 3))); + db::DeepLayer dl5 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l2, db::Box (0, 1, 2, 3))); + db::DeepLayer dl6 = store.create_polygon_layer (db::RecursiveShapeIterator (layout, layout.cell (c1), l1, db::Box (0, 1, 2, 3))); + + EXPECT_EQ (store.layouts (), (unsigned int) 4); + + unsigned int lyi1 = dl1.layout_index (); + unsigned int lyi2 = dl2.layout_index (); + unsigned int lyi3 = dl3.layout_index (); + unsigned int lyi4 = dl4.layout_index (); + unsigned int lyi5 = dl5.layout_index (); + unsigned int lyi6 = dl6.layout_index (); + + EXPECT_EQ (lyi1, lyi2); + EXPECT_NE (lyi3, lyi2); + EXPECT_NE (lyi5, lyi4); + EXPECT_NE (lyi5, lyi3); + EXPECT_EQ (lyi6, lyi4); + + EXPECT_EQ (dl1.layer (), l1); + EXPECT_EQ (dl2.layer (), l2); + EXPECT_EQ (dl4.layer (), l1); + EXPECT_EQ (dl6.layer (), l2); + + // dl1 and dl2 share the same layout, but not the same layer + // dl4 and dl6 share the same layout, but not the same layer + + EXPECT_EQ (store.is_valid_layout_index (lyi6), true); + EXPECT_EQ (store.is_valid_layout_index (lyi5), true); + EXPECT_EQ (store.is_valid_layout_index (lyi3), true); + EXPECT_EQ (store.is_valid_layout_index (lyi1), true); + + EXPECT_EQ (shapes_in_top (store.const_layout (lyi6), l2), size_t (1)); + dl6 = db::DeepLayer (); + EXPECT_EQ (shapes_in_top (store.const_layout (lyi6), l2), size_t (0)); + + EXPECT_EQ (shapes_in_top (store.const_layout (lyi6), l1), size_t (1)); + db::DeepLayer dl4a = dl4; + dl4 = db::DeepLayer (); + EXPECT_EQ (shapes_in_top (store.const_layout (lyi6), l1), size_t (1)); + dl4a = db::DeepLayer (); + EXPECT_EQ (store.is_valid_layout_index (lyi6), false); + + dl3 = db::DeepLayer (); + EXPECT_EQ (store.is_valid_layout_index (lyi3), false); + + { + db::DeepLayer dl5a = dl5; + db::DeepLayer dl5b = dl5a; + dl5 = db::DeepLayer (); + EXPECT_EQ (store.is_valid_layout_index (lyi5), true); + } + EXPECT_EQ (store.is_valid_layout_index (lyi5), false); + + EXPECT_EQ (shapes_in_top (store.const_layout (lyi1), l1), size_t (1)); + EXPECT_EQ (shapes_in_top (store.const_layout (lyi1), l2), size_t (1)); + + dl1 = db::DeepLayer (); + EXPECT_EQ (shapes_in_top (store.const_layout (lyi1), l1), size_t (0)); + EXPECT_EQ (shapes_in_top (store.const_layout (lyi1), l2), size_t (1)); + + dl2 = db::DeepLayer (); + EXPECT_EQ (store.is_valid_layout_index (lyi1), false); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 5c0d7a9a4..b35a4ef9e 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -56,7 +56,8 @@ SOURCES = \ dbHierarchyBuilderTests.cc \ dbRecursiveShapeIteratorTests.cc \ dbHierProcessorTests.cc \ - dbDeepRegionTests.cc + dbDeepRegionTests.cc \ + dbDeepShapeStoreTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC