mirror of https://github.com/KLayout/klayout.git
Attempt to introduce multithreading into hierarchical processor
However, performance does not scale well currently.
This commit is contained in:
parent
35e03c5f95
commit
121ec46390
|
|
@ -38,6 +38,7 @@
|
|||
#include "tlException.h"
|
||||
#include "tlVector.h"
|
||||
#include "tlString.h"
|
||||
#include "tlThreads.h"
|
||||
#include "gsi.h"
|
||||
|
||||
#include <cstring>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<tl::Timer> decl_Timer ("tl", "Timer",
|
||||
|
|
@ -162,7 +162,11 @@ Class<tl::Timer> 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,
|
||||
|
|
|
|||
|
|
@ -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 <class Trans>
|
||||
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<db::PolygonRef> 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<db::PolygonRef> res = c->second.propagated ();
|
||||
std::set<db::PolygonRef> 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<key_type, db::LocalProcessorCellContext>::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<db::PolygonRef> 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<db::PolygonRef> 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<CellInstArray>, std::set<PolygonRef> > &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<db::PolygonRef> &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<db::CellInstArray>, std::set<db::PolygonRef> > 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<LocalProcessorContextComputationWorker> (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<db::CellInstArray>, std::set<db::PolygonRef> > 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<CellInstArray>, std::set<PolygonRef> > &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<CellInstArray>, std::set<PolygonRef> > &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<tl::Job<LocalProcessorResultComputationWorker> > rc_job (new tl::Job<LocalProcessorResultComputationWorker> (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<db::cell_index_type> 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<db::cell_index_type> later;
|
||||
|
||||
std::vector<db::cell_index_type> next_cells_bu;
|
||||
next_cells_bu.reserve (cells_bu.size ());
|
||||
|
||||
std::list<LocalProcessorResultComputationTask *> tasks;
|
||||
|
||||
for (std::vector<db::cell_index_type>::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<CellInstArray>, std::set<db::PolygonRef> > &intruders, std::set<db::PolygonRef> &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<CellInstArray>, std::set<db::PolygonRef> > &intruders, std::set<db::PolygonRef> &result) const
|
||||
{
|
||||
const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ());
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "dbLayout.h"
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbLocalOperation.h"
|
||||
#include "tlThreadedWorkers.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -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<db::PolygonRef> &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<CellInstArray>, std::set<PolygonRef> > &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<CellInstArray>, std::set<PolygonRef> > 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<LocalProcessorContextComputationTask *> (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<LocalProcessorResultComputationTask *> (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<tl::Job<LocalProcessorContextComputationWorker> > 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<CellInstArray>, std::set<PolygonRef> > &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<CellInstArray>, std::set<PolygonRef> > &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<CellInstArray>, std::set<PolygonRef> > &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<CellInstArray>, std::set<PolygonRef> > &intruders, db::Coord dist) const;
|
||||
void push_results (db::Cell *cell, unsigned int output_layer, const std::set<db::PolygonRef> &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<CellInstArray>, std::set<db::PolygonRef> > &intruders, std::set<db::PolygonRef> &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<CellInstArray>, std::set<db::PolygonRef> > &intruders, std::set<db::PolygonRef> &result) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ gsi::Class<db::NetExtractor> 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"),
|
||||
"@@@"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue