mirror of https://github.com/KLayout/klayout.git
WIP: trying performance improvement of two-layer DRC checks (do merge internally instead of before)
This commit is contained in:
parent
b51187bf7c
commit
a75f1d77e3
|
|
@ -1184,13 +1184,8 @@ AsIfFlatRegion::width_check (db::Coord d, const RegionCheckOptions &options) con
|
|||
EdgePairsDelegate *
|
||||
AsIfFlatRegion::space_or_isolated_check (db::Coord d, const RegionCheckOptions &options, bool isolated) const
|
||||
{
|
||||
if (options.opposite_filter != NoOppositeFilter || options.rect_filter != NoRectFilter || options.shielded) {
|
||||
// NOTE: we have to use the "foreign" scheme with a filter because only this scheme
|
||||
// guarantees that all subject shapes are visited.
|
||||
return run_check (db::SpaceRelation, isolated, foreign_regionptr (), d, options);
|
||||
} else {
|
||||
return run_check (db::SpaceRelation, isolated, subject_regionptr (), d, options);
|
||||
}
|
||||
// NOTE: we have to use "foreign" to make sure every subject sees neighboring subjects
|
||||
return run_check (db::SpaceRelation, isolated, foreign_regionptr (), d, options);
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
|
|
@ -1238,12 +1233,14 @@ AsIfFlatRegion::inside_check (const Region &other, db::Coord d, const RegionChec
|
|||
EdgePairsDelegate *
|
||||
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
|
||||
{
|
||||
bool has_other = other && other != subject_regionptr () && other != foreign_regionptr ();
|
||||
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (pc_always_different (options.prop_constraint)) {
|
||||
if (! has_other && pc_always_different (options.prop_constraint)) {
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
bool needs_merged_primary = different_polygons || options.needs_merged ();
|
||||
bool needs_merged_primary = (! has_other && different_polygons) || options.needs_merged ();
|
||||
|
||||
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
|
||||
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
|
||||
|
|
@ -1252,15 +1249,18 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
|
||||
std::vector<db::RegionIterator> others;
|
||||
std::vector<bool> foreign;
|
||||
bool has_other = false;
|
||||
bool other_is_merged = true;
|
||||
|
||||
if (other == subject_regionptr () || other == foreign_regionptr ()) {
|
||||
if (! has_other) {
|
||||
|
||||
foreign.push_back (other == foreign_regionptr ());
|
||||
others.push_back (polygons);
|
||||
other_is_merged = primary_is_merged;
|
||||
|
||||
} else {
|
||||
|
||||
foreign.push_back (false);
|
||||
|
||||
if (! other->merged_semantics ()) {
|
||||
others.push_back (other->begin ());
|
||||
other_is_merged = true;
|
||||
|
|
@ -1272,7 +1272,13 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
others.push_back (other->begin ());
|
||||
other_is_merged = other->is_merged ();
|
||||
}
|
||||
has_other = true;
|
||||
|
||||
// adds another intruder section to implement subject merging ("primary_intruders")
|
||||
if (! primary_is_merged) {
|
||||
foreign.push_back (true);
|
||||
others.push_back (polygons);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdgePairs> output (new FlatEdgePairs ());
|
||||
|
|
|
|||
|
|
@ -2368,6 +2368,7 @@ DeepRegion::cop_to_edges (db::CompoundRegionOperationNode &node, db::PropertyCon
|
|||
EdgePairsDelegate *
|
||||
DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
|
||||
{
|
||||
// @@@
|
||||
if (empty ()) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
} else if (other && ! is_subject_regionptr (other) && other->empty () && ! options.negative) {
|
||||
|
|
|
|||
|
|
@ -376,10 +376,10 @@ private:
|
|||
*/
|
||||
template <class TS, class TI>
|
||||
DB_PUBLIC_TEMPLATE
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::set<const TI *> > >
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::set<std::pair<unsigned int, const TI *> > > >
|
||||
separate_interactions_by_properties (const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, db::PropertyConstraint property_constraint)
|
||||
{
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::set<const TI *> > > by_prop_id;
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::set<std::pair<unsigned int, const TI *> > > > by_prop_id;
|
||||
|
||||
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
|
|
@ -387,7 +387,7 @@ separate_interactions_by_properties (const shape_interactions<db::object_with_pr
|
|||
|
||||
db::properties_id_type prop_id = subject.properties_id ();
|
||||
|
||||
std::pair<std::vector<const TS *>, std::set<const TI *> > &s2p = by_prop_id [prop_id];
|
||||
auto &s2p = by_prop_id [prop_id];
|
||||
s2p.first.push_back (&subject);
|
||||
|
||||
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
|
||||
|
|
@ -395,7 +395,7 @@ separate_interactions_by_properties (const shape_interactions<db::object_with_pr
|
|||
const std::pair<unsigned int, db::object_with_properties<TI> > &intruder = interactions.intruder_shape (*ii);
|
||||
|
||||
if (pc_match (property_constraint, prop_id, intruder.second.properties_id ())) {
|
||||
s2p.second.insert (&intruder.second);
|
||||
s2p.second.insert (std::make_pair (intruder.first, &intruder.second));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ check_local_operation_base<TS, TI>::check_local_operation_base (const EdgeRelati
|
|||
|
||||
template <class TS, class TI>
|
||||
void
|
||||
check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cell *subject_cell, const std::vector<const TS *> &subjects, const std::set<const TI *> &intruders, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result, const db::LocalProcessorBase *proc) const
|
||||
check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cell *subject_cell, const std::vector<const TS *> &subjects, const std::set<const TI *> &primary_intruders, const std::set<const TI *> &intruders, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result, const db::LocalProcessorBase *proc) const
|
||||
{
|
||||
// NOTE: the rectangle and opposite filters are unsymmetric
|
||||
bool symmetric_edge_pairs = ! m_has_other && m_options.opposite_filter == db::NoOppositeFilter && m_options.rect_filter == RectFilter::NoRectFilter;
|
||||
|
|
@ -229,7 +229,7 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
db::EdgeProcessor ep;
|
||||
ep.set_base_verbosity (50);
|
||||
|
||||
bool take_all = edge_check.has_negative_edge_output () || intruders.empty ();
|
||||
bool take_all = edge_check.has_negative_edge_output () || (intruders.empty () && primary_intruders.empty ());
|
||||
|
||||
db::Box common_box;
|
||||
bool subjects_are_fully_covered = false;
|
||||
|
|
@ -259,6 +259,14 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
all_intruders_box += intruder_box.enlarged (e);
|
||||
}
|
||||
|
||||
for (auto i = primary_intruders.begin (); i != primary_intruders.end (); ++i) {
|
||||
db::Box intruder_box = db::box_convert<TI> () (**i);
|
||||
if (! subjects_are_fully_covered && (*i)->is_box () && common_box.inside (intruder_box)) {
|
||||
subjects_are_fully_covered = true;
|
||||
}
|
||||
all_intruders_box += intruder_box.enlarged (e);
|
||||
}
|
||||
|
||||
common_box &= all_intruders_box;
|
||||
|
||||
}
|
||||
|
|
@ -269,7 +277,7 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
|
||||
size_t n = 0;
|
||||
|
||||
if (m_is_merged || (subjects.size () == 1 && subjects.front ()->is_box ())) {
|
||||
if (m_is_merged || (subjects.size () == 1 && subjects.front ()->is_box () && primary_intruders.empty ())) {
|
||||
|
||||
for (auto i = subjects.begin (); i != subjects.end (); ++i) {
|
||||
if (! take_all) {
|
||||
|
|
@ -280,9 +288,10 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
n += 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (primary_intruders.empty ()) {
|
||||
|
||||
// merge needed for the subject shapes
|
||||
// Here we don't have other subjects to consider. This is the simple case.
|
||||
|
||||
ep.clear ();
|
||||
size_t nn = 0;
|
||||
|
|
@ -310,6 +319,79 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
n += 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// merge needed for the subject and primary intruder shapes ("other subjects") - we merge both and then
|
||||
// reclaim original subject edges that are "outer" edges and not covered by other subjects shapes.
|
||||
|
||||
ep.clear ();
|
||||
size_t nn = 0;
|
||||
|
||||
for (auto i = subjects.begin (); i != subjects.end (); ++i) {
|
||||
for (auto e = (*i)->begin_edge (); ! e.at_end (); ++e) {
|
||||
ep.insert (*e, nn);
|
||||
}
|
||||
++nn;
|
||||
}
|
||||
|
||||
for (auto i = primary_intruders.begin (); i != primary_intruders.end (); ++i) {
|
||||
for (auto e = (*i)->begin_edge (); ! e.at_end (); ++e) {
|
||||
ep.insert (*e, nn);
|
||||
}
|
||||
++nn;
|
||||
}
|
||||
|
||||
std::vector<typename TS::edge_type> edges;
|
||||
|
||||
db::EdgeContainer ee (edges);
|
||||
db::SimpleMerge op (1 /*wc>0*/);
|
||||
ep.process (ee, op);
|
||||
ep.clear ();
|
||||
|
||||
std::vector<typename TS::edge_type> subject_edges;
|
||||
|
||||
size_t sz = 0;
|
||||
for (auto i = subjects.begin (); i != subjects.end (); ++i) {
|
||||
sz += (*i)->vertices ();
|
||||
}
|
||||
|
||||
subject_edges.reserve (sz);
|
||||
|
||||
for (auto i = subjects.begin (); i != subjects.end (); ++i) {
|
||||
for (auto e = (*i)->begin_edge (); ! e.at_end (); ++e) {
|
||||
subject_edges.push_back (*e);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<typename TI::edge_type> partial_edges;
|
||||
|
||||
EdgeBooleanClusterCollector<std::set<typename TI::edge_type> > cluster_collector (&partial_edges, db::EdgeAnd);
|
||||
|
||||
db::box_scanner<typename TI::edge_type, size_t> scanner;
|
||||
scanner.reserve (edges.size () + subject_edges.size ());
|
||||
|
||||
for (auto i = edges.begin (); i != edges.end (); ++i) {
|
||||
if (! i->is_degenerate ()) {
|
||||
scanner.insert (i.operator-> (), 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = subject_edges.begin (); i != subject_edges.end (); ++i) {
|
||||
if (! i->is_degenerate ()) {
|
||||
scanner.insert (i.operator-> (), 1);
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (cluster_collector, 1, db::box_convert<typename TI::edge_type> ());
|
||||
|
||||
for (auto e = partial_edges.begin (); e != partial_edges.end (); ++e) {
|
||||
if (! take_all) {
|
||||
poly_check.enter (*e, 0, common_box);
|
||||
} else {
|
||||
poly_check.enter (*e, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// merge the intruders to remove inner edges
|
||||
|
|
@ -384,11 +466,11 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
|
||||
} else {
|
||||
|
||||
if (m_is_merged || (subjects.size () == 1 && intruders.empty () && subjects.front ()->is_box ())) {
|
||||
if (m_is_merged || (subjects.size () == 1 && primary_intruders.empty () && subjects.front ()->is_box ())) {
|
||||
|
||||
// no merge required
|
||||
|
||||
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
|
||||
// NOTE: we need to eliminate identical shapes from primary intruders and subjects because those will shield
|
||||
|
||||
size_t n = 0;
|
||||
std::unordered_set<TI> subjects_hash;
|
||||
|
|
@ -406,7 +488,7 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
|
||||
n = 1;
|
||||
|
||||
for (auto i = intruders.begin (); i != intruders.end (); ++i) {
|
||||
for (auto i = primary_intruders.begin (); i != primary_intruders.end (); ++i) {
|
||||
if (subjects_hash.find (**i) == subjects_hash.end ()) {
|
||||
if (! take_all) {
|
||||
poly_check.enter (**i, n, common_box);
|
||||
|
|
@ -416,9 +498,9 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
}
|
||||
}
|
||||
|
||||
} else if (intruders.empty ()) {
|
||||
} else if (primary_intruders.empty ()) {
|
||||
|
||||
// merge needed for the subject shapes - no intruders present so this is the simple case
|
||||
// merge needed for the subject shapes - no primary intruders ("other subjects") present so this is the simple case
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
|
|
@ -451,7 +533,7 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
|
||||
} else {
|
||||
|
||||
// merge needed for the subject and intruder shapes - we merge both and then
|
||||
// merge needed for the subject and primary intruder shapes ("other subjects") - we merge both and then
|
||||
// separate edges into those from the subject and those from intruder shapes.
|
||||
|
||||
ep.clear ();
|
||||
|
|
@ -464,7 +546,7 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
|
|||
++nn;
|
||||
}
|
||||
|
||||
for (auto i = intruders.begin (); i != intruders.end (); ++i) {
|
||||
for (auto i = primary_intruders.begin (); i != primary_intruders.end (); ++i) {
|
||||
for (auto e = (*i)->begin_edge (); ! e.at_end (); ++e) {
|
||||
ep.insert (*e, nn);
|
||||
}
|
||||
|
|
@ -727,11 +809,19 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, db::Cell *s
|
|||
subjects.reserve (interactions.size ());
|
||||
|
||||
std::set<const TI *> intruders;
|
||||
std::set<const TI *> primary_intruders;
|
||||
|
||||
unsigned int primary_intruder_layer = check_local_operation_base<TS, TI>::m_has_other ? 1 : 0;
|
||||
|
||||
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
subjects.push_back (&interactions.subject_shape (i->first));
|
||||
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
|
||||
intruders.insert (&interactions.intruder_shape (*ii).second);
|
||||
const auto &is = interactions.intruder_shape (*ii);
|
||||
if (is.first == primary_intruder_layer) {
|
||||
primary_intruders.insert (&is.second);
|
||||
} else {
|
||||
intruders.insert (&is.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -740,7 +830,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, db::Cell *s
|
|||
std::unordered_set<db::EdgePair> result, intra_polygon_result;
|
||||
|
||||
// perform the basic check
|
||||
check_local_operation_base<TS, TI>::compute_results (layout, subject_cell, subjects, intruders, result, intra_polygon_result, proc);
|
||||
check_local_operation_base<TS, TI>::compute_results (layout, subject_cell, subjects, primary_intruders, intruders, result, intra_polygon_result, proc);
|
||||
|
||||
// detect and remove parts of the result which have or do not have results "opposite"
|
||||
// ("opposite" is defined by the projection of edges "through" the subject shape)
|
||||
|
|
@ -816,6 +906,8 @@ check_local_operation_with_properties<TS, TI>::do_compute_local (db::Layout *lay
|
|||
{
|
||||
tl_assert (results.size () == 1);
|
||||
|
||||
unsigned int primary_intruder_layer = check_local_operation_base<TS, TI>::m_has_other ? 1 : 0;
|
||||
|
||||
auto by_prop_id = separate_interactions_by_properties (interactions, check_local_operation_base<TS, TI>::m_options.prop_constraint);
|
||||
|
||||
for (auto s2p = by_prop_id.begin (); s2p != by_prop_id.end (); ++s2p) {
|
||||
|
|
@ -823,10 +915,18 @@ check_local_operation_with_properties<TS, TI>::do_compute_local (db::Layout *lay
|
|||
std::unordered_set<db::EdgePair> result, intra_polygon_result;
|
||||
|
||||
const std::vector<const TS *> &subjects = s2p->second.first;
|
||||
const std::set<const TI *> &intruders = s2p->second.second;
|
||||
|
||||
std::set<const TI *> intruders, primary_intruders;
|
||||
for (auto i = s2p->second.second.begin (); i != s2p->second.second.end (); ++i) {
|
||||
if (i->first == primary_intruder_layer) {
|
||||
primary_intruders.insert (i->second);
|
||||
} else {
|
||||
intruders.insert (i->second);
|
||||
}
|
||||
}
|
||||
|
||||
// perform the basic check
|
||||
check_local_operation_base<TS, TI>::compute_results (layout, subject_cell, subjects, intruders, result, intra_polygon_result, proc);
|
||||
check_local_operation_base<TS, TI>::compute_results (layout, subject_cell, subjects, primary_intruders, intruders, result, intra_polygon_result, proc);
|
||||
|
||||
// detect and remove parts of the result which have or do not have results "opposite"
|
||||
// ("opposite" is defined by the projection of edges "through" the subject shape)
|
||||
|
|
@ -2295,6 +2395,7 @@ PolygonToEdgeLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell
|
|||
|
||||
} else {
|
||||
|
||||
// @@@ that's not correct, isn't it?
|
||||
// With intruders: to compute our local contribution we take the edges without and with intruders
|
||||
// and deliver what is in both sets
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ protected:
|
|||
bool m_other_is_merged;
|
||||
db::RegionCheckOptions m_options;
|
||||
|
||||
void compute_results (db::Layout *layout, db::Cell *subject_cell, const std::vector<const TS *> &subjects, const std::set<const TI *> &intruders, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result, const LocalProcessorBase *proc) const;
|
||||
void compute_results (db::Layout *layout, db::Cell *subject_cell, const std::vector<const TS *> &subjects, const std::set<const TI *> &primary_intruders, const std::set<const TI *> &intruders, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result, const LocalProcessorBase *proc) const;
|
||||
void apply_opposite_filter (const std::vector<const TS *> &subjects, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result) const;
|
||||
void apply_rectangle_filter (const std::vector<const TS *> &subjects, std::unordered_set<db::EdgePair> &result) const;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue