From 461fb7721cfdd7a2989bbacd71a7076d727e5eeb Mon Sep 17 00:00:00 2001 From: David Wells Date: Sun, 3 Feb 2019 22:35:36 -0500 Subject: [PATCH] Cleanup the Vector::thread_loop_partitioner logic. It was previously possible to, in one function call, either set up the partitioner multiple times or for inappropriately small vectors. This commit cleans up the way we handle the partitioner in multiple places so that, when possible, vectors share partitioners and do not set up partitioners if they are too small. --- include/deal.II/lac/vector.h | 20 +++- include/deal.II/lac/vector.templates.h | 123 +++++++++++++------------ 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index 2dadf1da5e..b413f686b1 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -986,6 +986,22 @@ private: */ AlignedVector values; + /** + * Convenience function used at the end of initialization or + * reinitialization. Resets (if necessary) the loop partitioner to the + * correct state, based on its current state and the length of the vector. + */ + void + maybe_reset_thread_partitioner(); + + /** + * Actual implementation of the reinit functions. + */ + void + do_reinit(const size_type new_size, + const bool omit_zeroing_entries, + const bool reset_partitioner); + /** * For parallel loops with TBB, this member variable stores the affinity * information of loops. @@ -1275,7 +1291,8 @@ template inline void Vector::swap(Vector &v) { - std::swap(values, v.values); + values.swap(v.values); + std::swap(thread_loop_partitioner, v.thread_loop_partitioner); } @@ -1300,6 +1317,7 @@ Vector::load(Archive &ar, const unsigned int) // the load stuff again from the archive ar &static_cast(*this); ar &values; + maybe_reset_thread_partitioner(); } #endif diff --git a/include/deal.II/lac/vector.templates.h b/include/deal.II/lac/vector.templates.h index 87c126c8b8..bc98f73050 100644 --- a/include/deal.II/lac/vector.templates.h +++ b/include/deal.II/lac/vector.templates.h @@ -83,6 +83,11 @@ namespace internal copy_petsc_vector(const PETScWrappers::VectorBase &v, ::dealii::Vector & out) { + if (v.size() == 0) + { + out.reinit(0); + return; + } // Create a sequential PETSc vector and then copy over the entries into // the deal.II vector. Vec sequential_vector; @@ -125,10 +130,7 @@ namespace internal template Vector::Vector(const PETScWrappers::VectorBase &v) { - if (v.size() != 0) - { - internal::copy_petsc_vector(v, *this); - } + internal::copy_petsc_vector(v, *this); } #endif @@ -164,6 +166,8 @@ Vector::Vector(const TrilinosWrappers::MPI::Vector &v) AssertThrow(ierr == 0, ExcTrilinosError(ierr)); std::copy(start_ptr[0], start_ptr[0] + size(), begin()); + + maybe_reset_thread_partitioner(); } } @@ -177,7 +181,6 @@ Vector::operator=(const Vector &v) if (PointerComparison::equal(this, &v)) return *this; - thread_loop_partitioner = v.thread_loop_partitioner; if (size() != v.size()) reinit(v, true); @@ -201,7 +204,6 @@ template inline Vector & Vector::operator=(const Vector &v) { - thread_loop_partitioner = v.thread_loop_partitioner; if (size() != v.size()) reinit(v, true); @@ -221,41 +223,7 @@ template inline void Vector::reinit(const size_type n, const bool omit_zeroing_entries) { - const std::size_t old_size = size(); - - // avoid allocating if the new size is not larger than the old size - if (n <= size()) - { - thread_loop_partitioner = - std::make_shared(); - if (n == 0) - { - values.clear(); - } - else if (n != size()) - values.resize_fast(n); - - if (!omit_zeroing_entries) - values.fill(); - return; - } - - // otherwise size() < n and we must allocate - AlignedVector new_values; - new_values.resize_fast(n); - if (!omit_zeroing_entries) - new_values.fill(); - new_values.swap(values); - - if (old_size != size()) - { - // only reset the partitioner if we actually expect a significant vector - // size - if (size() >= - 4 * internal::VectorImplementation::minimum_parallel_grain_size) - thread_loop_partitioner = - std::make_shared(); - } + do_reinit(n, omit_zeroing_entries, true); } @@ -264,26 +232,9 @@ template inline void Vector::grow_or_shrink(const size_type n) { - const std::size_t old_size = size(); - if (n == 0) - { - values.clear(); - thread_loop_partitioner = - std::make_shared(); - return; - } - values.resize(n); - if (old_size != n) - { - // only reset the partitioner if we actually expect a significant vector - // size - if (size() >= - 4 * internal::VectorImplementation::minimum_parallel_grain_size) - thread_loop_partitioner = - std::make_shared(); - } + maybe_reset_thread_partitioner(); } @@ -294,9 +245,8 @@ void Vector::reinit(const Vector &v, const bool omit_zeroing_entries) { + do_reinit(v.size(), omit_zeroing_entries, false); thread_loop_partitioner = v.thread_loop_partitioner; - - reinit(v.size(), omit_zeroing_entries); } @@ -1046,6 +996,57 @@ Vector::memory_consumption() const } + +template +void +Vector::maybe_reset_thread_partitioner() +{ + if (size() >= 4 * internal::VectorImplementation::minimum_parallel_grain_size) + { + if (thread_loop_partitioner == nullptr) + thread_loop_partitioner = + std::make_shared(); + } + else + thread_loop_partitioner.reset(); +} + + + +template +void +Vector::do_reinit(const size_type new_size, + const bool omit_zeroing_entries, + const bool reset_partitioner) +{ + if (new_size <= size()) + { + if (new_size == 0) + { + values.clear(); + } + else + { + values.resize_fast(new_size); + if (!omit_zeroing_entries) + values.fill(); + } + } + else + { + // otherwise size() < new_size and we must allocate + AlignedVector new_values; + new_values.resize_fast(new_size); + if (!omit_zeroing_entries) + new_values.fill(); + new_values.swap(values); + } + + if (reset_partitioner) + maybe_reset_thread_partitioner(); +} + + DEAL_II_NAMESPACE_CLOSE #endif -- 2.39.5