From 189ba72666a3462f8471e917fdbc19ac726c34a8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 23 Jul 2026 22:26:57 +0200 Subject: [PATCH] Performance enhancements for two-layer DRC checks The main optimization was introducing "distance overrides" in the local processor. That means, the primary shapes mixed in for local merge are collected with distance 0, while the shapes from the other layer are collected with the check distance. Some more optimizations involve early shortcuts in some cases. --- src/db/db/dbHierProcessor.cc | 83 ++++++++++++++++++++++------ src/db/db/dbHierProcessor.h | 7 ++- src/db/db/dbLocalOperation.h | 8 +++ src/db/db/dbRegionLocalOperations.cc | 33 +++++++++++ src/db/db/dbRegionLocalOperations.h | 1 + 5 files changed, 111 insertions(+), 21 deletions(-) diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 26cc7608e..9399cebc2 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -622,21 +622,28 @@ public: typedef typename local_processor_cell_contexts::context_key_type interactions_value_type; typedef std::unordered_map, interactions_value_type> interactions_type; - interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, interactions_type *result) - : mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result), m_rt (subject_layout) + interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, const std::map &override_distance, interactions_type *result) + : mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), m_override_distance (override_distance), mp_result (result), m_rt (subject_layout) { // nothing yet .. } void add (const db::CellInstArray *inst, unsigned int, const TI *ref, unsigned int layer) { - collect_instance_shape_interactions (inst, layer, *ref, m_dist); + db::Coord d = m_dist; + auto od = m_override_distance.find (layer); + if (od != m_override_distance.end ()) { + d = std::min (d, od->second); + } + + collect_instance_shape_interactions (inst, layer, *ref, d); } private: db::Layout *mp_subject_layout; unsigned int m_subject_layer; db::Coord m_dist; + std::map m_override_distance; interactions_type *mp_result; db::shape_reference_translator_with_trans m_rt; @@ -681,11 +688,11 @@ private: // LocalProcessorContextComputationTask implementation template -local_processor_context_computation_task::local_processor_context_computation_task (const local_processor *proc, local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist) +local_processor_context_computation_task::local_processor_context_computation_task (const local_processor *proc, local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist, const std::map &override_distance) : tl::Task (), mp_proc (proc), mp_contexts (&contexts), mp_parent_context (parent_context), mp_subject_parent (subject_parent), mp_subject_cell (subject_cell), m_subject_cell_inst (subject_cell_inst), - mp_intruder_cell (intruder_cell), m_dist (dist) + mp_intruder_cell (intruder_cell), m_dist (dist), m_override_distance (override_distance) { // This is quick, but will take away the intruders from the caller m_intruders.swap (intruders); @@ -695,7 +702,7 @@ template void local_processor_context_computation_task::perform () { - mp_proc->compute_contexts (*mp_contexts, mp_parent_context, mp_subject_parent, mp_subject_cell, m_subject_cell_inst, mp_intruder_cell, m_intruders, m_dist); + mp_proc->compute_contexts (*mp_contexts, mp_parent_context, mp_subject_parent, mp_subject_cell, m_subject_cell_inst, mp_intruder_cell, m_intruders, m_dist, m_override_distance); } // --------------------------------------------------------------------------------------------- @@ -900,8 +907,18 @@ void local_processor::compute_contexts (local_processor_contextsoverride_distance (); + std::map override_distance; + for (auto il = intruder_layers.begin (); il != intruder_layers.end (); ++il) { + auto o = od.find ((unsigned int) (il - intruder_layers.begin ())); + if (o != od.end ()) { + override_distance [*il] = o->second; + } + } + typename local_processor_cell_contexts::context_key_type intruders; - issue_compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist ()); + issue_compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist (), override_distance); if (mp_cc_job.get ()) { mp_cc_job->start (); @@ -922,14 +939,15 @@ void local_processor::issue_compute_contexts (local_processor_contex const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, - db::Coord dist) const + db::Coord dist, + const std::map &override_distance) const { bool is_small_job = subject_cell->begin ().at_end (); if (! is_small_job && mp_cc_job.get ()) { - mp_cc_job->schedule (new local_processor_context_computation_task (this, contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist)); + mp_cc_job->schedule (new local_processor_context_computation_task (this, contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist, override_distance)); } else { - compute_contexts (contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist); + compute_contexts (contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist, override_distance); } } @@ -941,7 +959,8 @@ void local_processor::compute_contexts (local_processor_contexts::context_key_type &intruders, - db::Coord dist_top) const + db::Coord dist_top, + const std::map &override_distance) const { CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts) @@ -1041,10 +1060,16 @@ void local_processor::compute_contexts (local_processor_contexts::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) { + auto od = override_distance.find (*il); + db::Coord d = dist; + if (od != override_distance.end ()) { + d = std::min (d, od->second); + } + db::box_convert inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il)); db::box_scanner2 scanner; - interaction_registration_inst2inst rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions); + interaction_registration_inst2inst rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), d, &interactions); unsigned int id = 0; @@ -1095,7 +1120,7 @@ void local_processor::compute_contexts (local_processor_contexts scanner; db::addressable_object_from_shape heap; - interaction_registration_inst2shape rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions); + interaction_registration_inst2shape rec (mp_subject_layout, contexts.subject_layer (), dist, override_distance, &interactions); for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) { @@ -1127,7 +1152,7 @@ void local_processor::compute_contexts (local_processor_contextscell (i->first.first); db::Cell *intruder_child_cell = (subject_cell == intruder_cell ? subject_child_cell : 0); - issue_compute_contexts (contexts, cell_context, subject_cell, subject_child_cell, i->first.second, intruder_child_cell, i->second, dist); + issue_compute_contexts (contexts, cell_context, subject_cell, subject_child_cell, i->first.second, intruder_child_cell, i->second, dist, override_distance); } @@ -1386,7 +1411,8 @@ template void local_processor::compute_local_cell (const db::local_processor_contexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation *op, const typename local_processor_cell_contexts::context_key_type &intruders, std::vector > &result) const { - db::Coord dist = dist_for_cell (subject_cell->cell_index (), op->dist ()); + auto override_distance = op->override_distance (); + db::Coord dist_global = dist_for_cell (subject_cell->cell_index (), op->dist ()); const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ()); db::shape_to_object s2o; @@ -1412,6 +1438,13 @@ local_processor::compute_local_cell (const db::local_processor_conte unsigned int il_index = 0; for (std::vector::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il, ++il_index) { + // compute effective distance + db::Coord dist = dist_global; + auto od = override_distance.find (il_index); + if (od != override_distance.end ()) { + dist = std::min (dist, dist_for_cell (subject_cell->cell_index (), od->second)); + } + unsigned int ail = contexts.actual_intruder_layer (*il); bool foreign = contexts.is_foreign (*il); @@ -1633,15 +1666,16 @@ local_processor::run_flat (const generic_shape_iterator &subject // build the subjects in the intruders list - db::Coord dist = op->dist (); + db::Coord dist_global = op->dist (); + auto override_distance = op->override_distance (); - db::Box subjects_box = safe_box_enlarged (subjects.bbox (), dist, dist); + db::Box subjects_box = safe_box_enlarged (subjects.bbox (), dist_global, dist_global); db::Box intruders_box; for (typename std::vector >::const_iterator il = intruders.begin (); il != intruders.end (); ++il) { intruders_box += il->bbox (); } - intruders_box = safe_box_enlarged (intruders_box, dist, dist); + intruders_box = safe_box_enlarged (intruders_box, dist_global, dist_global); db::Box common_box = intruders_box & subjects_box; if (common_box.empty () || common_box.width () == 0 || common_box.height () == 0) { @@ -1670,6 +1704,12 @@ local_processor::run_flat (const generic_shape_iterator &subject bool ff = foreign.size () > il_index && foreign [il_index]; + db::Coord dist = dist_global; + auto od = override_distance.find (il_index); + if (od != override_distance.end ()) { + dist = std::min (dist, od->second); + } + if (*il == subjects && ! ff) { interaction_registration_shape1_scanner_combo scanner (&interactions, il_index, report_progress (), scan_description); @@ -1736,6 +1776,12 @@ local_processor::run_flat (const generic_shape_iterator &subject bool ff = foreign.size () > il_index && foreign [il_index]; + db::Coord dist = dist_global; + auto od = override_distance.find (il_index); + if (od != override_distance.end ()) { + dist = std::min (dist, od->second); + } + if (*il == subjects && ! ff) { interaction_registration_shape1_scanner_combo scanner (&interactions, il_index, report_progress (), scan_description); @@ -1789,6 +1835,7 @@ local_processor::run_flat (const generic_shape_iterator &subject } } + } } diff --git a/src/db/db/dbHierProcessor.h b/src/db/db/dbHierProcessor.h index 8d446641a..a2a3d8714 100644 --- a/src/db/db/dbHierProcessor.h +++ b/src/db/db/dbHierProcessor.h @@ -359,7 +359,7 @@ class DB_PUBLIC local_processor_context_computation_task : public tl::Task { public: - local_processor_context_computation_task (const local_processor *proc, local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist); + local_processor_context_computation_task (const local_processor *proc, local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist, const std::map &override_distance); void perform (); private: @@ -372,6 +372,7 @@ private: const db::Cell *mp_intruder_cell; typename local_processor_cell_contexts::context_key_type m_intruders; db::Coord m_dist; + std::map m_override_distance; }; template @@ -578,8 +579,8 @@ private: void next () const; size_t get_progress () const; - void compute_contexts (db::local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist) const; - void issue_compute_contexts (db::local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist) const; + void compute_contexts (db::local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist, const std::map &override_distance) const; + void issue_compute_contexts (db::local_processor_contexts &contexts, db::local_processor_cell_context *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts::context_key_type &intruders, db::Coord dist, const std::map &override_distance) const; void compute_local_cell (const db::local_processor_contexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation *op, const typename local_processor_cell_contexts::context_key_type &intruders, std::vector > &result) const; bool subject_cell_is_breakout (db::cell_index_type ci) const diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index 5ce9c2db3..8f8651865 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -118,6 +118,14 @@ public: */ virtual db::Coord dist () const { return 0; } + /** + * @brief Gets a override distance for a specific input layer + * The input layers are numbered from 0 to n-1, where n is the allowed number of intruder layers + * The override distance is used insted of the global distance ("dist()") for the given + * input layer. The override distance cannot be bigger than the global distance. + */ + virtual std::map override_distance () const { return std::map (); } + /** * @brief Gets the cell variant reducer that indicates whether to build cell variants and which */ diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index f60484eb6..82c17c80e 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -813,8 +813,27 @@ check_local_operation::do_compute_local (db::Layout *layout, db::Cell *s unsigned int primary_intruder_layer = check_local_operation_base::m_has_other ? 1 : 0; + // in the case of a two-layer check, return if there is no second layer shape + if (check_local_operation_base::m_has_other) { + + bool any = false; + for (auto i = interactions.begin (); i != interactions.end () && ! any; ++i) { + for (auto ii = i->second.begin (); ii != i->second.end () && ! any; ++ii) { + const auto &is = interactions.intruder_shape (*ii); + any = (is.first != primary_intruder_layer); + } + } + + if (! any) { + return; + } + + } + 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) { const auto &is = interactions.intruder_shape (*ii); if (is.first == primary_intruder_layer) { @@ -823,6 +842,7 @@ check_local_operation::do_compute_local (db::Layout *layout, db::Cell *s intruders.insert (&is.second); } } + } tl_assert (results.size () == 1); @@ -863,6 +883,19 @@ check_local_operation::do_compute_local (db::Layout *layout, db::Cell *s } } +template +std::map +check_local_operation::override_distance () const +{ + // makes sure, the "foreign"-type pseudo-intruder used for merging only + // does not use the full search range, but only "touching". + std::map od; + if (check_local_operation_base::m_has_other) { + od.insert (std::make_pair (1, 0)); + } + return od; +} + template db::Coord check_local_operation::dist () const diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h index 1650d6fb0..cafe7419e 100644 --- a/src/db/db/dbRegionLocalOperations.h +++ b/src/db/db/dbRegionLocalOperations.h @@ -207,6 +207,7 @@ public: check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options); virtual db::Coord dist () const; + virtual std::map override_distance () const; virtual OnEmptyIntruderHint on_empty_intruder_hint () const; virtual bool requests_single_subjects () const { return true; } virtual std::string description () const;