From 5843d24d45d1535b44c2df4ade5258e18bc5fb92 Mon Sep 17 00:00:00 2001 From: Maximilian Bergbauer Date: Fri, 8 Sep 2023 15:47:59 +0200 Subject: [PATCH] Implement shrink_to_fit --- include/deal.II/base/aligned_vector.h | 100 ++++++++++++++++++-------- tests/base/aligned_vector_01.cc | 4 ++ tests/base/aligned_vector_01.output | 1 + 3 files changed, 75 insertions(+), 30 deletions(-) diff --git a/include/deal.II/base/aligned_vector.h b/include/deal.II/base/aligned_vector.h index a20feabea9..9a13dfea1c 100644 --- a/include/deal.II/base/aligned_vector.h +++ b/include/deal.II/base/aligned_vector.h @@ -200,6 +200,12 @@ public: void reserve(const size_type new_allocated_size); + /** + * Releases the memory allocated but not used. + */ + void + shrink_to_fit(); + /** * Releases all previously allocated memory and leaves the vector in a state * equivalent to the state after the default constructor has been called. @@ -464,6 +470,15 @@ public: #endif private: + /** + * Allocates a new vector and moves the data from the old vector to the new + * vector. Deletes the old vector and releases the memory. + */ + void + allocate_and_move(const size_t old_size, + const size_t new_size, + const size_t new_allocated_size); + /** * A class that is used as the "deleter" for a `std::unique_ptr` object that * AlignedVector uses to store the memory used for the elements. @@ -1358,6 +1373,48 @@ AlignedVector::resize(const size_type new_size, const T &init) +template +inline void +AlignedVector::allocate_and_move(const size_t old_size, + const size_t new_size, + const size_t new_allocated_size) +{ + // allocate and align along 64-byte boundaries (this is enough for all + // levels of vectorization currently supported by deal.II) + T *new_data_ptr; + Utilities::System::posix_memalign(reinterpret_cast(&new_data_ptr), + 64, + new_size * sizeof(T)); + + // Now create a deleter that encodes what should happen when the object is + // released: We need to destroy the objects that are currently alive (in + // reverse order, and then release the memory. Note that we catch the + // 'this' pointer because the number of elements currently alive might + // change over time. + Deleter deleter(this); + + // copy whatever elements we need to retain + if (new_allocated_size > 0) + dealii::internal::AlignedVectorMoveConstruct(elements.get(), + elements.get() + old_size, + new_data_ptr); + + // Now reset all the member variables of the current object + // based on the allocation above. Assigning to a std::unique_ptr + // object also releases the previously pointed to memory. + // + // Note that at the time of releasing the old memory, 'used_elements_end' + // still points to its previous value, and this is important for the + // deleter object of the previously allocated array (see how it loops over + // the to-be-destroyed elements at the Deleter::DefaultDeleterAction + // class). + elements = decltype(elements)(new_data_ptr, std::move(deleter)); + used_elements_end = elements.get() + old_size; + allocated_elements_end = elements.get() + new_size; +} + + + template inline void AlignedVector::reserve(const size_type new_allocated_size) @@ -1372,36 +1429,7 @@ AlignedVector::reserve(const size_type new_allocated_size) const size_type new_size = std::max(new_allocated_size, 2 * old_allocated_size); - // allocate and align along 64-byte boundaries (this is enough for all - // levels of vectorization currently supported by deal.II) - T *new_data_ptr; - Utilities::System::posix_memalign( - reinterpret_cast(&new_data_ptr), 64, new_size * sizeof(T)); - - // Now create a deleter that encodes what should happen when the object is - // released: We need to destroy the objects that are currently alive (in - // reverse order, and then release the memory. Note that we catch the - // 'this' pointer because the number of elements currently alive might - // change over time. - Deleter deleter(this); - - // copy whatever elements we need to retain - if (new_allocated_size > 0) - dealii::internal::AlignedVectorMoveConstruct( - elements.get(), elements.get() + old_size, new_data_ptr); - - // Now reset all of the member variables of the current object - // based on the allocation above. Assigning to a std::unique_ptr - // object also releases the previously pointed to memory. - // - // Note that at the time of releasing the old memory, 'used_elements_end' - // still points to its previous value, and this is important for the - // deleter object of the previously allocated array (see how it loops over - // the to-be-destroyed elements a the Deleter::DefaultDeleterAction - // class). - elements = decltype(elements)(new_data_ptr, std::move(deleter)); - used_elements_end = elements.get() + old_size; - allocated_elements_end = elements.get() + new_size; + allocate_and_move(old_size, new_size, new_allocated_size); } else if (new_allocated_size == 0) clear(); @@ -1412,6 +1440,18 @@ AlignedVector::reserve(const size_type new_allocated_size) +template +inline void +AlignedVector::shrink_to_fit() +{ + const size_type used_size = used_elements_end - elements.get(); + const size_type allocated_size = allocated_elements_end - elements.get(); + if (allocated_size > used_size) + allocate_and_move(used_size, used_size, used_size); +} + + + template inline void AlignedVector::clear() diff --git a/tests/base/aligned_vector_01.cc b/tests/base/aligned_vector_01.cc index c9f53bf0da..180e924da9 100644 --- a/tests/base/aligned_vector_01.cc +++ b/tests/base/aligned_vector_01.cc @@ -45,7 +45,11 @@ test() deallog << a[i] << ' '; deallog << std::endl; + deallog << "Memory Shrinking: "; + deallog << a.memory_consumption() << " to "; a.resize(4); + a.shrink_to_fit(); + deallog << a.memory_consumption() << std::endl; deallog << "Shrinking: "; for (unsigned int i = 0; i < a.size(); ++i) deallog << a[i] << ' '; diff --git a/tests/base/aligned_vector_01.output b/tests/base/aligned_vector_01.output index 1b934a8299..3139875e46 100644 --- a/tests/base/aligned_vector_01.output +++ b/tests/base/aligned_vector_01.output @@ -1,6 +1,7 @@ DEAL::Constructor: 0 0 0 0 DEAL::Insertion: 0 0 1 0 5 42 0 0 1 0 5 42 27 +DEAL::Memory Shrinking: 104 to 56 DEAL::Shrinking: 0 0 1 0 DEAL::Reserve: 0 0 1 0 DEAL::Assignment: 0 0 1 0 5 42 27 -- 2.39.5