Skip to content

Commit adb8126

Browse files
author
Matthias Koefferlein
committed
Experimental feature: Region#peel to reduce hierarchical load
1 parent b7d18af commit adb8126

12 files changed

Lines changed: 304 additions & 56 deletions

src/db/db/dbAsIfFlatRegion.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ class DB_PUBLIC AsIfFlatRegion
138138

139139
virtual RegionDelegate *add (const Region &other) const;
140140

141+
virtual RegionDelegate *peel (double /*complexity_factor*/) const
142+
{
143+
return const_cast<AsIfFlatRegion *> (this);
144+
}
145+
141146
virtual RegionDelegate *selected_outside (const Region &other) const
142147
{
143148
return selected_interacting_generic (other, 1, false, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;

src/db/db/dbDeepRegion.cc

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,140 @@ DeepRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Var
880880
return new db::DeepRegion (result);
881881
}
882882

883+
namespace {
884+
885+
/**
886+
* @brief Implements a boolean AND or NOT operation with property handling
887+
*/
888+
class DB_PUBLIC PushHierLocalOperationWithProperties
889+
: public local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> >
890+
{
891+
public:
892+
PushHierLocalOperationWithProperties (double complexity_factor)
893+
: local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > (),
894+
m_complexity_factor (complexity_factor)
895+
{
896+
// .. nothing yet ..
897+
}
898+
899+
OnEmptyIntruderHint on_empty_intruder_hint () const { return Copy; }
900+
901+
std::string description () const
902+
{
903+
return tl::to_string (tr ("'peel' operation"));
904+
}
905+
906+
907+
virtual void do_compute_local (db::Layout *layout, db::Cell * /*subject_cell*/, const shape_interactions<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > &interactions, std::vector<std::unordered_set<db::object_with_properties<db::PolygonRef> > > &results, const db::LocalProcessorBase *proc) const
908+
{
909+
tl_assert (results.size () == 1);
910+
auto &result = results.front ();
911+
912+
db::EdgeProcessor ep;
913+
914+
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
915+
916+
const auto &subject = interactions.subject_shape (i->first);
917+
db::properties_id_type prop_id = subject.properties_id ();
918+
919+
if (i->second.empty ()) {
920+
921+
result.insert (subject);
922+
923+
} else {
924+
925+
ep.clear ();
926+
927+
const auto &subject = interactions.subject_shape (i->first);
928+
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
929+
ep.insert (*e, 0);
930+
}
931+
932+
size_t p2 = 1;
933+
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
934+
const auto &intruder = interactions.intruder_shape (*ii);
935+
for (auto e = intruder.second.begin_edge (); ! e.at_end(); ++e) {
936+
ep.insert (*e, p2);
937+
}
938+
p2 += 2;
939+
}
940+
941+
std::unordered_set<db::object_with_properties<db::PolygonRef> > result1;
942+
943+
db::BooleanOp op (db::BooleanOp::ANotB);
944+
db::polygon_ref_generator_with_properties<db::object_with_properties<db::PolygonRef> > pr (layout, result1, prop_id);
945+
db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ());
946+
db::PolygonGenerator pg (splitter, true, true);
947+
ep.set_base_verbosity (50);
948+
ep.process (pg, op);
949+
950+
if (result1.empty ()) {
951+
952+
// shortcut: nothing to do
953+
954+
} else if (m_complexity_factor < 0.0) {
955+
956+
// no complexity limit
957+
result.insert (result1.begin (), result1.end ());
958+
959+
} else if (m_complexity_factor == 0.0) {
960+
961+
// only remove shape if it is really entirely covered in this case
962+
result.insert (subject);
963+
964+
} else {
965+
966+
size_t vertices_before = subject.vertices ();
967+
size_t vertices_after = 0;
968+
for (auto r = result1.begin (); r != result1.end (); ++r) {
969+
vertices_after += r->vertices ();
970+
}
971+
972+
if (floor (0.5 + m_complexity_factor * vertices_before) >= vertices_after) {
973+
result.insert (result1.begin (), result1.end ());
974+
} else {
975+
result.insert (subject);
976+
}
977+
978+
}
979+
980+
}
981+
982+
}
983+
}
984+
985+
private:
986+
double m_complexity_factor;
987+
};
988+
989+
}
990+
991+
RegionDelegate *
992+
DeepRegion::peel (double complexity_factor) const
993+
{
994+
if (empty ()) {
995+
// we can return "this", as this method is only intended for in-place execution inside Region
996+
return const_cast<DeepRegion *> (this);
997+
}
998+
999+
DeepLayer dl_out (deep_layer ().derived ());
1000+
1001+
PushHierLocalOperationWithProperties op (complexity_factor);
1002+
1003+
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), deep_layer ().breakout_cells ());
1004+
configure_proc (proc);
1005+
proc.set_threads (deep_layer ().store ()->threads ());
1006+
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
1007+
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
1008+
1009+
// with this setting, only top-down interactions are considered
1010+
proc.set_top_down (true);
1011+
1012+
proc.run (&op, deep_layer ().layer (), deep_layer ().layer (), dl_out.layer ());
1013+
1014+
return new DeepRegion (dl_out);
1015+
}
1016+
8831017
RegionDelegate *
8841018
DeepRegion::and_with (const Region &other, PropertyConstraint property_constraint) const
8851019
{

src/db/db/dbDeepRegion.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class DB_PUBLIC DeepRegion
140140
virtual RegionDelegate *sized_inside (const Region &inside, bool outside, coord_type d, int steps, unsigned int mode) const;
141141
virtual RegionDelegate *sized_inside (const Region &inside, bool outside, coord_type dx, coord_type dy, int steps, unsigned int mode) const;
142142

143+
virtual RegionDelegate *peel (double complexity_factor) const;
144+
143145
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
144146

145147
virtual RegionDelegate *nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Variant &net_prop_name, const std::vector<const Net *> *nets) const;

src/db/db/dbEmptyRegion.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class DB_PUBLIC EmptyRegion
111111
virtual RegionDelegate *add_in_place (const Region &other);
112112
virtual RegionDelegate *add (const Region &other) const;
113113

114+
virtual RegionDelegate *peel (double /*complexity_factor*/) const { return new EmptyRegion (); }
115+
114116
virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); }
115117
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
116118
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }

src/db/db/dbHierProcessor.cc

Lines changed: 64 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ local_processor_result_computation_task<TS, TI, TR>::perform ()
744744
// LocalProcessorBase implementation
745745

746746
LocalProcessorBase::LocalProcessorBase ()
747-
: m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_boolean_core (false),
747+
: m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_top_down (false), m_boolean_core (false),
748748
m_base_verbosity (30), mp_vars (0), mp_current_cell (0)
749749
{
750750
// .. nothing yet ..
@@ -1034,84 +1034,90 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
10341034
}
10351035
}
10361036

1037-
// TODO: can we shortcut this if interactions is empty?
1038-
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
1037+
// in top-down mode we are not interested in cell-to-cell interactions, nor shape-to-instance interactions
1038+
// except local ones (shape-to-child cells), hence we skip this part
1039+
if (! top_down ()) {
10391040

1040-
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
1041+
// TODO: can we shortcut this if interactions is empty?
1042+
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
10411043

1042-
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
1043-
interaction_registration_inst2inst<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions);
1044+
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
10441045

1045-
unsigned int id = 0;
1046+
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
1047+
interaction_registration_inst2inst<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions);
10461048

1047-
if (subject_cell == intruder_cell) {
1049+
unsigned int id = 0;
10481050

1049-
// Use the same id's for same instances - this way we can easily detect same instances
1050-
// and don't make them self-interacting
1051+
if (subject_cell == intruder_cell) {
10511052

1052-
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
1053-
unsigned int iid = ++id;
1054-
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
1055-
scanner.insert1 (&i->cell_inst (), iid);
1056-
}
1057-
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
1058-
scanner.insert2 (&i->cell_inst (), iid);
1053+
// Use the same id's for same instances - this way we can easily detect same instances
1054+
// and don't make them self-interacting
1055+
1056+
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
1057+
unsigned int iid = ++id;
1058+
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
1059+
scanner.insert1 (&i->cell_inst (), iid);
1060+
}
1061+
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
1062+
scanner.insert2 (&i->cell_inst (), iid);
1063+
}
10591064
}
1060-
}
10611065

1062-
} else {
1066+
} else {
10631067

1064-
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
1065-
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
1066-
scanner.insert1 (&i->cell_inst (), ++id);
1068+
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
1069+
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
1070+
scanner.insert1 (&i->cell_inst (), ++id);
1071+
}
10671072
}
1068-
}
10691073

1070-
if (intruder_cell) {
1071-
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
1072-
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
1073-
scanner.insert2 (&i->cell_inst (), ++id);
1074+
if (intruder_cell) {
1075+
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
1076+
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
1077+
scanner.insert2 (&i->cell_inst (), ++id);
1078+
}
10741079
}
10751080
}
1076-
}
10771081

1078-
}
1082+
}
10791083

1080-
for (std::set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
1081-
if (! inst_bci (*i).empty ()) {
1082-
scanner.insert2 (i.operator-> (), ++id);
1084+
for (std::set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
1085+
if (! inst_bci (*i).empty ()) {
1086+
scanner.insert2 (i.operator-> (), ++id);
1087+
}
10831088
}
1084-
}
10851089

1086-
scanner.process (rec, dist, inst_bcs, inst_bci);
1090+
scanner.process (rec, dist, inst_bcs, inst_bci);
10871091

1088-
}
1092+
}
10891093

1090-
if (! intruders.second.empty () || ! intruder_shapes.empty ()) {
1094+
if (! intruders.second.empty () || ! intruder_shapes.empty ()) {
10911095

1092-
db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
1093-
db::addressable_object_from_shape<TI> heap;
1094-
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
1096+
db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
1097+
db::addressable_object_from_shape<TI> heap;
1098+
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
10951099

1096-
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
1097-
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
1098-
scanner.insert1 (&i->cell_inst (), 0);
1100+
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
1101+
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
1102+
scanner.insert1 (&i->cell_inst (), 0);
1103+
}
10991104
}
1100-
}
11011105

1102-
for (typename std::map<unsigned int, std::set<TI> >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) {
1103-
for (typename std::set<TI>::const_iterator i = il->second.begin (); i != il->second.end (); ++i) {
1104-
scanner.insert2 (i.operator-> (), il->first);
1106+
for (typename std::map<unsigned int, std::set<TI> >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) {
1107+
for (typename std::set<TI>::const_iterator i = il->second.begin (); i != il->second.end (); ++i) {
1108+
scanner.insert2 (i.operator-> (), il->first);
1109+
}
11051110
}
1106-
}
11071111

1108-
for (std::map<unsigned int, const db::Shapes *>::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) {
1109-
for (db::Shapes::shape_iterator i = im->second->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
1110-
scanner.insert2 (heap (*i), im->first);
1112+
for (std::map<unsigned int, const db::Shapes *>::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) {
1113+
for (db::Shapes::shape_iterator i = im->second->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
1114+
scanner.insert2 (heap (*i), im->first);
1115+
}
11111116
}
1112-
}
11131117

1114-
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
1118+
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
1119+
1120+
}
11151121

11161122
}
11171123

@@ -1417,14 +1423,14 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
14171423
}
14181424
}
14191425

1420-
// local shapes vs. child cell
1421-
14221426
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, ail);
14231427

14241428
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (*il);
14251429
static std::set<TI> empty_intruders;
14261430

1427-
if (! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
1431+
// local shapes vs. local shapes
1432+
1433+
if (! top_down () && ! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
14281434

14291435
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
14301436

@@ -1439,6 +1445,8 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
14391445

14401446
}
14411447

1448+
// local shapes vs. child cells
1449+
14421450
if (! subject_shapes->empty () && ! ((! intruder_cell || intruder_cell->begin ().at_end ()) && intruders.first.empty ())) {
14431451

14441452
db::box_scanner2<TS, int, db::CellInstArray, int> scanner;
@@ -1452,7 +1460,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
14521460

14531461
unsigned int inst_id = 0;
14541462

1455-
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
1463+
if (! top_down () && subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
14561464

14571465
// Same cell, same layer -> no shape to child instance interactions because this will be taken care of
14581466
// by the instances themselves (and their intruders). This also means, we prefer to deal with

src/db/db/dbHierProcessor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,16 @@ class DB_PUBLIC LocalProcessorBase
465465
return m_nthreads;
466466
}
467467

468+
void set_top_down (bool f)
469+
{
470+
m_top_down = f;
471+
}
472+
473+
bool top_down () const
474+
{
475+
return m_top_down;
476+
}
477+
468478
void set_max_vertex_count (size_t max_vertex_count)
469479
{
470480
m_max_vertex_count = max_vertex_count;
@@ -525,6 +535,7 @@ class DB_PUBLIC LocalProcessorBase
525535
unsigned int m_nthreads;
526536
size_t m_max_vertex_count;
527537
double m_area_ratio;
538+
bool m_top_down;
528539
bool m_boolean_core;
529540
int m_base_verbosity;
530541
const db::VariantsCollectorBase *mp_vars;

0 commit comments

Comments
 (0)