From 99f111fe01879998a9412f424cb60e773997a194 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 2 Feb 2019 22:43:42 +0100 Subject: [PATCH] Attempt to achieve reproducibility between MSVC and gcc Applies to dbHierProcessor.cc: The issue was related to std::unordered_set/map which (as the name says) is not ordered. The output of the boolean core computation step is currently dependent on the order (it's single pass), hence the order of the contexts matters. Using ordered sets where possible and explicit sorting might help. --- src/db/db/dbHash.h | 16 +++++++ src/db/db/dbHierProcessor.cc | 74 ++++++++++++++++++++---------- src/db/db/dbHierProcessor.h | 24 +++++----- testdata/algo/deep_region_au6.gds | Bin 9818 -> 9818 bytes testdata/algo/hlp12.oas | Bin 868 -> 832 bytes testdata/algo/hlp14.oas | Bin 526 -> 513 bytes testdata/algo/hlp6.oas | Bin 2671 -> 2637 bytes 7 files changed, 77 insertions(+), 37 deletions(-) diff --git a/src/db/db/dbHash.h b/src/db/db/dbHash.h index 5f5ecb481..5c14ce12a 100644 --- a/src/db/db/dbHash.h +++ b/src/db/db/dbHash.h @@ -404,6 +404,22 @@ namespace std return hf; } }; + + /** + * @brief Generic hash for an ordered set + */ + template + struct hash > + { + size_t operator() (const std::set &o) const + { + size_t hf = 0; + for (typename std::set::const_iterator i = o.begin (); i != o.end (); ++i) { + hf = hfunc (hf, std::hash () (*i)); + } + return hf; + } + }; } #endif diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index a2f4d83d6..73fb42941 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -242,14 +242,14 @@ LocalProcessorCellContexts::LocalProcessorCellContexts (const db::Cell *intruder } db::LocalProcessorCellContext * -LocalProcessorCellContexts::find_context (const key_type &intruders) +LocalProcessorCellContexts::find_context (const context_key_type &intruders) { - std::unordered_map::iterator c = m_contexts.find (intruders); + std::unordered_map::iterator c = m_contexts.find (intruders); return c != m_contexts.end () ? &c->second : 0; } db::LocalProcessorCellContext * -LocalProcessorCellContexts::create (const key_type &intruders) +LocalProcessorCellContexts::create (const context_key_type &intruders) { return &m_contexts[intruders]; } @@ -290,6 +290,18 @@ subtract (std::unordered_set &res, const std::unordered_set &a, const std::pair &b) + { + return *a.first < *b.first; + } +}; + +} + void LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &contexts, db::Cell *cell, const LocalOperation *op, unsigned int output_layer, const LocalProcessor *proc) { @@ -300,7 +312,19 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte int index = 0; int total = int (m_contexts.size ()); - for (std::unordered_map::iterator c = m_contexts.begin (); c != m_contexts.end (); ++c) { + + // NOTE: we use the ordering provided by key_type::operator< rather than the unordered map to achieve + // reproducability across different platforms. unordered_map is faster, but for processing them, + // strict ordering is a more robust choice. + std::vector > sorted_contexts; + sorted_contexts.reserve (m_contexts.size ()); + for (std::unordered_map::iterator c = m_contexts.begin (); c != m_contexts.end (); ++c) { + sorted_contexts.push_back (std::make_pair (&c->first, &c->second)); + } + + std::sort (sorted_contexts.begin (), sorted_contexts.end (), context_sorter ()); + + for (std::vector >::const_iterator c = sorted_contexts.begin (); c != sorted_contexts.end (); ++c) { ++index; @@ -311,31 +335,31 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte if (first) { { - tl::MutexLocker locker (&c->second.lock ()); - common = c->second.propagated (); + tl::MutexLocker locker (&c->second->lock ()); + common = c->second->propagated (); } CRONOLOGY_COMPUTE_BRACKET(event_compute_local_cell) - proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, c->first, common); + proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, *c->first, common); first = false; } else { std::unordered_set res; { - tl::MutexLocker locker (&c->second.lock ()); - res = c->second.propagated (); + tl::MutexLocker locker (&c->second->lock ()); + res = c->second->propagated (); } { CRONOLOGY_COMPUTE_BRACKET(event_compute_local_cell) - proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, c->first, res); + proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, *c->first, res); } if (common.empty ()) { CRONOLOGY_COMPUTE_BRACKET(event_propagate) - c->second.propagate (res); + c->second->propagate (res); } else if (res != common) { @@ -354,8 +378,8 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte if (! lost.empty ()) { subtract (common, lost, cell->layout (), proc->max_vertex_count (), proc->area_ratio ()); - for (std::unordered_map::iterator cc = m_contexts.begin (); cc != c; ++cc) { - cc->second.propagate (lost); + for (std::vector >::const_iterator cc = sorted_contexts.begin (); cc != c; ++cc) { + cc->second->propagate (lost); } } @@ -373,7 +397,7 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte subtract (gained, common, cell->layout (), proc->max_vertex_count (), proc->area_ratio ()); if (! gained.empty ()) { - c->second.propagate (gained); + c->second->propagate (gained); } } @@ -740,7 +764,7 @@ 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::unordered_set > &intruders, db::Coord dist) +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, LocalProcessorCellContexts::context_key_type &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), @@ -849,7 +873,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, const L contexts.set_intruder_layer (intruder_layer); contexts.set_subject_layer (subject_layer); - std::pair, std::unordered_set > intruders; + LocalProcessorCellContexts::context_key_type intruders; issue_compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist ()); if (mp_cc_job.get ()) { @@ -869,7 +893,7 @@ void LocalProcessor::issue_compute_contexts (LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, - std::pair, std::unordered_set > &intruders, + LocalProcessorCellContexts::context_key_type &intruders, db::Coord dist) const { bool is_small_job = subject_cell->begin ().at_end (); @@ -887,7 +911,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, - const std::pair, std::unordered_set > &intruders, + const LocalProcessorCellContexts::context_key_type &intruders, db::Coord dist) const { CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts) @@ -1008,7 +1032,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, } - for (std::unordered_set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { + for (std::set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { if (! inst_bci (*i).empty ()) { scanner.insert2 (i.operator-> (), ++id); } @@ -1028,7 +1052,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, } } - for (std::unordered_set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { + for (std::set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { scanner.insert2 (i.operator-> (), 0); } @@ -1053,7 +1077,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, if (! nbox.empty ()) { - std::pair, std::unordered_set > intruders_below; + LocalProcessorCellContexts::context_key_type intruders_below; db::shape_reference_translator_with_trans rt (mp_subject_layout, tni); @@ -1173,7 +1197,7 @@ LocalProcessor::compute_results (LocalProcessorContexts &contexts, const LocalOp } void -LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const db::LocalOperation *op, const std::pair, std::unordered_set > &intruders, std::unordered_set &result) const +LocalProcessor::compute_local_cell (const db::LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const LocalOperation *op, const LocalProcessorCellContexts::context_key_type &intruders, std::unordered_set &result) const { const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ()); @@ -1221,7 +1245,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: } // TODO: TODO: can we confine this search to the subject's (sized) bounding box? - for (std::unordered_set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { + for (std::set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { scanner.insert (i.operator-> (), interactions.next_id ()); } @@ -1239,7 +1263,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: } // TODO: can we confine this search to the subject's (sized) bounding box? - for (std::unordered_set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { + for (std::set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { scanner.insert2 (i.operator-> (), interactions.next_id ()); } @@ -1284,7 +1308,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db:: } // TODO: can we confine this search to the subject's (sized) bounding box? - for (std::unordered_set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { + for (std::set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { if (! inst_bci (*i).empty ()) { scanner.insert2 (i.operator-> (), ++inst_id); } diff --git a/src/db/db/dbHierProcessor.h b/src/db/db/dbHierProcessor.h index 5ed1ecb4e..5bc2cf4d1 100644 --- a/src/db/db/dbHierProcessor.h +++ b/src/db/db/dbHierProcessor.h @@ -152,15 +152,15 @@ private: class DB_PUBLIC LocalProcessorCellContexts { public: - typedef std::pair, std::unordered_set > key_type; - typedef std::unordered_map map_type; - typedef map_type::const_iterator iterator; + typedef std::pair, std::set > context_key_type; + typedef std::unordered_map context_map_type; + typedef context_map_type::const_iterator iterator; LocalProcessorCellContexts (); LocalProcessorCellContexts (const db::Cell *intruder_cell); - db::LocalProcessorCellContext *find_context (const key_type &intruders); - db::LocalProcessorCellContext *create (const key_type &intruders); + db::LocalProcessorCellContext *find_context (const context_key_type &intruders); + db::LocalProcessorCellContext *create (const context_key_type &intruders); void compute_results (const LocalProcessorContexts &contexts, db::Cell *cell, const LocalOperation *op, unsigned int output_layer, const LocalProcessor *proc); iterator begin () const @@ -175,7 +175,7 @@ public: private: const db::Cell *mp_intruder_cell; - std::unordered_map m_contexts; + std::unordered_map m_contexts; }; class DB_PUBLIC LocalProcessorContexts @@ -260,7 +260,7 @@ class DB_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::unordered_set > &intruders, db::Coord dist); + 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, LocalProcessorCellContexts::context_key_type &intruders, db::Coord dist); void perform (); private: @@ -271,7 +271,7 @@ private: db::Cell *mp_subject_cell; db::ICplxTrans m_subject_cell_inst; const db::Cell *mp_intruder_cell; - std::pair, std::unordered_set > m_intruders; + LocalProcessorCellContexts::context_key_type m_intruders; db::Coord m_dist; }; @@ -382,11 +382,11 @@ private: mutable std::auto_ptr > mp_cc_job; 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::unordered_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::unordered_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::unordered_set > &intruders, db::Coord dist) 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 LocalProcessorCellContexts::context_key_type &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 LocalProcessorCellContexts::context_key_type &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, LocalProcessorCellContexts::context_key_type &intruders, db::Coord dist) const; void push_results (db::Cell *cell, unsigned int output_layer, const std::unordered_set &result) const; - void compute_local_cell (const db::LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const LocalOperation *op, const std::pair, std::unordered_set > &intruders, std::unordered_set &result) const; + void compute_local_cell (const db::LocalProcessorContexts &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const LocalOperation *op, const LocalProcessorCellContexts::context_key_type &intruders, std::unordered_set &result) const; }; } diff --git a/testdata/algo/deep_region_au6.gds b/testdata/algo/deep_region_au6.gds index 6609f6f4071cc0c2333e0ae7ac461b2abbb344db..9fecea99fb9bb8f92637ea72e40ec2d1129e3f82 100644 GIT binary patch delta 1662 zcmaJ>JxE(o6h3*4iHRnt)fb!ko0#x;SRF*IP(ln@sv$_JB3X0_Z|Lk;T9pXrVY12RpXNqf_S=nx5|+uW_-2%Xja0zVmnQdAY1z)*2Ke%UY+Qh!y`% zmi%lQq?y}$>a=3Drxl|9dmW|4SM$qf?|v;*KThwzX*{Q)jywH6G&qvEBPK_!eg0up z_`oW0F*E!6FvVVGh7Thtb|!#bd@wv4qL@S8%S?{M>3~xpe>naz=Pl*x( zM8NLPMEPVJ4WAg`FCE$9WKXO0w?H)6LlpT&^r&Ib@W4=7K2oZDq>{zo1`U5pss%ub z0w6Vr0>EDvuuST`Od74WWYF+8Q6Ygh5YZqtX!x79REoABL0bkP1%EAFT~R3zlC`}y zLaO%g1~&Fp3WRj?XB#0^dnmQeRSJYOnr$PbYKJtpv9F!N8&80!iiYQ8V#+qxZk}P` z?B-&ub5$ZJJdsS%@S(Jxa&2@2)9Q+v>dnxEQJC9QYHm{{^Y0BBUZpYDHi6CJhcm@TwgKuXnq)nQJrWg`#>T+&-ug&`e;}=ABNxXH=>)O0;mM!IG|xn}G?4 zJkwjDX*cEend#AKA*wfdNrK@PkYoH*d&ype>2ckLG7@~Gkmi#rRXeA7E01QTRHqW}dHgB;Ho{(CnH{YAvU=Iwua(*E32E{%hI`Q$cg0h@ZS;MjyyJyQ@G(k?*kesm>y*DPj_yltHC0=t> z;)$;(evbG#up{?Km0#qaurIz2{DpI%lYJodIT=AL@$ASiYClGjHsxo!3f f+Z=#Ht;kWFd@v@tGbKKln2N>a+lZl(@jOUuoi^gS&l+dltrR$;*bR9*ll07ARf*7-}enre8bvjBprZXlb5T#-%*Z?UH z--rYvW#sb}VU;?G6?=<>nP3%aUC-7#9-Kfa5UG=VGEJn8H^@l!XYjEhq3cu(Yu9-m@hnyZ3 zX?j>JbF-RS7pqYxFWH(I+LBR0j5_dwwv2vr^-yFG^74Lg0=XAh%Duoxf_tHJ~P|y|5|WPv2^4T~gTEaV8Re;y4+8;zF(evmy-}f!G+Snp(%$ z2`7VVg%XHT&D=XozYmd@nIQkp1i4I`Y2W4dY?YjBg}heQ@v!bg=e5VQ+3TSvyFotI zIo5I;TZI}{mF$iRt+nAlkiB`X6)RNgVf{X@@wD;N&i+p31J2=h&*FFXd-wS1 zU>$_VWU|M_dlwU#OpkM1?(x~{<#|8O_t@)q)~MV&P9FPguDhuBGLgaixt!@0+1JCw z{>b9B&%JJ8gM4_A&F?nX>;kWO{zjhX=Nar$nX>ImR*`K6u&Zy>M$}jNM2$*$ivO> zK~xANb%Aw-$PK;~lA<;ssYOgTln(MRh?+36t&q&Wz?%0$^%CPU79`VvG7nr9F}+mH zyU3dVgO!`@f`|dw9s!UE3Kv)xiJg>MA&H~|DEvYd delta 207 zcmX@W_JnQ2BF6d)tQS~!Fu&m8X1yTdAOHfQHjGRi>R*^=b9`my<_%cD_rSBRXHS|Q2Jc0okI0B%BqSitr{R8*u* z5y<@DYzty9TgeFIY~Ta2k6mJ95EXg$8$`A(Wdf4R&Vk5d-c6 delta 40 ycmV+@0N4M41dard;vLQyhI@+R04M`6_AjPA-xw!% zvls>#Ffy%ho4~weClko<4u=`eE!k&gFmp3(P!bTe0EtX6ZP~{7WHOT|P-%z53-*?5 zpg7A5%Nfp{d>c7|8lS9WhN#@(xkX?StB5(+jX(*Y9Uuvi8+$%89qDBfwS~HIg3OJH zEZhuxSOq|)UeLH9``{qs%uM(F=ZGmD>klUWhzn8gMWd4z@`H)&co1)E7C)T8@`bp z6b1(Ap@Lv)t8}nK#ECsrh~gm!g$O<5Agr=6BFOOj(pE1IKJWYE^W(iw<9p*|U+fnM zyS0nI%Nu)(?V`SKGSgrXPxkxJBN7zfnQpK>>(Un5!-T+#sWihZR1uiVpo%?y0?g3E01_rh