Nektar++
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
NekMemoryManager.hpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: NekMemoryManager.hpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description:
32 //
33 // A memory manager that allocates memory from thread specific pools.
34 //
35 ////////////////////////////////////////////////////////////////////////////////
36 
37 #ifndef NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
38 #define NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
39 
40 #include <memory>
41 #include <type_traits>
42 
43 #include <boost/core/ignore_unused.hpp>
44 
48 
49 #include <vector>
50 
51 #ifdef max
52 #undef max
53 #endif
54 
55 namespace Nektar
56 {
57 
58 /// @brief General purpose memory allocation routines with the ability
59 /// to allocate from thread specific memory pools.
60 ///
61 /// If compiled with NEKTAR_MEMORY_POOL_ENABLED, the MemoryManager
62 /// allocates from thread specific memory pools for small objects.
63 /// Large objects are managed with the system supplied new/delete.
64 /// These memory pools provide faster allocation and deallocation
65 /// of small objects (particularly useful for shared pointers which
66 /// allocate many 4 byte objects).
67 ///
68 /// @warning All memory allocated from the memory manager must be returned
69 /// to the memory manager. Calling delete on memory allocated from the
70 /// manager will likely cause undefined behavior. A particularly subtle
71 /// violation of this rule occurs when giving memory allocated from the
72 /// manager to a shared pointer.
73 /// @code
74 /// std::shared_ptr<Obj> f(MemoryManager<Obj>::Allocate());
75 /// @endcode
76 /// Shared pointers call delete when they go out of scope, so this line of
77 /// code will cause problems. Instead, you should call the
78 /// AllocateSharedPtr method:
79 /// @code
80 /// std::shared_ptr<Obj> f = MemoryManager<Obj>::AllocateSharedPtr();
81 /// @endcode
82 template<typename DataType>
84 {
85 public:
86  /// @brief Deallocate a pointer allocated by
87  /// MemoryManager::Allocate.
88  /// @note Results are undefined if called with a pointer to
89  /// something that was not allocated with the memory manager.
90  ///
91  /// Use this method to deallocate a pointer you have allocated from
92  /// the MemoryManager using the Allocate method.
93  ///
94  /// Example:
95  /// @code
96  /// CustObj* c = MemoryManager::Allocate<CustObj>();
97  /// MemoryManager::Deallocate(c);
98  /// @endcode
99  static void Deallocate(DataType*& data)
100  {
101 #ifdef NEKTAR_MEMORY_POOL_ENABLED
102  data->~DataType();
103  GetMemoryPool().Deallocate(data, sizeof(DataType));
104 #else
105 #ifdef NEKTAR_USE_ALIGNED_MEM
106  boost::alignment::aligned_free(data);
107 #else
108  delete data;
109 #endif
110 #endif
111 
112  data = NULL;
113  }
114 
115 #ifdef NEKTAR_MEMORY_POOL_ENABLED
116  /// @brief Allocates a single object from the memory pool.
117  /// @throws unknown If the object throws an exception during
118  /// construction, this method will catch it, release the memory
119  /// back to the pool, then rethrow it.
120  ///
121  /// The allocated object must be returned to the memory pool
122  /// via Deallocate.
123  template<typename... Args>
124  static DataType* Allocate(const Args &...args)
125  {
126  DataType* result = static_cast<DataType*>(
127  GetMemoryPool().Allocate(sizeof(DataType)));
128 
129  if (result)
130  {
131  try
132  {
133  new (result) DataType(args...);
134  }
135  catch(...)
136  {
137  GetMemoryPool().Deallocate(result, sizeof(DataType));
138  throw;
139  }
140  }
141 
142  return result;
143  }
144 
145 #else //NEKTAR_MEMORY_POOL_ENABLED
146  /// @brief Allocates a single object from the memory pool.
147  /// @throws unknown Any exception thrown by DataType's default
148  /// constructor will propogate through this method.
149  ///
150  /// The allocated object must be returned to the memory pool
151  /// via Deallocate.
152  template<typename... Args>
153  static DataType* Allocate(const Args &...args)
154  {
155  #ifdef NEKTAR_USE_ALIGNED_MEM
156  void *ptr = boost::alignment::aligned_alloc(tinysimd::simd<NekDouble>::alignment,
157  sizeof(DataType));
158  return new (ptr) DataType(args...);
159  #else
160  return new DataType(args...);
161  #endif
162  }
163 #endif //NEKTAR_MEMORY_POOL_ENABLED
164 
165  /// @brief Allocate a shared pointer from the memory pool.
166  ///
167  /// The shared pointer does not need to be returned to the memory
168  /// pool. When the reference count to this object reaches 0, the
169  /// shared pointer will automatically return the memory.
170  template<typename... Args>
171  static std::shared_ptr<DataType> AllocateSharedPtr(const Args &...args)
172  {
173  return AllocateSharedPtrD( [](DataType *){}, args...);
174  }
175 
176  template<typename DeallocatorType, typename... Args>
177  static std::shared_ptr<DataType> AllocateSharedPtrD(
178  const DeallocatorType& d, const Args &...args)
179  {
180  DataType* data = Allocate(args...);
181  return std::shared_ptr<DataType>(
182  data, [=](DataType *ptr){
183  d(ptr);
185  });
186  }
187 
188  /// \brief Allocates a chunk of raw, uninitialized memory, capable of
189  /// holding NumberOfElements objects.
190  ///
191  /// \param NumberOfElements The number of elements the array should be
192  /// capable of holding.
193  ///
194  /// This method is not meant to be called by client code. Use Array
195  /// instead. Any memory allocated from this method must be returned to the
196  /// memory pool via RawDeallocate. Failure to do so will result in memory
197  /// leaks and undefined behavior.
198  static DataType* RawAllocate(size_t NumberOfElements)
199  {
200 #ifdef NEKTAR_MEMORY_POOL_ENABLED
201  return static_cast<DataType*>(GetMemoryPool().Allocate(
202  NumberOfElements * sizeof(DataType)));
203 #else //NEKTAR_MEMORY_POOL_ENABLED
204  #ifdef NEKTAR_USE_ALIGNED_MEM
205  return static_cast<DataType*>(boost::alignment::aligned_alloc(
207  NumberOfElements * sizeof(DataType)));
208  #else
209  return static_cast<DataType*>(::operator new(NumberOfElements * sizeof(DataType)));
210  #endif
211 #endif //NEKTAR_MEMORY_POOL_ENABLED
212  }
213 
214 
215  /// \brief Deallocates memory allocated from RawAllocate.
216  /// \param array A pointer to the memory returned from RawAllocate.
217  /// \param NumberOfElements The number of object held in the array.
218  ///
219  /// This method is not meant to be called by client code. Use Array instead.
220  /// Only memory allocated via RawAllocate should be returned to the pool here.
221  static void RawDeallocate(DataType* array, size_t NumberOfElements)
222  {
223 #ifdef NEKTAR_MEMORY_POOL_ENABLED
224  GetMemoryPool().Deallocate(array, sizeof(DataType)*NumberOfElements);
225 #else //NEKTAR_MEMORY_POOL_ENABLED
226  boost::ignore_unused(NumberOfElements);
227  #ifdef NEKTAR_USE_ALIGNED_MEM
228  boost::alignment::aligned_free(array);
229  #else
230  ::operator delete(array);
231  #endif
232 #endif //NEKTAR_MEMORY_POOL_ENABLED
233  }
234 
235  /////////////////////////////////////////////////////////////////
236  ///\name Allocator Interface
237  /// The allocator interface allows a MemoryManager object to be used
238  /// in any object that allows an allocator parameter, such as STL
239  /// containers.
240  /////////////////////////////////////////////////////////////////
241  typedef DataType value_type;
242  typedef size_t size_type;
243  typedef ptrdiff_t difference_type;
244  typedef DataType* pointer;
245  typedef const DataType* const_pointer;
246  typedef DataType& reference;
247  typedef const DataType& const_reference;
248 
250  template<typename T>
252  {
253  boost::ignore_unused(rhs);
254  }
256 
257  pointer address(reference r) const { return &r; }
258  const_pointer address(const_reference r) const { return &r; }
259 
260  pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0)//typename MemoryManager<void>::pointer hint = 0)
261  {
262  boost::ignore_unused(hint);
263  return RawAllocate(n);
264  }
265 
267  {
268  return RawDeallocate(p, n);
269  }
270 
272  {
273  new(p) DataType(val);
274  }
275 
277  {
278  p->~DataType();
279  }
280 
282  {
283  return std::numeric_limits<size_type>::max()/sizeof(DataType);
284  }
285 
286  template<typename U>
287  struct rebind
288  {
290  };
291 
292  /////////////////////////////////////////////////////////////////
293  ///@}
294  /////////////////////////////////////////////////////////////////
295 
296 private:
297 
298 };
299 
300 template<typename DataType>
302 {
303  boost::ignore_unused(lhs,rhs);
304  return true;
305 }
306 
307 template<typename DataType>
309 {
310  return !(lhs == rhs);
311 }
312 
313 }
314 
315 #endif //NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
316 
317 
void Deallocate(void *p, size_t bytes)
Deallocate memory claimed by an earlier call to allocate.
void * Allocate(size_t bytes)
Allocate a block of memory of size ByteSize.
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
static std::shared_ptr< DataType > AllocateSharedPtrD(const DeallocatorType &d, const Args &...args)
void deallocate(pointer p, size_type n)
MemoryManager(const MemoryManager< T > &rhs)
pointer address(reference r) const
const DataType * const_pointer
const DataType & const_reference
static void RawDeallocate(DataType *array, size_t NumberOfElements)
Deallocates memory allocated from RawAllocate.
void construct(pointer p, const_reference val)
static void Deallocate(DataType *&data)
Deallocate a pointer allocated by MemoryManager::Allocate.
pointer allocate(size_type n, std::allocator< void >::const_pointer hint=0)
static DataType * Allocate(const Args &...args)
Allocates a single object from the memory pool.
const_pointer address(const_reference r) const
static DataType * RawAllocate(size_t NumberOfElements)
Allocates a chunk of raw, uninitialized memory, capable of holding NumberOfElements objects.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
bool operator==(const Array< OneD, T1 > &lhs, const Array< OneD, T2 > &rhs)
MemPool & GetMemoryPool()
bool operator!=(const Array< OneD, T1 > &lhs, const Array< OneD, T2 > &rhs)
typename abi< ScalarType >::type simd
Definition: tinysimd.hpp:83