From 769f0fb209eea1e8331e1c7bcd19cf92065eee20 Mon Sep 17 00:00:00 2001
From: Stefen Guzik <guzik2@llnl.gov>
Date: Sat, 26 Jul 2008 01:28:23 +0000
Subject: [PATCH] Memory fix

---
 Geo/CustomContainer.h | 54 ++++++++++++++++++++++++++++++++++++-------
 Geo/GModelIO_CGNS.cpp |  4 ++++
 Geo/MZone.h           | 13 +++++++++++
 Geo/MZoneBoundary.cpp | 23 ++++++++++++++++++
 Geo/MZoneBoundary.h   | 30 ++++++++++++++++++++++++
 5 files changed, 116 insertions(+), 8 deletions(-)

diff --git a/Geo/CustomContainer.h b/Geo/CustomContainer.h
index c1553069fe..5f6ac7d606 100644
--- a/Geo/CustomContainer.h
+++ b/Geo/CustomContainer.h
@@ -73,16 +73,13 @@ class Pool
 
   // Constructor
   Pool(const unsigned _blockSize = 128)
-    : tailBlock(0), tailElement(0), blockSize(_blockSize)
+    : tailBlock(0), tailElement(0), blockSize(_blockSize), numUsedElement(0)
   { }
 
   // Destructor
-  ~Pool(){
-    while(tailBlock) {
-      Block<T> *const block = tailBlock;
-      tailBlock = block->prev;
-      delete block;
-    }
+  ~Pool()
+  {
+    delete_all_blocks();
   }
 
   // Get an element
@@ -91,6 +88,7 @@ class Pool
     if(!tailElement) create_block();
     void *const rval = tailElement;
     tailElement =  static_cast<T*>(tailElement->get_pool_prev());
+    ++numUsedElement;
     return rval;
   }
 
@@ -99,6 +97,13 @@ class Pool
   {
     elem->set_pool_prev(tailElement);
     tailElement = elem;
+    --numUsedElement;
+  }
+
+  // Free memory used by the pool
+  void free_memory()
+  {
+    if(numUsedElement == 0) delete_all_blocks();
   }
 
  private:
@@ -107,6 +112,7 @@ class Pool
   Block<T> *tailBlock;
   T *tailElement;
   unsigned blockSize;
+  unsigned numUsedElement;
 
   // Create a new block
   void create_block()
@@ -121,6 +127,16 @@ class Pool
     }
   }
 
+  // Delete all blocks
+  void delete_all_blocks()
+  {
+    while(tailBlock) {
+      Block<T> *const block = tailBlock;
+      tailBlock = block->prev;
+      delete block;
+    }
+  }
+
   // Copy and assignment are not permitted
   Pool(const Pool&);
   Pool &operator=(const Pool&);
@@ -200,6 +216,7 @@ class Block
  *   - No per-object data is stored as per normal requirements for allocators.
  *     Critical OpenMP sections are defined since multiple threads can access
  *     the allocator.
+ *   - If set_offsets is to be used, T must have a default constructor.
  *
  *============================================================================*/
 
@@ -292,6 +309,15 @@ class FaceAllocator
     offset16 = f16.get_offset();
   }
 
+  // Release memory used by the pools
+  static void free_pool_memory()
+  {
+    face2Pool.free_memory();
+    face6Pool.free_memory();
+    face8Pool.free_memory();
+    face16Pool.free_memory();
+  }
+
   // Allocate the array
   void allocate(const unsigned short nCapacity, T *&faces)
   {
@@ -503,6 +529,10 @@ ptrdiff_t FaceAllocator<T>::offset16 = 0;
  *   - The only way to add elements is by 'push_back'
  *   - Erasing may reorder the elements.
  *   - T must only contain primitive types
+ *   - init_memory() should be called before constructing any class
+ *     FaceVector<T> and release_memory() should be called after all classes
+ *     FaceVector<T> have been destroyed.  These routines explictly manage
+ *     memory used by pools in the allocator.
  *
  *============================================================================*/
 
@@ -551,9 +581,17 @@ class FaceVector : public FaceAllocator<T>
 
   // Vector size and capacity
   unsigned size() const { return _size; }
-
   unsigned capacity() const { return _capacity; }
 
+  // Memory managment
+  // Init sets offsets to ensure pointers can be recovered.  It should be called
+  // once before using FaceVector<T>
+  static void init_memory() { FaceAllocator<T>::set_offsets(); }
+  // This releases memory used by the pools if no pool elements are in use.  It
+  // should be called after use of FaceVector<T> is finished and all
+  // FaceVector<T> classes have been destroyed.
+  static void release_memory() { FaceAllocator<T>::free_pool_memory(); }
+
  private:
 
   // Data
diff --git a/Geo/GModelIO_CGNS.cpp b/Geo/GModelIO_CGNS.cpp
index 35a8e39510..a17d7113f0 100644
--- a/Geo/GModelIO_CGNS.cpp
+++ b/Geo/GModelIO_CGNS.cpp
@@ -278,12 +278,16 @@ int GModel::writeCGNS(const std::string &name, const int zoneDefinition,
 
   switch(meshDim) {
   case 2:
+    MZone<2>::preInit();
     write_CGNS_zones<2>(*this, zoneDefinition, options, scalingFactor,
                         vectorDim, groups[face], cgIndexFile, cgIndexBase);
+    MZone<2>::postDestroy();
     break;
   case 3:
+    MZone<3>::preInit();
     write_CGNS_zones<3>(*this, zoneDefinition, options, scalingFactor,
                         vectorDim, groups[region], cgIndexFile, cgIndexBase);
+    MZone<3>::postDestroy();
     break;
   }
 
diff --git a/Geo/MZone.h b/Geo/MZone.h
index 0c241057f1..71005908f7 100644
--- a/Geo/MZone.h
+++ b/Geo/MZone.h
@@ -310,6 +310,9 @@ template <> struct FaceTr<MFace> {
  * =====
  *
  *   - explicitly instantiated in 'MZone.cpp'
+ *   - this class uses some explicit memory management.  Call preInit() before
+ *     constructing any class MZone and postDestroy() after all MZone classes
+ *     have been destroyed.
  *
  ******************************************************************************/
 
@@ -410,7 +413,17 @@ class MZone
       if(zoneElemConn[iElemType].numElem > 0) ++numElemType;
     return numElemType;
   }
+  
+//--Memory management
 
+  static void preInit()
+  {
+    CCon::FaceVector<typename BoFaceMap::const_iterator>::init_memory();
+  }
+  static void postDestroy()
+  {
+    CCon::FaceVector<typename BoFaceMap::const_iterator>::release_memory();
+  }
 
 /*==============================================================================
  * Member data
diff --git a/Geo/MZoneBoundary.cpp b/Geo/MZoneBoundary.cpp
index 7027f31917..c84a4a2829 100644
--- a/Geo/MZoneBoundary.cpp
+++ b/Geo/MZoneBoundary.cpp
@@ -892,6 +892,29 @@ int MZoneBoundary<DIM>::exteriorBoundaryVertices
 }
 
 
+/*******************************************************************************
+ *
+ * Specialization of constructor
+ * MZoneBoundary<DIM>::GlobalVertexData<FaceT>::FaceDataB::FaceDataB()
+ * - Note that these dummy constructors are only required by
+ *   FaceAllocator<T>::set_offsets()
+ *   [with T = MZoneBoundary<DIM>::GlobalVertexData<FaceT>::FaceDataB]
+ *
+ ******************************************************************************/
+
+template<>
+template<>
+MZoneBoundary<2>::GlobalVertexData<MEdge>::FaceDataB::FaceDataB()
+  : face(0, 0) 
+{ }
+
+template<>
+template<>
+MZoneBoundary<3>::GlobalVertexData<MFace>::FaceDataB::FaceDataB()
+   : face(0, 0, 0) 
+{ }
+
+
 /*******************************************************************************
  *
  * Explicit instantiations of class MZoneBoundary
diff --git a/Geo/MZoneBoundary.h b/Geo/MZoneBoundary.h
index 9cdf8ba223..cfc6e737a1 100644
--- a/Geo/MZoneBoundary.h
+++ b/Geo/MZoneBoundary.h
@@ -167,6 +167,9 @@ struct ZoneBoVecSort
  * =====
  *
  *   - explicitly instantiated in 'MZoneBoundary.cpp'
+ *   - this class uses some explicit memory management.  Call preInit() before
+ *     constructing any class MZoneBoundary and postDestroy() after all
+ *     MZoneBoundary classes have been destroyed.
  *
  ******************************************************************************/
 
@@ -203,6 +206,11 @@ class MZoneBoundary
         parentFace(bFMapIt->second.parentFace),
         faceIndex(bFMapIt->second.faceIndex), zoneIndex(_zoneIndex)
       { }
+     private:
+      // The default constructor is required by 'set_offsets()' in
+      // class 'FaceAllocator'.  This is invoked by preInit() below.
+      FaceDataB();
+      friend class CCon::FaceAllocator<FaceDataB>;
     };
     struct ZoneData
     {
@@ -211,6 +219,11 @@ class MZoneBoundary
       ZoneData(const int _vertexIndex, const int _zoneIndex)
         : vertexIndex(_vertexIndex), zoneIndex(_zoneIndex)
       { }
+     private:
+      // The default constructor is required by 'set_offsets()' in
+      // class 'FaceAllocator'.  This is invoked by preInit() below.
+      ZoneData() { };
+      friend class CCon::FaceAllocator<ZoneData>;
     };
     CCon::FaceVector<FaceDataB> faces;
     CCon::FaceVector<ZoneData> zoneData;
@@ -249,6 +262,22 @@ class MZoneBoundary
 
   int exteriorBoundaryVertices(ZoneBoVec &zoneBoVec);
 
+//--Memory management
+
+  static void preInit()
+  {
+    CCon::FaceVector<typename GlobalVertexData<FaceT>::FaceDataB>
+      ::init_memory();
+    CCon::FaceVector<typename GlobalVertexData<FaceT>::ZoneData>::init_memory();
+  }
+  static void postDestroy()
+  {
+    CCon::FaceVector<typename GlobalVertexData<FaceT>::FaceDataB>
+      ::release_memory();
+    CCon::FaceVector<typename GlobalVertexData<FaceT>::ZoneData>
+      ::release_memory();
+  }
+
 
 /*==============================================================================
  * Member data
@@ -263,4 +292,5 @@ private:
 
 };
 
+
 #endif
-- 
GitLab