From fb6cf92b154efd9154cbc3659ea141fd4d2fa3a8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 14 Feb 2017 00:13:57 +0100 Subject: [PATCH] WIP on complex regions for RecursiveShapeIterator - Added some tests - Performance improvements for insert of regions into shapes - Added LayoutLocker for that purpose (locks a layout against updates temporarily) - Improved implementation on RecursiveShapeIterator with complex regions: will now check if a shape is really inside the region. --- src/db/dbLayout.h | 39 ++++++++ src/db/dbRecursiveShapeIterator.cc | 111 ++++++++++++--------- src/db/dbRecursiveShapeIterator.h | 2 + src/db/gsiDeclDbRecursiveShapeIterator.cc | 8 +- src/db/gsiDeclDbRegion.cc | 1 - src/db/gsiDeclDbShapes.cc | 6 ++ src/unit_tests/dbRecursiveShapeIterator.cc | 64 ++++++++++++ 7 files changed, 177 insertions(+), 54 deletions(-) diff --git a/src/db/dbLayout.h b/src/db/dbLayout.h index f6931e1da..0fd6f91d9 100644 --- a/src/db/dbLayout.h +++ b/src/db/dbLayout.h @@ -1672,6 +1672,45 @@ private: void do_prune_cells_or_subcells (const std::set &ids, int levels, bool subcells); }; +/** + * @brief A nice helper class that employs RAII for locking the layout against updates + * + * If a layout shall be locked against internal updates temporarily, use this locker: + * @code + * Layout *ly = ...; + * { + * db::LayoutLocker locker (ly); + * // the layout is not updated here + * ... modify the layout + * } + * // now only the layout gets updated + * @endcode + */ +class DB_PUBLIC LayoutLocker +{ +public: + explicit LayoutLocker (db::Layout *layout = 0) + : mp_layout (layout) + { + if (mp_layout) { + mp_layout->start_changes (); + } + } + + ~LayoutLocker () + { + if (mp_layout) { + mp_layout->end_changes (); + } + } + +private: + LayoutLocker (const LayoutLocker &); + LayoutLocker &operator= (const LayoutLocker &); + + db::Layout *mp_layout; +}; + } #endif diff --git a/src/db/dbRecursiveShapeIterator.cc b/src/db/dbRecursiveShapeIterator.cc index d4d495e99..c86fd8399 100644 --- a/src/db/dbRecursiveShapeIterator.cc +++ b/src/db/dbRecursiveShapeIterator.cc @@ -497,6 +497,60 @@ RecursiveShapeIterator::bbox () const return box; } +void +RecursiveShapeIterator::skip_shape_iter_for_complex_region () const +{ + while (! m_shape.at_end ()) { + + // skip shape quad if possible + while (! m_shape.at_end ()) { + if (is_outside_complex_region (m_shape.quad_box ())) { + m_shape.skip_quad (); + } else { + m_shape_quad_id = m_shape.quad_id (); + break; + } + } + + // skip shapes outside the complex region + if (! m_shape.at_end ()) { + if (! is_outside_complex_region (m_shape->bbox ())) { + break; + } else { + ++m_shape; + } + } + + } +} + +void +RecursiveShapeIterator::skip_inst_iter_for_complex_region () const +{ + while (! m_inst.at_end ()) { + + // skip inst quad if possible + while (! m_inst.at_end ()) { + if (is_outside_complex_region (m_inst.quad_box ())) { + m_inst.skip_quad (); + } else { + m_inst_quad_id = m_inst.quad_id (); + break; + } + } + + // skip insts outside the complex region + if (! m_inst.at_end ()) { + if (! is_outside_complex_region (m_inst->bbox ())) { + break; + } else { + ++m_inst; + } + } + + } +} + void RecursiveShapeIterator::next () { @@ -504,16 +558,8 @@ RecursiveShapeIterator::next () ++m_shape; - // skip shape quad if possible - if (! m_local_complex_region_stack.empty () && m_shape_quad_id != m_shape.quad_id ()) { - while (! m_shape.at_end ()) { - if (is_outside_complex_region (m_shape.quad_box ())) { - m_shape.skip_quad (); - } else { - m_shape_quad_id = m_shape.quad_id (); - break; - } - } + if (! m_local_complex_region_stack.empty ()) { + skip_shape_iter_for_complex_region (); } if (! mp_shapes && m_shape.at_end ()) { @@ -626,9 +672,8 @@ RecursiveShapeIterator::down () const if (! m_local_complex_region_stack.empty ()) { - const box_tree_type &pcl = m_local_complex_region_stack.back (); - m_local_complex_region_stack.push_back (box_tree_type ()); + const box_tree_type &pcl = m_local_complex_region_stack.end ()[-2]; if (! new_region.empty ()) { @@ -694,16 +739,8 @@ RecursiveShapeIterator::start_shapes () const m_shape_quad_id = 0; - // skip instance quad if possible if (! m_local_complex_region_stack.empty ()) { - while (! m_shape.at_end ()) { - if (is_outside_complex_region (m_shape.quad_box ())) { - m_shape.skip_quad (); - } else { - m_shape_quad_id = m_shape.quad_id (); - break; - } - } + skip_shape_iter_for_complex_region (); } } @@ -722,14 +759,7 @@ RecursiveShapeIterator::new_layer () const // skip instance quad if possible if (! m_local_complex_region_stack.empty ()) { - while (! m_shape.at_end ()) { - if (is_outside_complex_region (m_shape.quad_box ())) { - m_shape.skip_quad (); - } else { - m_shape_quad_id = m_shape.quad_id (); - break; - } - } + skip_shape_iter_for_complex_region (); } } @@ -755,14 +785,7 @@ RecursiveShapeIterator::new_cell () const // skip instance quad if possible if (! m_local_complex_region_stack.empty ()) { - while (! m_inst.at_end ()) { - if (is_outside_complex_region (m_inst.quad_box ())) { - m_inst.skip_quad (); - } else { - m_inst_quad_id = m_inst.quad_id (); - break; - } - } + skip_inst_iter_for_complex_region (); } new_inst (); @@ -777,21 +800,11 @@ RecursiveShapeIterator::new_inst () const while (! m_inst.at_end ()) { // skip instance quad if possible - if (! m_local_complex_region_stack.empty () && m_inst_quad_id != m_inst.quad_id ()) { - - while (! m_inst.at_end ()) { - if (is_outside_complex_region (m_inst.quad_box ())) { - m_inst.skip_quad (); - } else { - m_inst_quad_id = m_inst.quad_id (); - break; - } - } - + if (! m_local_complex_region_stack.empty ()) { + skip_inst_iter_for_complex_region (); if (m_inst.at_end ()) { break; } - } if (m_local_region_stack.back () != box_type::world ()) { diff --git a/src/db/dbRecursiveShapeIterator.h b/src/db/dbRecursiveShapeIterator.h index 7473f5d81..c9c8e2e8d 100644 --- a/src/db/dbRecursiveShapeIterator.h +++ b/src/db/dbRecursiveShapeIterator.h @@ -694,6 +694,8 @@ private: void init (); void init_complex_region (const box_type &box, const region_type &excl_region); void init_complex_region (const region_type &excl_region); + void skip_shape_iter_for_complex_region () const; + void skip_inst_iter_for_complex_region () const; void validate () const; void start_shapes () const; void next_shape () const; diff --git a/src/db/gsiDeclDbRecursiveShapeIterator.cc b/src/db/gsiDeclDbRecursiveShapeIterator.cc index 72a5d205c..5df1c9edd 100644 --- a/src/db/gsiDeclDbRecursiveShapeIterator.cc +++ b/src/db/gsiDeclDbRecursiveShapeIterator.cc @@ -161,7 +161,7 @@ Class decl_RecursiveShapeIterator ("RecursiveShapeIt ) + gsi::constructor ("new", &new_si3a, "@brief Creates a recursive, single-layer shape iterator with a region.\n" - "@args layout, cell, layer, box, overlapping\n" + "@args layout, cell, layer, box, excl_region, overlapping\n" "@param layout The layout which shall be iterated\n" "@param cell The initial cell which shall be iterated (including it's children)\n" "@param layer The layer (index) from which the shapes are taken\n" @@ -184,7 +184,7 @@ Class decl_RecursiveShapeIterator ("RecursiveShapeIt ) + gsi::constructor ("new", &new_si3b, "@brief Creates a recursive, single-layer shape iterator with a region.\n" - "@args layout, cell, layer, box, overlapping\n" + "@args layout, cell, layer, region, overlapping\n" "@param layout The layout which shall be iterated\n" "@param cell The initial cell which shall be iterated (including it's children)\n" "@param layer The layer (index) from which the shapes are taken\n" @@ -222,7 +222,7 @@ Class decl_RecursiveShapeIterator ("RecursiveShapeIt ) + gsi::constructor ("new", &new_si4a, "@brief Creates a recursive, multi-layer shape iterator with a region.\n" - "@args layout, cell, layers, box, overlapping\n" + "@args layout, cell, layers, box, excl_region, overlapping\n" "@param layout The layout which shall be iterated\n" "@param cell The initial cell which shall be iterated (including it's children)\n" "@param layers The layer indexes from which the shapes are taken\n" @@ -246,7 +246,7 @@ Class decl_RecursiveShapeIterator ("RecursiveShapeIt ) + gsi::constructor ("new", &new_si4b, "@brief Creates a recursive, multi-layer shape iterator with a region.\n" - "@args layout, cell, layers, box, overlapping\n" + "@args layout, cell, layers, region, overlapping\n" "@param layout The layout which shall be iterated\n" "@param cell The initial cell which shall be iterated (including it's children)\n" "@param layers The layer indexes from which the shapes are taken\n" diff --git a/src/db/gsiDeclDbRegion.cc b/src/db/gsiDeclDbRegion.cc index 1a5086e6f..66dba7320 100644 --- a/src/db/gsiDeclDbRegion.cc +++ b/src/db/gsiDeclDbRegion.cc @@ -20,7 +20,6 @@ */ - #include "gsiDecl.h" #include "dbRegion.h" diff --git a/src/db/gsiDeclDbShapes.cc b/src/db/gsiDeclDbShapes.cc index bfe6972c6..737b16fb6 100644 --- a/src/db/gsiDeclDbShapes.cc +++ b/src/db/gsiDeclDbShapes.cc @@ -207,6 +207,9 @@ static db::Shape insert_shape_with_dcplx_trans (db::Shapes *s, const db::Shape & static void insert_region (db::Shapes *sh, const db::Region &r) { + // NOTE: if the source (r) is from the same layout than the shapes live in, we better + // lock the layout against updates while inserting + db::LayoutLocker locker (sh->layout ()); for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) { sh->insert (*s); } @@ -214,6 +217,9 @@ static void insert_region (db::Shapes *sh, const db::Region &r) static void insert_region_with_trans (db::Shapes *sh, const db::Region &r, const db::ICplxTrans &trans) { + // NOTE: if the source (r) is from the same layout than the shapes live in, we better + // lock the layout against updates while inserting + db::LayoutLocker locker (sh->layout ()); for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) { sh->insert (s->transformed (trans)); } diff --git a/src/unit_tests/dbRecursiveShapeIterator.cc b/src/unit_tests/dbRecursiveShapeIterator.cc index 74c38eaf6..2db048433 100644 --- a/src/unit_tests/dbRecursiveShapeIterator.cc +++ b/src/unit_tests/dbRecursiveShapeIterator.cc @@ -22,6 +22,7 @@ #include "dbRecursiveShapeIterator.h" +#include "dbRegion.h" #include "tlString.h" #include "utHead.h" @@ -274,6 +275,10 @@ TEST(1a) std::string x; + db::RecursiveShapeIterator i0 (g, c0, 0, db::Box ()); + x = collect(i0, g); + EXPECT_EQ (x, ""); + db::RecursiveShapeIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100)); x = collect(i1, g); EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); @@ -393,6 +398,10 @@ TEST(2) std::string x; + db::RecursiveShapeIterator i0 (g, c0, 0, db::Box ()); + x = collect(i0, g); + EXPECT_EQ (x, ""); + db::RecursiveShapeIterator i (g, c0, 0, db::Box::world ()); x = collect(i, g); EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); @@ -414,4 +423,59 @@ TEST(2) EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); } +TEST(3) +{ + db::Manager m; + db::Layout g (&m); + g.insert_layer(0); + + db::Cell &c0 (g.cell (g.add_cell ())); + db::Cell &c1 (g.cell (g.add_cell ())); + db::Cell &c2 (g.cell (g.add_cell ())); + + db::Box b (1000, -500, 2000, 500); + c2.shapes (0).insert (b); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2)); + c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2)); + + std::string x; + + db::RecursiveShapeIterator i (g, c0, 0, db::Box::world ()); + x = collect(i, g); + EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)"); + + db::RecursiveShapeIterator i2 (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500))); + x = collect(i2, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)"); + + db::RecursiveShapeIterator i3 (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850))); + x = collect(i3, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + + db::Region rr; + rr.insert (db::Box (3400, 3450, 5600, 6500)); + rr.insert (db::Box (6650, 5300, 10000, 7850)); + + db::RecursiveShapeIterator i23 (g, c0, 0, rr); + x = collect(i23, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)"); + + db::RecursiveShapeIterator i2o (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500)), true); + x = collect(i2o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)"); + + db::RecursiveShapeIterator i3o (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850)), true); + x = collect(i3o, g); + EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); + + db::Region rro; + rro.insert (db::Box (3400, 3450, 5600, 6500)); + rro.insert (db::Box (6650, 5300, 10000, 7850)); + + db::RecursiveShapeIterator i23o (g, c0, 0, rro); + x = collect(i23o, g); + EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)"); +}