From ab4d97c1e5d81610b59943e906c08b0050d2aba4 Mon Sep 17 00:00:00 2001 From: Clement Jamin Date: Wed, 21 Nov 2012 16:16:47 +0100 Subject: [PATCH] The global optimizers are now parallel (needs some intense testing now) --- Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h | 635 +++++++++++++++--- Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h | 3 +- .../CGAL/Mesh_3/Mesh_global_optimizer.h | 462 ++++++++++--- .../include/CGAL/Mesh_3/Mesh_sizing_field.h | 61 +- Mesh_3/include/CGAL/Mesh_3/Odt_move.h | 4 +- Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h | 4 + Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h | 4 + .../CGAL/Triangulation_data_structure_3.h | 2 + .../CGAL/Triangulation_ds_cell_base_3.h | 45 +- 9 files changed, 1030 insertions(+), 190 deletions(-) diff --git a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h index da9ce336b31..0e5d3c9cb67 100644 --- a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h +++ b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h @@ -33,6 +33,10 @@ #include #include +#ifdef MESH_3_PROFILING + #include +#endif + #include #include #include @@ -41,13 +45,18 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + #include #include #include namespace CGAL { namespace Mesh_3 { - + +static tbb::mutex mut_outdated_cells, mut_moving_vertices, mut_vertex_to_proj; // CJTODO LOCK #ifdef CGAL_INTRUSIVE_LIST template @@ -356,12 +365,169 @@ private: }; #endif // #ifdef CGAL_INTRUSIVE_LIST -template + +/************************************************ +// Class C3T3_helpers_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class C3T3_helpers_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::Point_3 Point_3; + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Cell_handle Cell_handle; + typedef typename Tr::Facet Facet; + + C3T3_helpers_base(LockDataStructureType *) {} + + LockDataStructureType *get_lock_data_structure() const + { + return 0; + } + + bool try_lock_point(const Point_3 &p, int lock_radius = 0) const + { + return true; + } + + bool try_lock_vertex(Vertex_handle vh, int lock_radius = 0) const + { + return true; + } + + bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const + { + return true; + } + + bool try_lock_element(const Facet &facet, int lock_radius = 0) const + { + return true; + } + + void unlock_all_elements() {} +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class C3T3_helpers_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::Point_3 Point_3; + typedef typename Tr::Vertex_handle Vertex_handle; + typedef typename Tr::Cell_handle Cell_handle; + typedef typename Tr::Facet Facet; + + C3T3_helpers_base(LockDataStructureType *p_lock_ds) + : m_lock_ds(p_lock_ds) {} + + + // LOCKS (CONCURRENCY) + + /*Mesh_3::LockDataStructureType *get_lock_data_structure() const + { + return m_lock_ds; + }*/ + + bool try_lock_point(const Point_3 &p, int lock_radius = 0) const + { + if (m_lock_ds) + { + return m_lock_ds->try_lock(p, lock_radius).first; + } + return true; + } + + bool try_lock_vertex(Vertex_handle vh, int lock_radius = 0) const + { + if (m_lock_ds) + { + return m_lock_ds->try_lock(vh->point(), lock_radius).first; + } + return true; + } + + bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const + { + bool success = true; + + // Lock the element area on the grid + for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex) + { + Vertex_handle vh = cell_handle->vertex(iVertex); + success = try_lock_vertex(vh, lock_radius); + } + + return success; + } + + bool try_lock_element(const Facet &facet, int lock_radius = 0) const + { + bool success = true; + + // Lock the element area on the grid + Cell_handle cell = facet.first; + for (int iVertex = (facet.second+1)&3 ; + success && iVertex != facet.second ; iVertex = (iVertex+1)&3) + { + Vertex_handle vh = cell->vertex(iVertex); + success = try_lock_vertex(vh, lock_radius); + } + + return success; + } + + bool is_element_locked_by_this_thread(Cell_handle cell_handle) const + { + bool locked = true; + for (int iVertex = 0 ; locked && iVertex < 4 ; ++iVertex) + { + Vertex_handle vh = cell_handle->vertex(iVertex); + locked = m_lock_ds->is_locked_by_this_thread(vh->point()); + } + return locked; + } + + void unlock_all_elements() + { + if (m_lock_ds) + { + m_lock_ds->unlock_all_tls_locked_cells(); + } + } + +protected: + Mesh_3::LockDataStructureType *m_lock_ds; +}; +#endif // CGAL_LINKED_WITH_TBB + + +/************************************************ + * + * C3T3_helpers class + * + ************************************************/ + +template class C3T3_helpers +: public C3T3_helpers_base { // ----------------------------------- // Private types // ----------------------------------- + typedef C3T3_helpers Self; + typedef C3T3_helpers_base Base; + typedef typename C3T3::Concurrency_tag Concurrency_tag; + typedef typename C3T3::Triangulation Tr; typedef Tr Triangulation; typedef typename Tr::Geom_traits Gt; @@ -417,8 +583,10 @@ public: /** * Constructor */ - C3T3_helpers(C3T3& c3t3, const MeshDomain& domain) - : c3t3_(c3t3) + C3T3_helpers(C3T3& c3t3, const MeshDomain& domain, + LockDataStructureType *p_lock_ds = 0) + : Base(p_lock_ds) + , c3t3_(c3t3) , tr_(c3t3.triangulation()) , domain_(domain) { } @@ -519,11 +687,17 @@ public: * Moves \c old_vertex to \c new_position * Stores the cells which have to be updated in \c outdated_cells * Updates the Vertex_handle old_vertex to its new value in \c moving_vertices + * The second one (with the p_could_lock_zone param) is for the parallel version */ Vertex_handle move_point(const Vertex_handle& old_vertex, const Point_3& new_position, Outdated_cell_set& outdated_cells_set, Moving_vertices_set& moving_vertices); + Vertex_handle move_point(const Vertex_handle& old_vertex, + const Point_3& new_position, + Outdated_cell_set& outdated_cells_set, + Moving_vertices_set& moving_vertices, + bool *p_could_lock_zone); /** * Outputs to out the sliver (wrt \c criterion and \c sliver_bound) incident @@ -896,7 +1070,8 @@ private: { const Vertex_handle& v = f.first->vertex((k+i)&3); if ( c3t3_.in_dimension(v) > 2 ) - { + { + tbb::mutex::scoped_lock lock(mut_vertex_to_proj); vertex_to_proj.insert(v); } } @@ -1018,7 +1193,8 @@ private: Vertex_handle move_point_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, - Outdated_cell_set& outdated_cells_set); + Outdated_cell_set& outdated_cells_set, + bool *p_could_lock_zone = 0); template < typename OutdatedCellsOutputIterator, typename DeletedCellsOutputIterator > @@ -1132,7 +1308,8 @@ private: const Point_3& conflict_point, CellsOutputIterator insertion_conflict_cells, FacetsOutputIterator insertion_conflict_boundary, - CellsOutputIterator removal_conflict_cells) const; + CellsOutputIterator removal_conflict_cells, + bool *p_could_lock_zone = 0) const; template < typename ConflictCellsInputIterator, @@ -1280,44 +1457,99 @@ private: template void update_facets(Intrusive_list& outdated_cells, FacetUpdater updater) { - typename Intrusive_list::iterator it; - for(it = outdated_cells.begin(); - it != outdated_cells.end(); - ++it) +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) { - Cell_handle cell = *it; - - int i=0; - bool inf = false; - for ( ; i<4 && (!inf) ; ++i ){ - if ( tr_.is_infinite(cell->vertex(i)) ){ - inf = true; - Cell_handle n = cell->neighbor(i); - if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated - if(cell < n){ // otherwise n will report it later - updater(Facet(cell,i)); - } - } else { // report it now or never - if(cell < n){ - updater(Facet(cell,i)); - }else { - updater(Facet(n,n->index(cell))); + tbb::parallel_do(outdated_cells.begin(), outdated_cells.end(), + [&]( const Cell_handle& cell ) // CJTODO: lambdas ok? + { + Cell_handle null_cell; + bool inf = false; + for (int i=0 ; i<4 && (!inf) ; ++i ){ + if ( tr_.is_infinite(cell->vertex(i)) ){ + inf = true; + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != null_cell){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + Facet f(cell,i); + updater(f); + } + } else { // report it now or never + if(cell < n){ + Facet f(cell,i); + updater(f); + }else { + Facet f(n,n->index(cell)); + updater(f); + } } } } - } - if(! inf){ - for ( i=0 ; i<4 ; ++i ){ - Cell_handle n = cell->neighbor(i); - if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated - if(cell < n){ // otherwise n will report it later - updater(Facet(cell,i)); + if(! inf){ + for ( int i=0 ; i<4 ; ++i ){ + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != null_cell){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + Facet f(cell,i); + updater(f); + } + } else { // report it now or never + if(cell < n){ + Facet f(cell,i); + updater(f); + }else { + Facet f(n,n->index(cell)); + updater(f); + } } - } else { // report it now or never - if(cell < n){ - updater(Facet(cell,i)); - }else { - updater(Facet(n,n->index(cell))); + } + } + }); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + typename Intrusive_list::iterator it; + for(it = outdated_cells.begin(); + it != outdated_cells.end(); + ++it) + { + Cell_handle cell = *it; + + int i=0; + bool inf = false; + for ( ; i<4 && (!inf) ; ++i ){ + if ( tr_.is_infinite(cell->vertex(i)) ){ + inf = true; + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + updater(Facet(cell,i)); + } + } else { // report it now or never + if(cell < n){ + updater(Facet(cell,i)); + }else { + updater(Facet(n,n->index(cell))); + } + } + } + } + if(! inf){ + for ( i=0 ; i<4 ; ++i ){ + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + updater(Facet(cell,i)); + } + } else { // report it now or never + if(cell < n){ + updater(Facet(cell,i)); + }else { + updater(Facet(n,n->index(cell))); + } } } } @@ -1492,7 +1724,7 @@ private: C3T3& c3t3_; Tr& tr_; const MeshDomain& domain_; -}; +}; // class C3T3_helpers template @@ -1706,16 +1938,48 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells, typename OutdatedCells::iterator first_cell = outdated_cells.begin(); typename OutdatedCells::iterator last_cell = outdated_cells.end(); Update_c3t3 updater(domain_,c3t3_); - + +#ifdef MESH_3_PROFILING + std::cerr << std::endl << " Updating cells..."; + WallClockTimer t; + size_t num_cells = c3t3_.number_of_cells_in_complex(); +#endif + // Updates cells - while ( first_cell != last_cell ) + // Note: ~58% of rebuild_restricted_delaunay time +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) { - const Cell_handle& cell = *first_cell++; - c3t3_.remove_from_complex(cell); - updater(cell); + tbb::parallel_do(first_cell, last_cell, + [&]( OutdatedCells::const_reference cell ) // CJTODO: lambdas ok? + { + c3t3_.remove_from_complex(cell); + updater(cell); + }); } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + while ( first_cell != last_cell ) + { + const Cell_handle& cell = *first_cell++; + c3t3_.remove_from_complex(cell); + updater(cell); + } + } + +#ifdef MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds (#cells from " + << num_cells << " to " << c3t3_.number_of_cells_in_complex() << ")." + << std::endl; + std::cerr << " Updating facets..."; + t.reset(); +#endif // Get facets (returns each canonical facet only once) + // Note: ~42% of rebuild_restricted_delaunay time // Facet_vector facets; std::set vertex_to_proj; Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); @@ -1723,9 +1987,17 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells, // now we can clear outdated_cells.clear(); + +#ifdef MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds (" + << vertex_to_proj.size() << " vertices to project)." << std::endl; + std::cerr << " Projecting interior vertices..."; + t.reset(); +#endif CGAL_HISTOGRAM_PROFILER("|vertex_to_proj|=", vertex_to_proj.size()); // Project interior vertices + // Note: ~0% of rebuild_restricted_delaunay time // TODO : iterate to be sure no interior vertice become on the surface // because of move ? for ( typename std::set::iterator it = vertex_to_proj.begin() ; @@ -1746,6 +2018,10 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells, moving_vertices.insert(new_vertex); } } + +#ifdef MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds." << std::endl; +#endif } #endif //CGAL_INTRUSIVE_LIST @@ -1763,35 +2039,87 @@ rebuild_restricted_delaunay(ForwardIterator first_cell, Facet_vector facets = get_facets(first_cell, last_cell); // Updates cells - while ( first_cell != last_cell ) + // Note: ~58% of rebuild_restricted_delaunay time +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) { - const Cell_handle& cell = *first_cell++; - c3t3_.remove_from_complex(cell); - updater(cell); + tbb::parallel_do(first_cell, last_cell, + [&]( ForwardIterator::reference cell ) // CJTODO: lambdas ok? + { + c3t3_.remove_from_complex(cell); + updater(cell); + }); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + while ( first_cell != last_cell ) + { + const Cell_handle& cell = *first_cell++; + c3t3_.remove_from_complex(cell); + updater(cell); + } } // Updates facets std::set > vertex_to_proj; - for ( typename Facet_vector::iterator fit = facets.begin() ; - fit != facets.end() ; - ++fit ) +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) { - // Update facet - c3t3_.remove_from_complex(*fit); - updater(*fit); - - // Update vertex_to_proj - if ( c3t3_.is_in_complex(*fit) ) + tbb::parallel_do(facets.begin(), facets.end(), + [&]( const Facet& facet ) // CJTODO: lambdas ok? { - // Iterate on vertices - int k = fit->second; - for ( int i=1 ; i<4 ; ++i ) + // Update facet + c3t3_.remove_from_complex(facet); + updater(facet); + + // Update vertex_to_proj + if ( c3t3_.is_in_complex(facet) ) { - const Vertex_handle& v = fit->first->vertex((k+i)&3); - if ( c3t3_.in_dimension(v) > 2 ) - { - vertex_to_proj.insert - (std::make_pair(v, c3t3_.surface_patch_index(*fit))); + // Iterate on vertices + int k = facet.second; + for ( int i=1 ; i<4 ; ++i ) + { + const Vertex_handle& v = facet.first->vertex((k+i)&3); + if ( c3t3_.in_dimension(v) > 2 ) + { + std::pair p + = std::make_pair(v, c3t3_.surface_patch_index(facet)); + tbb::mutex::scoped_lock lock(mut_vertex_to_proj); + vertex_to_proj.insert(p); + } + } + } + }); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + for ( typename Facet_vector::iterator fit = facets.begin() ; + fit != facets.end() ; + ++fit ) + { + // Update facet + c3t3_.remove_from_complex(*fit); + updater(*fit); + + // Update vertex_to_proj + if ( c3t3_.is_in_complex(*fit) ) + { + // Iterate on vertices + int k = fit->second; + for ( int i=1 ; i<4 ; ++i ) + { + const Vertex_handle& v = fit->first->vertex((k+i)&3); + if ( c3t3_.in_dimension(v) > 2 ) + { + vertex_to_proj.insert + (std::make_pair(v, c3t3_.surface_patch_index(*fit))); + } } } } @@ -1858,6 +2186,7 @@ move_point(const Vertex_handle& old_vertex, } } +// Sequential template typename C3T3_helpers::Vertex_handle C3T3_helpers:: @@ -1891,12 +2220,138 @@ move_point(const Vertex_handle& old_vertex, } } +// Parallel +// In case of success (could_lock_zone = true), the zone is locked after the call +// ==> the caller needs to call "unlock_all_elements" by itself +// In case of failure (could_lock_zone = false), the zone is unlocked by this function +template +typename C3T3_helpers::Vertex_handle +C3T3_helpers:: +move_point(const Vertex_handle& old_vertex, + const Point_3& new_position, + Outdated_cell_set& outdated_cells_set, + Moving_vertices_set& moving_vertices, + bool *p_could_lock_zone) +{ + CGAL_assertion(p_could_lock_zone != 0); + *p_could_lock_zone = true; + + Cell_vector incident_cells; + incident_cells.reserve(64); + if (!try_lock_vertex(old_vertex)) // LOCK + { + *p_could_lock_zone = false; + unlock_all_elements(); + return Vertex_handle(); + } + + //======= Get incident cells ========== + //tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); + Cell_handle d = old_vertex->cell(); + if (!try_lock_element(d)) // LOCK + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(incident_cells.begin(), incident_cells.end())) + { + ch->tds_data().clear(); + } + *p_could_lock_zone = false; + unlock_all_elements(); + return Vertex_handle(); + } + incident_cells.push_back(d); + d->tds_data().mark_in_conflict(); + int head=0; + int tail=1; + do { + Cell_handle c = incident_cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == old_vertex) + continue; + Cell_handle next = c->neighbor(i); + if (!try_lock_element(next)) // LOCK + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(incident_cells.begin(), incident_cells.end())) + { + ch->tds_data().clear(); + } + *p_could_lock_zone = false; + unlock_all_elements(); + return Vertex_handle(); + } + if (! next->tds_data().is_clear()) + continue; + incident_cells.push_back(next); + ++tail; + next->tds_data().mark_in_conflict(); + } + ++head; + } while(head != tail); + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(incident_cells.begin(), incident_cells.end())) + { + ch->tds_data().clear(); + } + //======= /Get incident cells ========== + + if (!try_lock_point(new_position)) // LOCK + { + *p_could_lock_zone = false; + unlock_all_elements(); + return Vertex_handle(); + } + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + { + BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells.begin(), + incident_cells.end())) + { + ch->invalidate_circumcenter(); + } + + tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK + std::copy(incident_cells.begin(),incident_cells.end(), + std::inserter(outdated_cells_set, outdated_cells_set.end())); + lock.release(); // CJTODO LOCK + + Vertex_handle new_vertex = move_point_no_topo_change(old_vertex, new_position); + + // Don't "unlock_all_elements" here, the caller may need it to do it himself + return new_vertex; + } + else + { + //moving_vertices.erase(old_vertex); MOVED BELOW + + Vertex_handle new_vertex = + move_point_topo_change(old_vertex, new_position, outdated_cells_set, + p_could_lock_zone); + + if (*p_could_lock_zone == false) + { + unlock_all_elements(); + return Vertex_handle(); + } + + + tbb::mutex::scoped_lock lock(mut_moving_vertices); // CJTODO LOCK + moving_vertices.erase(old_vertex); + moving_vertices.insert(new_vertex); + lock.release(); + + // Don't "unlock_all_elements" here, the caller may need it to do it itself + return new_vertex; + } +} + template typename C3T3_helpers::Vertex_handle C3T3_helpers:: move_point_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, - Outdated_cell_set& outdated_cells_set) + Outdated_cell_set& outdated_cells_set, + bool *p_could_lock_zone) { Cell_set insertion_conflict_cells; Cell_set removal_conflict_cells; @@ -1906,14 +2361,20 @@ move_point_topo_change(const Vertex_handle& old_vertex, get_conflict_zone_topo_change(old_vertex, new_position, std::inserter(insertion_conflict_cells,insertion_conflict_cells.end()), std::back_inserter(insertion_conflict_boundary), - std::inserter(removal_conflict_cells, removal_conflict_cells.end())); - + std::inserter(removal_conflict_cells, removal_conflict_cells.end()), + p_could_lock_zone); + + if (p_could_lock_zone && *p_could_lock_zone == false) + return Vertex_handle(); + + tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK for(typename Cell_set::iterator it = insertion_conflict_cells.begin(); it != insertion_conflict_cells.end(); ++it) outdated_cells_set.erase(*it); for(typename Cell_set::iterator it = removal_conflict_cells.begin(); it != removal_conflict_cells.end(); ++it) outdated_cells_set.erase(*it); + lock.release(); Cell_vector outdated_cells; Vertex_handle nv = move_point_topo_change_conflict_zone_known(old_vertex, new_position, @@ -1924,10 +2385,12 @@ move_point_topo_change(const Vertex_handle& old_vertex, removal_conflict_cells.end(), std::back_inserter(outdated_cells), CGAL::Emptyset_iterator()); // deleted_cells - + + lock.acquire(mut_outdated_cells); for(typename Cell_vector::iterator it = outdated_cells.begin(); it != outdated_cells.end(); ++it) outdated_cells_set.insert(*it); + lock.release(); return nv; } @@ -1960,6 +2423,7 @@ move_point_topo_change(const Vertex_handle& old_vertex, removal_conflict_cells.end(), outdated_cells, deleted_cells); + return nv; } @@ -1996,10 +2460,6 @@ move_point_topo_change_conflict_zone_known( int dimension = c3t3_.in_dimension(old_vertex); Index vertex_index = c3t3_.index(old_vertex); FT meshing_info = old_vertex->meshing_info(); -#ifdef CGAL_INTRUSIVE_LIST - Vertex_handle next = old_vertex->next_intrusive(); - Vertex_handle prev = old_vertex->previous_intrusive(); -#endif // insert new point Vertex_handle new_vertex = tr_.insert_in_hole(new_position, @@ -2020,10 +2480,6 @@ move_point_topo_change_conflict_zone_known( c3t3_.set_dimension(new_vertex,dimension); c3t3_.set_index(new_vertex,vertex_index); new_vertex->set_meshing_info(meshing_info); -#ifdef CGAL_INTRUSIVE_LIST - new_vertex->next_intrusive() = next; - new_vertex->previous_intrusive() = prev; -#endif // End Move point //// Fill outdated_cells @@ -2119,10 +2575,6 @@ move_point_topo_change(const Vertex_handle& old_vertex, c3t3_.set_dimension(new_vertex,dimension); c3t3_.set_index(new_vertex,vertex_index); new_vertex->set_meshing_info(meshing_info); -#ifdef CGAL_INTRUSIVE_LIST - new_vertex->next_intrusive() = next; - new_vertex->previous_intrusive() = prev; -#endif return new_vertex; } @@ -2136,7 +2588,11 @@ move_point_no_topo_change(const Vertex_handle& old_vertex, const Point_3& new_position, OutdatedCellsOutputIterator outdated_cells) { + + tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK get_conflict_zone_no_topo_change(old_vertex, outdated_cells); + lock.release(); // CJTODO LOCK + return move_point_no_topo_change(old_vertex, new_position); } @@ -2496,16 +2952,22 @@ get_conflict_zone_topo_change(const Vertex_handle& v, const Point_3& conflict_point, CellsOutputIterator insertion_conflict_cells, FacetsOutputIterator insertion_conflict_boundary, - CellsOutputIterator removal_conflict_cells) const + CellsOutputIterator removal_conflict_cells, + bool *p_could_lock_zone) const { // Get triangulation_vertex incident cells : removal conflict zone + // CJTODO: hasn't it already been computed in "move_point"? tr_.incident_cells(v, removal_conflict_cells); // Get conflict_point conflict zone int li=0; int lj=0; typename Tr::Locate_type lt; - Cell_handle cell = tr_.locate(conflict_point, lt, li, lj, v->cell()); + Cell_handle cell = tr_.locate( + conflict_point, lt, li, lj, v->cell(), p_could_lock_zone); + + if (p_could_lock_zone && *p_could_lock_zone == false) + return; if ( lt == Tr::VERTEX ) // Vertex removal is forbidden return; @@ -2514,7 +2976,8 @@ get_conflict_zone_topo_change(const Vertex_handle& v, tr_.find_conflicts(conflict_point, cell, insertion_conflict_boundary, - insertion_conflict_cells); + insertion_conflict_cells, + p_could_lock_zone); } template diff --git a/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h b/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h index 82b2c3abbca..e81537d2ea0 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h +++ b/Mesh_3/include/CGAL/Mesh_3/Lloyd_move.h @@ -102,7 +102,8 @@ public: return CGAL::NULL_VECTOR; } -#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE +#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \ + || defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA) static std::string name() { return std::string("Lloyd"); } #endif diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h index c5e058ee87b..c85ee86ccd0 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h @@ -33,25 +33,189 @@ #include #include #include +#include + +#include +#include + +#ifdef MESH_3_PROFILING + #include +#endif #include #include +#include #include #include +#ifdef CGAL_LINKED_WITH_TBB +# include +# include +# include +#endif + namespace CGAL { namespace Mesh_3 { + +/************************************************ +// Class Mesh_global_optimizer_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Mesh_global_optimizer_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + + typedef std::vector > Moves_vector; + typedef unsigned int Nb_frozen_points_type ; + + Mesh_global_optimizer_base(const Bbox_3 &, int) + : big_moves_size_(0) {} + + void update_big_moves(const FT& new_sq_move) + { + if (big_moves_.size() < big_moves_size_ ) + big_moves_.insert(new_sq_move); + else + { + FT smallest = *(big_moves_.begin()); + if( new_sq_move > smallest ) + { + big_moves_.erase(big_moves_.begin()); + big_moves_.insert(new_sq_move); + } + } + } + + void clear_big_moves() + { + big_moves_.clear(); + } + + LockDataStructureType *get_lock_data_structure() { return 0; } + void unlock_all_elements() {} + +protected: + std::size_t big_moves_size_; + std::multiset big_moves_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Mesh_global_optimizer_base +{ +protected: + typedef typename Tr::Geom_traits Gt; + typedef typename Gt::FT FT; + typedef tbb::concurrent_vector > Moves_vector; + typedef tbb::atomic Nb_frozen_points_type ; + + Mesh_global_optimizer_base(const Bbox_3 &bbox, int num_grid_cells_per_axis) + : big_moves_size_(0) + , m_lock_ds(bbox, num_grid_cells_per_axis) + { + big_moves_current_size_ = 0; + big_moves_smallest_ = std::numeric_limits::max(); + } + + void update_big_moves(const FT& new_sq_move) + { + static tbb::mutex mut; + + if (++big_moves_current_size_ <= big_moves_size_ ) + { + tbb::mutex::scoped_lock lock(mut); + std::multiset::const_iterator it = big_moves_.insert(new_sq_move); + + // New smallest move of all big moves? + if (it == big_moves_.begin()) + big_moves_smallest_ = new_sq_move; + } + else + { + --big_moves_current_size_; + + if( new_sq_move > big_moves_smallest_ ) + { + tbb::mutex::scoped_lock lock(mut); + // Test it again since it may have been modified by another + // thread in the meantime + if( new_sq_move > big_moves_smallest_ ) + { + big_moves_.erase(big_moves_.begin()); + std::multiset::const_iterator it = big_moves_.insert(new_sq_move); + + // New smallest move of all big moves? + if (it == big_moves_.begin()) + big_moves_smallest_ = new_sq_move; + } + } + } + } + + void clear_big_moves() + { + big_moves_current_size_ = 0; + big_moves_smallest_ = std::numeric_limits::max(); + big_moves_.clear(); + } + + LockDataStructureType *get_lock_data_structure() + { + return &m_lock_ds; + } + + void unlock_all_elements() + { + m_lock_ds.unlock_all_tls_locked_cells(); + } + +public: + +protected: + tbb::atomic big_moves_current_size_; + tbb::atomic big_moves_smallest_; + std::size_t big_moves_size_; + std::multiset big_moves_; + + /// Lock data structure + LockDataStructureType m_lock_ds; +}; +#endif // CGAL_LINKED_WITH_TBB + + + + +/************************************************ +// Class Mesh_global_optimizer +************************************************/ template > class Mesh_global_optimizer -{ +: public Mesh_global_optimizer_base +{ // Types + typedef typename C3T3::Concurrency_tag Concurrency_tag; + + typedef Mesh_global_optimizer Self; + typedef Mesh_global_optimizer_base< + typename C3T3::Triangulation, typename C3T3::Concurrency_tag> Base; + + using Base::get_lock_data_structure; + typedef typename C3T3::Triangulation Tr; typedef typename Tr::Geom_traits Gt; @@ -67,7 +231,6 @@ class Mesh_global_optimizer typedef typename std::vector Cell_vector; typedef typename std::vector Vertex_vector; typedef typename std::set Vertex_set; - typedef std::vector > Moves_vector; #ifdef CGAL_INTRUSIVE_LIST typedef Intrusive_list Outdated_cell_set; @@ -135,11 +298,6 @@ private: */ Vector_3 compute_move(const Vertex_handle& v); - /** - * update big_moves_ vector with new_sq_move value - */ - void update_big_moves(const FT& new_sq_move); - /** * Updates mesh using moves of \c moves vector. Updates moving_vertices with * the new set of moving vertices after the move. @@ -197,11 +355,8 @@ private: double time_limit_; CGAL::Timer running_time_; - std::size_t big_moves_size_; - std::set big_moves_; - bool do_freeze_; - mutable unsigned int nb_frozen_points_; + mutable Nb_frozen_points_type nb_frozen_points_; #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE mutable FT sum_moves_; @@ -217,27 +372,30 @@ Mesh_global_optimizer(C3T3& c3t3, const bool do_freeze, const FT& convergence_ratio, const Mf move_function) -: c3t3_(c3t3) +: Base(c3t3.bbox(), + Concurrent_mesher_config::get().locking_grid_num_cells_per_axis) +, c3t3_(c3t3) , tr_(c3t3_.triangulation()) , domain_(domain) , sq_freeze_ratio_(freeze_ratio*freeze_ratio) , convergence_ratio_(convergence_ratio) -, helper_(c3t3_,domain_) +, helper_(c3t3_,domain_, get_lock_data_structure()) , move_function_(move_function) , sizing_field_(c3t3.triangulation()) , time_limit_(-1) , running_time_() -, big_moves_size_(0) -, big_moves_() - , do_freeze_(do_freeze) -, nb_frozen_points_(0) #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE , sum_moves_(0) #endif // CGAL_MESH_3_OPTIMIZER_VERBOSE { + nb_frozen_points_ = 0; // We put it here in case it's an "atomic" + + // If we're multi-thread + tr_.set_lock_data_structure(get_lock_data_structure()); + #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE std::cerr << "Fill sizing field..."; CGAL::Timer timer; @@ -280,7 +438,7 @@ operator()(int nb_iterations, Visitor visitor) #endif //CGAL_MESH_3_OPTIMIZER_VERBOSE // Initialize big moves (stores the largest moves) - big_moves_.clear(); + clear_big_moves(); big_moves_size_ = (std::max)(std::size_t(1), std::size_t(moving_vertices.size()/500)); @@ -321,7 +479,7 @@ operator()(int nb_iterations, Visitor visitor) visitor.end_of_iteration(i); #ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE - unsigned int moving_vertices_size = moving_vertices.size(); + size_t moving_vertices_size = moving_vertices.size(); std::cerr << boost::format("\r \r" "end iter.%1%, %2% / %3%, last step:%4$.2fs, step avg:%5$.2fs, avg big moves:%6$.3f ") % (i+1) @@ -358,6 +516,10 @@ operator()(int nb_iterations, Visitor visitor) << "s" << std::endl << std::endl; #endif +#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + CGAL_MESH_3_SET_PERFORMANCE_DATA(std::string(Mf::name()) + "_optim_time", running_time_.time()); +#endif + if ( do_freeze_ && nb_frozen_points_ == initial_vertices_nb ) return ALL_VERTICES_FROZEN; @@ -396,37 +558,98 @@ compute_moves(Moving_vertices_set& moving_vertices) moves.reserve(moving_vertices.size()); // reset worst_move list - big_moves_.clear(); + clear_big_moves(); - // Get move for each moving vertex - typename Moving_vertices_set::iterator vit = moving_vertices.begin(); - for ( ; vit != moving_vertices.end() ; ) - { - Vertex_handle oldv = *vit; - Vector_3 move = compute_move(oldv); - ++vit; - - if ( CGAL::NULL_VECTOR != move ) - { - Point_3 new_position = translate(oldv->point(),move); - moves.push_back(std::make_pair(oldv,new_position)); - } - else // CGAL::NULL_VECTOR == move - { - if(do_freeze_) - moving_vertices.erase(oldv); - } +#ifdef MESH_3_PROFILING + std::cerr << "Computing moves..."; + WallClockTimer t; +#endif - // Stop if time_limit_ is reached - if ( is_time_limit_reached() ) - break; - } + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) + { + tbb::concurrent_vector vertices_not_moving_any_more; + + // Get move for each moving vertex + tbb::parallel_do(moving_vertices.begin(), moving_vertices.end(), + [&]( const Vertex_handle& oldv ) // CJTODO: lambdas ok? + { + Vector_3 move = compute_move(oldv); + + if ( CGAL::NULL_VECTOR != move ) + { + Point_3 new_position = translate(oldv->point(),move); + FT size = (Mesh_global_optimizer::Sizing_field::is_vertex_update_needed ? + sizing_field_(new_position, oldv) : 0); + moves.push_back(std::make_tuple(oldv,new_position,size)); + } + else // CGAL::NULL_VECTOR == move + { + if(this->do_freeze_) + { + vertices_not_moving_any_more.push_back(oldv); + } + } + + // CJTODO TEMP : ŕ remettre (comment ?) + // Stop if time_limit_ is reached + //if ( is_time_limit_reached() ) + // break; + }); + + tbb::concurrent_vector::const_iterator it + = vertices_not_moving_any_more.begin(); + tbb::concurrent_vector::const_iterator it_end + = vertices_not_moving_any_more.end(); + for ( ; it != it_end ; ++it) + { + moving_vertices.erase(*it); + } + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + // Get move for each moving vertex + typename Moving_vertices_set::iterator vit = moving_vertices.begin(); + for ( ; vit != moving_vertices.end() ; ) + { + Vertex_handle oldv = *vit; + ++vit; + Vector_3 move = compute_move(oldv); + + if ( CGAL::NULL_VECTOR != move ) + { + Point_3 new_position = translate(oldv->point(),move); + FT size = (Sizing_field::is_vertex_update_needed ? + sizing_field_(new_position, oldv) : 0); + moves.push_back(std::make_tuple(oldv,new_position,size)); + } + else // CGAL::NULL_VECTOR == move + { + if(do_freeze_) + moving_vertices.erase(oldv); // CJTODO: si non-intrusive, + //on peut optimiser en passant l'itérateur, + // et il faut faire "vit = mv.erase(vit)" au lieu de ++vit + } + + // Stop if time_limit_ is reached + if ( is_time_limit_reached() ) + break; + } + } + +#ifdef MESH_3_PROFILING + std::cerr << "done in " << t.elapsed() << " seconds." << std::endl; +#endif return moves; } - - - + + + template typename Mesh_global_optimizer::Vector_3 Mesh_global_optimizer:: @@ -467,33 +690,14 @@ compute_move(const Vertex_handle& v) nb_frozen_points_++; return CGAL::NULL_VECTOR; } - + // Update big moves update_big_moves(local_move_sq_ratio); return move; } - -template -void -Mesh_global_optimizer:: -update_big_moves(const FT& new_sq_move) -{ - if (big_moves_.size() < big_moves_size_ ) - big_moves_.insert(new_sq_move); - else - { - FT smallest = *(big_moves_.begin()); - if( new_sq_move > smallest ) - { - big_moves_.erase(big_moves_.begin()); - big_moves_.insert(new_sq_move); - } - } -} - - + template void Mesh_global_optimizer:: @@ -504,36 +708,109 @@ update_mesh(const Moves_vector& moves, // Cells which have to be updated Outdated_cell_set outdated_cells; - // Apply moves in triangulation - for ( typename Moves_vector::const_iterator it = moves.begin() ; - it != moves.end() ; - ++it ) +#ifdef MESH_3_PROFILING + std::cerr << "Moving vertices..."; + WallClockTimer t; +#endif + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) { - const Vertex_handle& v = it->first; - const Point_3& new_position = it->second; - // Get size at new position - if ( Sizing_field::is_vertex_update_needed ) + // Apply moves in triangulation + tbb::parallel_for(tbb::blocked_range(0, moves.size()), + [&]( const tbb::blocked_range& r ) // CJTODO: lambdas ok? { - FT size = sizing_field_(new_position,v); - - // Move point - Vertex_handle new_v = helper_.move_point(v, new_position, outdated_cells, moving_vertices); + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + const Vertex_handle& v = cpp11::get<0>(moves[i]); + const Point_3& new_position = cpp11::get<1>(moves[i]); + // Get size at new position + if ( Self::Sizing_field::is_vertex_update_needed ) + { + //FT size = sizing_field_(new_position,v); + FT size = cpp11::get<2>(moves[i]); - // Restore size in meshing_info data - new_v->set_meshing_info(size); - } - else // Move point - { - helper_.move_point(v, new_position, outdated_cells, moving_vertices); - } + // Move point + bool could_lock_zone; + Vertex_handle new_v = helper_.move_point( + v, new_position, outdated_cells, moving_vertices, &could_lock_zone); + while (could_lock_zone == false) + { + new_v = helper_.move_point( + v, new_position, outdated_cells, moving_vertices, &could_lock_zone); + } + + // Restore size in meshing_info data + new_v->set_meshing_info(size); + } + else // Move point + { + bool could_lock_zone; + do { + helper_.move_point( + v, new_position, outdated_cells, moving_vertices, &could_lock_zone); + } while (!could_lock_zone); + } + + unlock_all_elements(); - // Stop if time_limit_ is reached, here we can't return without rebuilding - // restricted delaunay - if ( is_time_limit_reached() ) - break; + // CJTODO : ŕ remettre (comment ?) + // Stop if time_limit_ is reached, here we can't return without rebuilding + // restricted delaunay + /*if ( is_time_limit_reached() ) + break;*/ + } + }); } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + // Apply moves in triangulation + for ( typename Moves_vector::const_iterator it = moves.begin() ; + it != moves.end() ; + ++it ) + { + const Vertex_handle& v = cpp11::get<0>(*it); + const Point_3& new_position = cpp11::get<1>(*it); + // Get size at new position + if ( Sizing_field::is_vertex_update_needed ) + { + //FT size = sizing_field_(new_position,v); + FT size = cpp11::get<2>(*it); + + // Move point + Vertex_handle new_v = helper_.move_point(v, new_position, outdated_cells, moving_vertices); + + // Restore size in meshing_info data + new_v->set_meshing_info(size); + } + else // Move point + { + helper_.move_point(v, new_position, outdated_cells, moving_vertices); + } + + // Stop if time_limit_ is reached, here we can't return without rebuilding + // restricted delaunay + if ( is_time_limit_reached() ) + break; + } + } + + visitor.after_move_points(); +#ifdef MESH_3_PROFILING + std::cerr << "done in " << t.elapsed() << " seconds." << std::endl; +#endif + + +#ifdef MESH_3_PROFILING + std::cerr << "Updating C3T3 (rebuilding restricted Delaunay)..."; + t.reset(); +#endif + // Update c3t3 #ifdef CGAL_INTRUSIVE_LIST // AF: rebuild_restricted_delaunay does more cell insertion/removal @@ -548,6 +825,11 @@ update_mesh(const Moves_vector& moves, #endif visitor.after_rebuild_restricted_delaunay(); + +#ifdef MESH_3_PROFILING + std::cerr << "Updating C3T3 done in " << t.elapsed() << " seconds." << std::endl; +#endif + } @@ -580,7 +862,7 @@ check_convergence() const namespace bl = boost::lambda; FT sum(0); - for( typename std::set::const_iterator + for( typename std::multiset::const_iterator it = big_moves_.begin(), end = big_moves_.end() ; it != end ; ++it ) { sum += CGAL::sqrt(*it); diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h index f18d9050d92..f10a6c039ab 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_sizing_field.h @@ -26,16 +26,68 @@ #ifndef CGAL_MESH_3_MESH_SIZING_FIELD_H #define CGAL_MESH_3_MESH_SIZING_FIELD_H +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + namespace CGAL { namespace Mesh_3 { +/** + * @class Mesh_sizing_field_base + */ +// Sequential +template +class Mesh_sizing_field_base +{ +protected: + Cell_handle get_last_cell() const + { + return last_cell_; + } + + void set_last_cell(Cell_handle c) const + { + last_cell_ = c; + } + + /// A cell that is used to accelerate location queries + mutable Cell_handle last_cell_; +}; + +#ifdef CGAL_LINKED_WITH_TBB +/** + * @class Mesh_sizing_field_base specialization + */ +// Parallel +template +class Mesh_sizing_field_base +{ +protected: + Cell_handle get_last_cell() const + { + return last_cell_.local(); + } + + void set_last_cell(Cell_handle c) const + { + last_cell_.local() = c; + } + + /// A cell that is used to accelerate location queries + mutable tbb::enumerable_thread_specific last_cell_; +}; +#endif // CGAL_LINKED_WITH_TBB + /** * @class Mesh_sizing_field */ template class Mesh_sizing_field + : public Mesh_sizing_field_base { // Types typedef typename Tr::Geom_traits Gt; @@ -64,7 +116,7 @@ public: * Returns size at point \c p. */ FT operator()(const Point_3& p) const - { return this->operator()(p,last_cell_); } + { return this->operator()(p, get_last_cell()); } /** * Returns size at point \c p, using \c v to accelerate \c p location @@ -96,12 +148,10 @@ private: */ FT interpolate_on_facet_vertices(const Point_3& p, const Cell_handle& cell) const; - + private: /// The triangulation Tr& tr_; - /// A cell that is used to accelerate location queries - mutable Cell_handle last_cell_; }; @@ -110,7 +160,6 @@ template Mesh_sizing_field:: Mesh_sizing_field(Tr& tr) : tr_(tr) - , last_cell_() { } @@ -164,7 +213,7 @@ operator()(const Point_3& p, const Cell_handle& c) const #else const Cell_handle cell = tr_.locate(p,c); #endif - last_cell_ = cell; + set_last_cell(cell); if ( !tr_.is_infinite(cell) ) return interpolate_on_cell_vertices(p,cell); diff --git a/Mesh_3/include/CGAL/Mesh_3/Odt_move.h b/Mesh_3/include/CGAL/Mesh_3/Odt_move.h index 19ef341c497..46de71ae04e 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Odt_move.h +++ b/Mesh_3/include/CGAL/Mesh_3/Odt_move.h @@ -113,8 +113,8 @@ public: return CGAL::NULL_VECTOR; } - -#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE +#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \ + || defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA) static std::string name() { return std::string("Odt"); } #endif diff --git a/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h b/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h index 88002c5e247..f085a102614 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h +++ b/Mesh_3/include/CGAL/Mesh_3/Sliver_perturber.h @@ -433,6 +433,10 @@ operator()(const FT& sliver_bound, const FT& delta, Visitor visitor) std::cerr << std::endl << "Perturbation statistics:" << std::endl; print_final_perturbations_statistics(); #endif + +#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + CGAL_MESH_3_SET_PERFORMANCE_DATA("Perturber_optim_time", running_time_.time()); +#endif if ( is_time_limit_reached() ) { #ifdef CGAL_MESH_3_PERTURBER_VERBOSE diff --git a/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h b/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h index 55d209f615f..7d0300a1ad7 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h +++ b/Mesh_3/include/CGAL/Mesh_3/Slivers_exuder.h @@ -627,6 +627,10 @@ pump_vertices(double sliver_criterion_limit, std::cerr << std::endl; #endif // CGAL_MESH_3_EXUDER_VERBOSE +#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA + CGAL_MESH_3_SET_PERFORMANCE_DATA("Exuder_optim_time", running_time_.time()); +#endif + if ( is_time_limit_reached() ) { #ifdef CGAL_MESH_3_EXUDER_VERBOSE std::cerr << "Exuding return code: TIME_LIMIT_REACHED\n\n"; diff --git a/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h b/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h index 83de42e7cfb..4feee94ffb0 100644 --- a/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_data_structure_3.h @@ -79,6 +79,8 @@ class Triangulation_data_structure_3 typedef Triangulation_data_structure_3 Tds; public: + + static const bool Is_for_parallel_mesh_3 = used_by_parallel_mesh_3; // Tools to change the Vertex and Cell types of the TDS. template < typename Vb2 > diff --git a/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h b/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h index add670e11c2..146e78d21f4 100644 --- a/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h @@ -27,10 +27,50 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB +# include +#endif + namespace CGAL { + +/************************************************ +// Class Triangulation_ds_cell_base_3_base +// Two versions: sequential / parallel +************************************************/ + +// Sequential +template +class Triangulation_ds_cell_base_3_base +{ +public: + // TDS internal data access functions. + TDS_data& tds_data() { return _tds_data; } + const TDS_data& tds_data() const { return _tds_data; } + +protected: + TDS_data _tds_data; +}; + +#ifdef CGAL_LINKED_WITH_TBB +// Parallel +template +class Triangulation_ds_cell_base_3_base +{ +public: + // TDS internal data access functions. + TDS_data& tds_data() { return _tds_data.local(); } + const TDS_data& tds_data() const { return _tds_data.local(); } + +protected: + tbb::enumerable_thread_specific _tds_data; +}; +#endif // CGAL_LINKED_WITH_TBB + template < typename TDS = void > class Triangulation_ds_cell_base_3 + : public Triangulation_ds_cell_base_3_base { public: typedef TDS Triangulation_data_structure; @@ -198,15 +238,10 @@ public: void * for_compact_container() const { return N[0].for_compact_container(); } void * & for_compact_container() { return N[0].for_compact_container(); } - // TDS internal data access functions. - TDS_data& tds_data() { return _tds_data; } - const TDS_data& tds_data() const { return _tds_data; } - private: Cell_handle N[4]; Vertex_handle V[4]; - TDS_data _tds_data; }; template < class TDS >