diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index b3d832e2f..5dd824c64 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -38,6 +38,7 @@ #include "tlException.h" #include "tlVector.h" #include "tlString.h" +#include "tlThreads.h" #include "gsi.h" #include @@ -572,6 +573,15 @@ public: return m_properties_repository; } + /** + * @brief Gets the lock for the layout object + * This is a generic lock that can be used to lock modifications against multiple threads. + */ + tl::Mutex &lock () + { + return m_lock; + } + /** * @brief Collect memory statistics */ @@ -1630,6 +1640,7 @@ private: int m_waste_layer; bool m_editable; meta_info m_meta_info; + tl::Mutex m_lock; /** * @brief Sort the cells topologically diff --git a/src/gsi/gsi/gsiDeclTl.cc b/src/gsi/gsi/gsiDeclTl.cc index be1014d2b..dfcee4871 100644 --- a/src/gsi/gsi/gsiDeclTl.cc +++ b/src/gsi/gsi/gsiDeclTl.cc @@ -152,7 +152,7 @@ namespace gsi static std::string timer_to_s (const tl::Timer *timer) { - return tl::sprintf ("%.12gs (user), %.12gs (kernel)", timer->sec_user (), timer->sec_sys ()); + return tl::sprintf ("%.12gs (sys), %.12gs (user), %.12gs (wall)", timer->sec_sys (), timer->sec_user (), timer->sec_wall ()); } Class decl_Timer ("tl", "Timer", @@ -162,7 +162,11 @@ Class decl_Timer ("tl", "Timer", gsi::method ("sys", &tl::Timer::sec_sys, "@brief Returns the elapsed CPU time in kernel mode from start to stop in seconds\n" ) + - gsi::method_ext ("to_s", &timer_to_s, + gsi::method ("wall", &tl::Timer::sec_wall, + "@brief Returns the elapsed real time from start to stop in seconds\n" + "This method has been introduced in version 0.26." + ) + + gsi::method_ext ("to_s", &timer_to_s, "@brief Produces a string with the currently elapsed times\n" ) + gsi::method ("start", &tl::Timer::start, diff --git a/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc b/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc index 806a3c8fd..faf06d33e 100644 --- a/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc +++ b/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc @@ -51,6 +51,7 @@ public: Ref operator() (const Ref &ref) const { + tl::MutexLocker locker (&mp_layout->lock ()); shape_type sh = ref.obj ().transformed (ref.trans ()); return Ref (sh, mp_layout->shape_repository ()); } @@ -58,6 +59,7 @@ public: template Ref operator() (const Ref &ref, const Trans &tr) const { + tl::MutexLocker locker (&mp_layout->lock ()); shape_type sh = ref.obj ().transformed (tr * Trans (ref.trans ())); return Ref (sh, mp_layout->shape_repository ()); } @@ -131,7 +133,7 @@ LocalProcessorCellContexts::create (const key_type &intruders) } void -LocalProcessorCellContexts::compute_results (LocalProcessorContexts &contexts, db::Cell *cell, const LocalOperation *op, unsigned int output_layer, LocalProcessor *proc) +LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &contexts, db::Cell *cell, const LocalOperation *op, unsigned int output_layer, const LocalProcessor *proc) { bool first = true; std::set common; @@ -148,17 +150,27 @@ LocalProcessorCellContexts::compute_results (LocalProcessorContexts &contexts, d if (first) { - common = c->second.propagated (); + { + tl::MutexLocker locker (&contexts.lock ()); + common = c->second.propagated (); + } + proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, c->first, common); first = false; } else { - std::set res = c->second.propagated (); + std::set res; + { + tl::MutexLocker locker (&contexts.lock ()); + res = c->second.propagated (); + } + proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, c->first, res); if (common.empty ()) { + tl::MutexLocker locker (&contexts.lock ()); c->second.propagate (res); } else if (res != common) { @@ -173,6 +185,7 @@ LocalProcessorCellContexts::compute_results (LocalProcessorContexts &contexts, d common.swap (new_common); for (std::map::iterator cc = m_contexts.begin (); cc != c; ++cc) { + tl::MutexLocker locker (&contexts.lock ()); cc->second.propagate (lost); } @@ -180,7 +193,11 @@ LocalProcessorCellContexts::compute_results (LocalProcessorContexts &contexts, d std::set gained; std::set_difference (res.begin (), res.end (), common.begin (), common.end (), std::inserter (gained, gained.end ())); - c->second.propagate (gained); + + { + tl::MutexLocker locker (&contexts.lock ()); + c->second.propagate (gained); + } } @@ -275,7 +292,7 @@ public: if (mp_layout) { // In order to guarantee the refs come from the subject layout, we'd need to - // rewrite them to the subject layout if required. + // rewrite them if (!mp_result->has_shape_id (id2)) { db::shape_reference_translator rt (mp_layout); mp_result->add_shape (id2, rt (*ref2)); @@ -542,21 +559,70 @@ private: } +// --------------------------------------------------------------------------------------------- +// LocalProcessorContextComputationTask implementation + +LocalProcessorContextComputationTask::LocalProcessorContextComputationTask (const LocalProcessor *proc, LocalProcessorContexts &contexts, db::LocalProcessorCellContext *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, std::pair, std::set > &intruders, db::Coord dist) + : 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) +{ + // This is quick, but will take away the intruders from the caller + m_intruders.swap (intruders); +} + +void +LocalProcessorContextComputationTask::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); +} + +// --------------------------------------------------------------------------------------------- +// LocalProcessorResultComputationTask implementation + +LocalProcessorResultComputationTask::LocalProcessorResultComputationTask (const LocalProcessor *proc, LocalProcessorContexts &contexts, db::Cell *cell, LocalProcessorCellContexts *cell_contexts, const LocalOperation *op, unsigned int output_layer) + : mp_proc (proc), mp_contexts (&contexts), mp_cell (cell), mp_cell_contexts (cell_contexts), mp_op (op), m_output_layer (output_layer) +{ + // .. nothing yet .. +} + +void +LocalProcessorResultComputationTask::perform () +{ + mp_cell_contexts->compute_results (*mp_contexts, mp_cell, mp_op, m_output_layer, mp_proc); + + // erase the contexts we don't need any longer + { + tl::MutexLocker locker (& mp_contexts->lock ()); + mp_contexts->context_map ().erase (mp_cell); + } +} + // --------------------------------------------------------------------------------------------- // LocalProcessor implementation LocalProcessor::LocalProcessor (db::Layout *layout, db::Cell *top) - : mp_subject_layout (layout), mp_intruder_layout (layout), mp_subject_top (top), mp_intruder_top (top) + : mp_subject_layout (layout), mp_intruder_layout (layout), mp_subject_top (top), mp_intruder_top (top), m_nthreads (0) { // .. nothing yet .. } LocalProcessor::LocalProcessor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_top) - : mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), mp_subject_top (subject_top), mp_intruder_top (intruder_top) + : mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), mp_subject_top (subject_top), mp_intruder_top (intruder_top), m_nthreads (0) { // .. nothing yet .. } +std::string LocalProcessor::description (const LocalOperation *op) const +{ + if (op && m_description.empty ()) { + return op->description (); + } else { + return m_description; + } +} + void LocalProcessor::run (LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layer) { LocalProcessorContexts contexts; @@ -567,21 +633,57 @@ void LocalProcessor::run (LocalOperation *op, unsigned int subject_layer, unsign void LocalProcessor::push_results (db::Cell *cell, unsigned int output_layer, const std::set &result) const { if (! result.empty ()) { + tl::MutexLocker locker (&cell->layout ()->lock ()); cell->shapes (output_layer).insert (result.begin (), result.end ()); } } -void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer) +void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer) const { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Computing contexts for ")) + description ()); + try { - contexts.clear (); - contexts.set_intruder_layer (intruder_layer); - contexts.set_subject_layer (subject_layer); - contexts.set_description (op->description ()); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Computing contexts for ")) + description (op)); - std::pair, std::set > intruders; - compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist ()); + if (m_nthreads > 0) { + mp_cc_job.reset (new tl::Job (m_nthreads)); + } else { + mp_cc_job.reset (0); + } + + contexts.clear (); + contexts.set_intruder_layer (intruder_layer); + contexts.set_subject_layer (subject_layer); + + std::pair, std::set > intruders; + issue_compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist ()); + + if (mp_cc_job.get ()) { + mp_cc_job->start (); + mp_cc_job->wait (); + } + + } catch (...) { + mp_cc_job.reset (0); + throw; + } +} + +void LocalProcessor::issue_compute_contexts (LocalProcessorContexts &contexts, + db::LocalProcessorCellContext *parent_context, + db::Cell *subject_parent, + db::Cell *subject_cell, + const db::ICplxTrans &subject_cell_inst, + const db::Cell *intruder_cell, + std::pair, std::set > &intruders, + db::Coord dist) const +{ + bool is_small_job = subject_cell->begin ().at_end (); + + if (! is_small_job && mp_cc_job.get ()) { + mp_cc_job->schedule (new LocalProcessorContextComputationTask (this, contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist)); + } else { + compute_contexts (contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist); + } } void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, @@ -591,7 +693,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const std::pair, std::set > &intruders, - db::Coord dist) + db::Coord dist) const { if (tl::verbosity () >= 30) { if (! subject_parent) { @@ -601,16 +703,28 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, } } - db::LocalProcessorCellContexts &cell_contexts = contexts.contexts_per_cell (subject_cell, intruder_cell); + db::LocalProcessorCellContext *cell_context = 0; - db::LocalProcessorCellContext *context = cell_contexts.find_context (intruders); - if (context) { - context->add (parent_context, subject_parent, subject_cell_inst); - return; + // prepare a new cell context: this has to happen in a thread-safe way as we share the contexts + // object between threads + + { + tl::MutexLocker locker (& contexts.lock ()); + + db::LocalProcessorCellContexts &cell_contexts = contexts.contexts_per_cell (subject_cell, intruder_cell); + + cell_context = cell_contexts.find_context (intruders); + if (cell_context) { + // we already have a context for this intruder scheme + cell_context->add (parent_context, subject_parent, subject_cell_inst); + return; + } + + cell_context = cell_contexts.create (intruders); + cell_context->add (parent_context, subject_parent, subject_cell_inst); } - context = cell_contexts.create (intruders); - context->add (parent_context, subject_parent, subject_cell_inst); + // perform the actual task .. const db::Shapes *intruder_shapes = 0; if (intruder_cell) { @@ -744,7 +858,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, } db::Cell *intruder_child_cell = (subject_cell == intruder_cell ? &subject_child_cell : 0); - compute_contexts (contexts, context, subject_cell, &subject_child_cell, tn, intruder_child_cell, intruders_below, dist); + issue_compute_contexts (contexts, cell_context, subject_cell, &subject_child_cell, tn, intruder_child_cell, intruders_below, dist); } @@ -756,27 +870,91 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, } void -LocalProcessor::compute_results (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int output_layer) +LocalProcessor::compute_results (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int output_layer) const { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Computing results for ")) + description ()); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Computing results for ")) + description (op)); // avoids updates while we work on the layout mp_subject_layout->update (); - db::LayoutLocker locker (mp_subject_layout); + db::LayoutLocker layout_update_locker (mp_subject_layout); - for (db::Layout::bottom_up_const_iterator bu = mp_subject_layout->begin_bottom_up (); bu != mp_subject_layout->end_bottom_up (); ++bu) { + if (m_nthreads > 0) { + + std::auto_ptr > rc_job (new tl::Job (m_nthreads)); + + // schedule computation jobs in "waves": we need to make sure they are executed + // bottom-up. So we identify a new bunch of cells each time we pass through the cell set + // and proceed until all cells are removed. + + std::vector cells_bu; + cells_bu.reserve (mp_subject_layout->cells ()); + for (db::Layout::bottom_up_const_iterator bu = mp_subject_layout->begin_bottom_up (); bu != mp_subject_layout->end_bottom_up (); ++bu) { + cells_bu.push_back (*bu); + } + + int iter = 0; + while (true) { + + ++iter; + tl::SelfTimer timer (tl::verbosity () >= 21, tl::sprintf (tl::to_string (tr ("Computing results iteration #%d")), iter)); + + bool any = false; + std::set later; + + std::vector next_cells_bu; + next_cells_bu.reserve (cells_bu.size ()); + + std::list tasks; + + for (std::vector::const_iterator bu = cells_bu.begin (); bu != cells_bu.end (); ++bu) { + + if (later.find (*bu) == later.end ()) { + + LocalProcessorContexts::iterator cpc = contexts.context_map ().find (&mp_subject_layout->cell (*bu)); + if (cpc != contexts.context_map ().end ()) { + rc_job->schedule (new LocalProcessorResultComputationTask (this, contexts, cpc->first, &cpc->second, op, output_layer)); + any = true; + for (db::Cell::parent_cell_iterator pc = cpc->first->begin_parent_cells (); pc != cpc->first->end_parent_cells (); ++pc) { + later.insert (*pc); + } + } + + } else { + next_cells_bu.push_back (*bu); + } + + } + + cells_bu.swap (next_cells_bu); + + if (! any) { + break; + } + + if (rc_job.get ()) { + rc_job->start (); + rc_job->wait (); + } + + } + + } else { + + for (db::Layout::bottom_up_const_iterator bu = mp_subject_layout->begin_bottom_up (); bu != mp_subject_layout->end_bottom_up (); ++bu) { + + LocalProcessorContexts::iterator cpc = contexts.context_map ().find (&mp_subject_layout->cell (*bu)); + if (cpc != contexts.context_map ().end ()) { + cpc->second.compute_results (contexts, cpc->first, op, output_layer, this); + contexts.context_map ().erase (cpc); + } - LocalProcessorContexts::iterator cpc = contexts.context_map ().find (&mp_subject_layout->cell (*bu)); - if (cpc != contexts.context_map ().end ()) { - cpc->second.compute_results (contexts, cpc->first, op, output_layer, this); - contexts.context_map ().erase (cpc); } } } void -LocalProcessor::compute_local_cell (LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const db::LocalOperation *op, const std::pair, std::set > &intruders, std::set &result) +LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const db::LocalOperation *op, const std::pair, std::set > &intruders, std::set &result) const { const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ()); diff --git a/src/plugins/tools/netx/db_plugin/dbHierProcessor.h b/src/plugins/tools/netx/db_plugin/dbHierProcessor.h index f99235418..948352e13 100644 --- a/src/plugins/tools/netx/db_plugin/dbHierProcessor.h +++ b/src/plugins/tools/netx/db_plugin/dbHierProcessor.h @@ -28,6 +28,7 @@ #include "dbLayout.h" #include "dbPluginCommon.h" #include "dbLocalOperation.h" +#include "tlThreadedWorkers.h" #include #include @@ -40,7 +41,7 @@ class LocalProcessor; class LocalProcessorCellContext; class LocalProcessorContexts; -// @@@ TODO: move this somewhere else? +// TODO: move this somewhere else? class DB_PLUGIN_PUBLIC ShapeInteractions { public: @@ -78,7 +79,7 @@ private: unsigned int m_id; }; -// @@@ TODO: should be hidden (private data?) +// TODO: should be hidden (private data?) struct DB_PLUGIN_PUBLIC LocalProcessorCellDrop { LocalProcessorCellDrop (db::LocalProcessorCellContext *_parent_context, db::Cell *_parent, const db::ICplxTrans &_cell_inst) @@ -92,7 +93,7 @@ struct DB_PLUGIN_PUBLIC LocalProcessorCellDrop db::ICplxTrans cell_inst; }; -// @@@ TODO: should be hidden (private data?) +// TODO: should be hidden (private data?) class DB_PLUGIN_PUBLIC LocalProcessorCellContext { public: @@ -108,6 +109,11 @@ public: return m_propagated; } + const std::set &propagated () const + { + return m_propagated; + } + size_t size () const { return m_drops.size (); @@ -130,7 +136,7 @@ public: db::LocalProcessorCellContext *find_context (const key_type &intruders); db::LocalProcessorCellContext *create (const key_type &intruders); - void compute_results (LocalProcessorContexts &contexts, db::Cell *cell, const LocalOperation *op, unsigned int output_layer, LocalProcessor *proc); + void compute_results (const LocalProcessorContexts &contexts, db::Cell *cell, const LocalOperation *op, unsigned int output_layer, const LocalProcessor *proc); iterator begin () const { @@ -208,20 +214,82 @@ public: return m_intruder_layer; } - void set_description (const std::string &desc) + tl::Mutex &lock () const { - m_description = desc; - } - - const std::string &description () const - { - return m_description; + return m_lock; } private: contexts_per_cell_type m_contexts_per_cell; unsigned int m_subject_layer, m_intruder_layer; - std::string m_description; + mutable tl::Mutex m_lock; +}; + +class DB_PLUGIN_PUBLIC LocalProcessorContextComputationTask + : public tl::Task +{ +public: + LocalProcessorContextComputationTask (const LocalProcessor *proc, LocalProcessorContexts &contexts, db::LocalProcessorCellContext *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, std::pair, std::set > &intruders, db::Coord dist); + void perform (); + +private: + const LocalProcessor *mp_proc; + LocalProcessorContexts *mp_contexts; + db::LocalProcessorCellContext *mp_parent_context; + db::Cell *mp_subject_parent; + db::Cell *mp_subject_cell; + db::ICplxTrans m_subject_cell_inst; + const db::Cell *mp_intruder_cell; + std::pair, std::set > m_intruders; + db::Coord m_dist; +}; + +class DB_PLUGIN_PUBLIC LocalProcessorContextComputationWorker + : public tl::Worker +{ +public: + LocalProcessorContextComputationWorker () + : tl::Worker () + { + // .. nothing yet .. + } + + void perform_task (tl::Task *task) + { + static_cast (task)->perform (); + } +}; + +class DB_PLUGIN_PUBLIC LocalProcessorResultComputationTask + : public tl::Task +{ +public: + LocalProcessorResultComputationTask (const LocalProcessor *proc, LocalProcessorContexts &contexts, db::Cell *cell, LocalProcessorCellContexts *cell_contexts, const LocalOperation *op, unsigned int output_layer); + void perform (); + +private: + const LocalProcessor *mp_proc; + LocalProcessorContexts *mp_contexts; + db::Cell *mp_cell; + LocalProcessorCellContexts *mp_cell_contexts; + const LocalOperation *mp_op; + unsigned int m_output_layer; +}; + +class DB_PLUGIN_PUBLIC LocalProcessorResultComputationWorker + : public tl::Worker +{ +public: + LocalProcessorResultComputationWorker () + : tl::Worker () + { + // .. nothing yet .. + } + + void perform_task (tl::Task *task) + { + static_cast (task)->perform (); + } }; class DB_PLUGIN_PUBLIC LocalProcessor @@ -230,31 +298,37 @@ public: LocalProcessor (db::Layout *layout, db::Cell *top); LocalProcessor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_cell); void run (LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layer); - void compute_contexts (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer); - void compute_results (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int output_layer); + void compute_contexts (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer) const; + void compute_results (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int output_layer) const; void set_description (const std::string &d) { m_description = d; } - const std::string &description () const + void set_threads (unsigned int nthreads) { - return m_description; + m_nthreads = nthreads; } private: friend class LocalProcessorCellContexts; + friend class LocalProcessorContextComputationTask; db::Layout *mp_subject_layout; const db::Layout *mp_intruder_layout; db::Cell *mp_subject_top; const db::Cell *mp_intruder_top; std::string m_description; + unsigned int m_nthreads; + mutable std::auto_ptr > mp_cc_job; - void compute_contexts (LocalProcessorContexts &contexts, db::LocalProcessorCellContext *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const std::pair, std::set > &intruders, db::Coord dist); + std::string description (const LocalOperation *op) const; + void compute_contexts (db::LocalProcessorContexts &contexts, db::LocalProcessorCellContext *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const std::pair, std::set > &intruders, db::Coord dist) const; + void do_compute_contexts (db::LocalProcessorCellContext *cell_context, const db::LocalProcessorContexts &contexts, db::LocalProcessorCellContext *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const std::pair, std::set > &intruders, db::Coord dist) const; + void issue_compute_contexts (db::LocalProcessorContexts &contexts, db::LocalProcessorCellContext *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, std::pair, std::set > &intruders, db::Coord dist) const; void push_results (db::Cell *cell, unsigned int output_layer, const std::set &result) const; - void compute_local_cell (LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const LocalOperation *op, const std::pair, std::set > &intruders, std::set &result); + void compute_local_cell (const db::LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const LocalOperation *op, const std::pair, std::set > &intruders, std::set &result) const; }; } diff --git a/src/plugins/tools/netx/db_plugin/dbLocalOperation.cc b/src/plugins/tools/netx/db_plugin/dbLocalOperation.cc index 2ee0846b8..744342b0b 100644 --- a/src/plugins/tools/netx/db_plugin/dbLocalOperation.cc +++ b/src/plugins/tools/netx/db_plugin/dbLocalOperation.cc @@ -56,6 +56,7 @@ public: */ virtual void put (const db::Polygon &polygon) { + tl::MutexLocker locker (&mp_layout->lock ()); mp_polyrefs->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); } diff --git a/src/plugins/tools/netx/db_plugin/dbNetExtractor.cc b/src/plugins/tools/netx/db_plugin/dbNetExtractor.cc index 3818caae6..a8d7edfcb 100644 --- a/src/plugins/tools/netx/db_plugin/dbNetExtractor.cc +++ b/src/plugins/tools/netx/db_plugin/dbNetExtractor.cc @@ -35,7 +35,7 @@ namespace db { NetExtractor::NetExtractor() - : mp_orig_layout (0), mp_layout (0), mp_top_cell (0) + : mp_orig_layout (0), mp_layout (0), mp_top_cell (0), m_nthreads (0) { // @@@ @@ -49,6 +49,12 @@ NetExtractor::~NetExtractor () mp_top_cell = 0; } +void +NetExtractor::set_threads (unsigned int nthreads) +{ + m_nthreads = nthreads; +} + void NetExtractor::open (const db::Layout &orig_layout, cell_index_type orig_top_cell) { @@ -154,6 +160,7 @@ NetExtractor::and_or_not (NetLayer a, NetLayer b, bool is_and) db::BoolAndOrNotLocalOperation op (is_and); db::LocalProcessor proc (mp_layout, mp_top_cell); + proc.set_threads (m_nthreads); proc.run (&op, a.layer_index (), b.layer_index (), lout); return NetLayer (lout); diff --git a/src/plugins/tools/netx/db_plugin/dbNetExtractor.h b/src/plugins/tools/netx/db_plugin/dbNetExtractor.h index d4066a3ae..979ec3a97 100644 --- a/src/plugins/tools/netx/db_plugin/dbNetExtractor.h +++ b/src/plugins/tools/netx/db_plugin/dbNetExtractor.h @@ -74,6 +74,12 @@ public: void output (NetLayer a, const db::LayerProperties &lp); db::Layout *layout_copy () const; + void set_threads (unsigned int nthreads); + unsigned int threads () const + { + return m_nthreads; + } + private: // no copying NetExtractor (const db::NetExtractor &); @@ -86,6 +92,7 @@ private: db::Layout *mp_layout; db::Cell *mp_top_cell; db::CellMapping m_cm; + unsigned int m_nthreads; }; } diff --git a/src/plugins/tools/netx/db_plugin/gsiDeclDbNetExtractor.cc b/src/plugins/tools/netx/db_plugin/gsiDeclDbNetExtractor.cc index d6ee3c1df..225b5bf1f 100644 --- a/src/plugins/tools/netx/db_plugin/gsiDeclDbNetExtractor.cc +++ b/src/plugins/tools/netx/db_plugin/gsiDeclDbNetExtractor.cc @@ -55,6 +55,12 @@ gsi::Class decl_NetNetExtractor ("db", "NetExtractor", gsi::method ("open", &db::NetExtractor::open, gsi::arg ("orig_layout"), gsi::arg ("orig_top_cell_index"), "@@@" ) + + gsi::method ("threads=", &db::NetExtractor::set_threads, gsi::arg ("nthreads"), + "@@@" + ) + + gsi::method ("threads", &db::NetExtractor::threads, + "@@@" + ) + gsi::method_ext ("open", &open2, gsi::arg ("orig_layout"), gsi::arg ("orig_top_cell"), "@@@" ) + diff --git a/src/plugins/tools/netx/unit_tests/dbHierProcessorTests.cc b/src/plugins/tools/netx/unit_tests/dbHierProcessorTests.cc index db783ecff..d28ee65b5 100644 --- a/src/plugins/tools/netx/unit_tests/dbHierProcessorTests.cc +++ b/src/plugins/tools/netx/unit_tests/dbHierProcessorTests.cc @@ -158,7 +158,7 @@ std::string contexts_to_s (db::Layout *layout, db::LocalProcessorContexts &conte return res; } -void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, int out_layer_num, std::string *context_doc, bool single, db::Coord dist) +void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, int out_layer_num, std::string *context_doc, bool single, db::Coord dist, unsigned int nthreads = 0) { db::Layout layout_org; @@ -225,6 +225,7 @@ void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, in if (single) { db::LocalProcessor proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ())); + proc.set_threads (nthreads); if (! context_doc) { proc.run (lop, l1, l2, lout); @@ -240,6 +241,7 @@ void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, in db::Layout layout_org2 = layout_org; db::LocalProcessor proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ()), &layout_org2, &layout_org2.cell (*layout_org2.begin_top_down ())); + proc.set_threads (nthreads); if (! context_doc) { proc.run (lop, l1, l2, lout); @@ -255,24 +257,24 @@ void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, in db::compare_layouts (_this, layout_org, testdata (file), lmap, false /*skip other layers*/, db::AsPolygons); } -void run_test_bool (tl::TestBase *_this, const char *file, TestMode mode, int out_layer_num, std::string *context_doc = 0) +void run_test_bool (tl::TestBase *_this, const char *file, TestMode mode, int out_layer_num, std::string *context_doc = 0, unsigned int nthreads = 0) { - run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, true, 0); + run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, true, 0, nthreads); } -void run_test_bool2 (tl::TestBase *_this, const char *file, TestMode mode, int out_layer_num, std::string *context_doc = 0) +void run_test_bool2 (tl::TestBase *_this, const char *file, TestMode mode, int out_layer_num, std::string *context_doc = 0, unsigned int nthreads = 0) { - run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, false, 0); + run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, false, 0, nthreads); } -void run_test_bool_with_size (tl::TestBase *_this, const char *file, TestMode mode, db::Coord dist, int out_layer_num, std::string *context_doc = 0) +void run_test_bool_with_size (tl::TestBase *_this, const char *file, TestMode mode, db::Coord dist, int out_layer_num, std::string *context_doc = 0, unsigned int nthreads = 0) { - run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, true, dist); + run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, true, dist, nthreads); } -void run_test_bool2_with_size (tl::TestBase *_this, const char *file, TestMode mode, db::Coord dist, int out_layer_num, std::string *context_doc = 0) +void run_test_bool2_with_size (tl::TestBase *_this, const char *file, TestMode mode, db::Coord dist, int out_layer_num, std::string *context_doc = 0, unsigned int nthreads = 0) { - run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, false, dist); + run_test_bool_gen (_this, file, mode, out_layer_num, context_doc, false, dist, nthreads); } TEST(BasicAnd1) @@ -281,36 +283,108 @@ TEST(BasicAnd1) run_test_bool (_this, "hlp1.oas", TMAnd, 100); } +TEST(BasicAnd1SingleThread) +{ + // Simple flat AND + run_test_bool (_this, "hlp1.oas", TMAnd, 100, 0, 1); +} + +TEST(BasicAnd1FourThreads) +{ + // Simple flat AND + run_test_bool (_this, "hlp1.oas", TMAnd, 100, 0, 4); +} + TEST(BasicNot1) { - // Simple flat NOT + // Simple flat AND run_test_bool (_this, "hlp1.oas", TMNot, 101); } +TEST(BasicNot1SingleThread) +{ + // Simple flat NOT + run_test_bool (_this, "hlp1.oas", TMNot, 101, 0, 1); +} + +TEST(BasicNot1FourThreads) +{ + // Simple flat NOT + run_test_bool (_this, "hlp1.oas", TMNot, 101, 0, 4); +} + TEST(BasicAnd2) { // Up/down and down/up interactions, AND run_test_bool (_this, "hlp2.oas", TMAnd, 100); } +TEST(BasicAnd2SingleThread) +{ + // Up/down and down/up interactions, AND + run_test_bool (_this, "hlp2.oas", TMAnd, 100, 0, 1); +} + +TEST(BasicAnd2FourThreads) +{ + // Up/down and down/up interactions, AND + run_test_bool (_this, "hlp2.oas", TMAnd, 100, 0, 4); +} + TEST(BasicNot2) { // Up/down and down/up interactions, NOT run_test_bool (_this, "hlp2.oas", TMNot, 101); } +TEST(BasicNot2SingleThread) +{ + // Up/down and down/up interactions, NOT + run_test_bool (_this, "hlp2.oas", TMNot, 101, 0, 1); +} + +TEST(BasicNot2FourThreads) +{ + // Up/down and down/up interactions, NOT + run_test_bool (_this, "hlp2.oas", TMNot, 101, 0, 4); +} + TEST(BasicAnd3) { // Variant building, AND run_test_bool (_this, "hlp3.oas", TMAnd, 100); } +TEST(BasicAnd3SingleThread) +{ + // Variant building, AND + run_test_bool (_this, "hlp3.oas", TMAnd, 100, 0, 1); +} + +TEST(BasicAnd3FourThreads) +{ + // Variant building, AND + run_test_bool (_this, "hlp3.oas", TMAnd, 100, 0, 4); +} + TEST(BasicNot3) { // Variant building, NOT run_test_bool (_this, "hlp3.oas", TMNot, 101); } +TEST(BasicNot3SingleThread) +{ + // Variant building, NOT + run_test_bool (_this, "hlp3.oas", TMNot, 101, 0, 1); +} + +TEST(BasicNot3FourThreads) +{ + // Variant building, NOT + run_test_bool (_this, "hlp3.oas", TMNot, 101, 0, 4); +} + TEST(BasicAnd4) { // Sibling interactions, variant building, AND