Attempt to introduce multithreading into hierarchical processor

However, performance does not scale well currently.
This commit is contained in:
Matthias Koefferlein 2018-10-08 00:10:54 +02:00
parent 35e03c5f95
commit 121ec46390
9 changed files with 426 additions and 64 deletions

View File

@ -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

View File

@ -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,

View File

@ -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 ());

View File

@ -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;
};
}

View File

@ -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 ()));
}

View File

@ -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);

View File

@ -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;
};
}

View File

@ -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"),
"@@@"
) +

View File

@ -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