]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Implement shrink_to_fit
authorMaximilian Bergbauer <maximilian.bergbauer@tum.de>
Fri, 8 Sep 2023 13:47:59 +0000 (15:47 +0200)
committerMaximilian Bergbauer <maximilian.bergbauer@tum.de>
Fri, 8 Sep 2023 13:52:42 +0000 (15:52 +0200)
include/deal.II/base/aligned_vector.h
tests/base/aligned_vector_01.cc
tests/base/aligned_vector_01.output

index a20feabea955ff180624d762a73d92bd73ecc393..9a13dfea1ccfdc2ee0d849f7a9b6b789fe2b9da1 100644 (file)
@@ -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<T>::resize(const size_type new_size, const T &init)
 
 
 
+template <class T>
+inline void
+AlignedVector<T>::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<void **>(&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<T>(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 <class T>
 inline void
 AlignedVector<T>::reserve(const size_type new_allocated_size)
@@ -1372,36 +1429,7 @@ AlignedVector<T>::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<void **>(&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<T>(
-          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<T>::reserve(const size_type new_allocated_size)
 
 
 
+template <class T>
+inline void
+AlignedVector<T>::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 <class T>
 inline void
 AlignedVector<T>::clear()
index c9f53bf0da0fd6d03195a4bcec898ecaf8342ed1..180e924da9bc873dde2998494fb51b8e9e34dc74 100644 (file)
@@ -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] << ' ';
index 1b934a82996c3f22536b42f0baca1020bb50822c..3139875e46bd53029e9b23d54bd4994667ca65cb 100644 (file)
@@ -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 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.