Nektar++
Loading...
Searching...
No Matches
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
46
47#include <vector>
48
49#ifdef max
50#undef max
51#endif
52
53namespace Nektar
54{
55
56/// @brief General purpose memory allocation routines with the ability
57/// to allocate from thread specific memory pools.
58///
59/// If compiled with NEKTAR_MEMORY_POOL_ENABLED, the MemoryManager
60/// allocates from thread specific memory pools for small objects.
61/// Large objects are managed with the system supplied new/delete.
62/// These memory pools provide faster allocation and deallocation
63/// of small objects (particularly useful for shared pointers which
64/// allocate many 4 byte objects).
65///
66/// @warning All memory allocated from the memory manager must be returned
67/// to the memory manager. Calling delete on memory allocated from the
68/// manager will likely cause undefined behavior. A particularly subtle
69/// violation of this rule occurs when giving memory allocated from the
70/// manager to a shared pointer.
71/// @code
72/// std::shared_ptr<Obj> f(MemoryManager<Obj>::Allocate());
73/// @endcode
74/// Shared pointers call delete when they go out of scope, so this line of
75/// code will cause problems. Instead, you should call the
76/// AllocateSharedPtr method:
77/// @code
78/// std::shared_ptr<Obj> f = MemoryManager<Obj>::AllocateSharedPtr();
79/// @endcode
80template <typename DataType> class MemoryManager
81{
82public:
83 /// @brief Deallocate a pointer allocated by
84 /// MemoryManager::Allocate.
85 /// @note Results are undefined if called with a pointer to
86 /// something that was not allocated with the memory manager.
87 ///
88 /// Use this method to deallocate a pointer you have allocated from
89 /// the MemoryManager using the Allocate method.
90 ///
91 /// Example:
92 /// @code
93 /// CustObj* c = MemoryManager::Allocate<CustObj>();
94 /// MemoryManager::Deallocate(c);
95 /// @endcode
96 static void Deallocate(DataType *&data)
97 {
98#ifdef NEKTAR_MEMORY_POOL_ENABLED
99 data->~DataType();
100 GetMemoryPool().Deallocate(data, sizeof(DataType));
101#else
102#ifdef NEKTAR_USE_ALIGNED_MEM
103 data->~DataType();
104 free(data);
105#else
106 delete data;
107#endif
108#endif
109
110 data = nullptr;
111 }
112
113#ifdef NEKTAR_MEMORY_POOL_ENABLED
114 /// @brief Allocates a single object from the memory pool.
115 /// @throws unknown If the object throws an exception during
116 /// construction, this method will catch it, release the memory
117 /// back to the pool, then rethrow it.
118 ///
119 /// The allocated object must be returned to the memory pool
120 /// via Deallocate.
121 template <typename... Args> static DataType *Allocate(const Args &...args)
122 {
123 DataType *result =
124 static_cast<DataType *>(GetMemoryPool().Allocate(sizeof(DataType)));
125
126 if (result)
127 {
128 try
129 {
130 new (result) DataType(args...);
131 }
132 catch (...)
133 {
134 GetMemoryPool().Deallocate(result, sizeof(DataType));
135 throw;
136 }
137 }
138
139 return result;
140 }
141
142#else // NEKTAR_MEMORY_POOL_ENABLED
143 /// @brief Allocates a single object from the memory pool.
144 /// @throws unknown Any exception thrown by DataType's default
145 /// constructor will propogate through this method.
146 ///
147 /// The allocated object must be returned to the memory pool
148 /// via Deallocate.
149 template <typename... Args> static DataType *Allocate(const Args &...args)
150 {
151#ifdef NEKTAR_USE_ALIGNED_MEM
152 void *ptr = aligned_alloc(tinysimd::simd<NekDouble>::alignment,
153 sizeof(DataType));
154 return new (ptr) DataType(args...);
155#else
156 return new DataType(args...);
157#endif
158 }
159#endif // NEKTAR_MEMORY_POOL_ENABLED
160
161 /// @brief Allocate a shared pointer from the memory pool.
162 ///
163 /// The shared pointer does not need to be returned to the memory
164 /// pool. When the reference count to this object reaches 0, the
165 /// shared pointer will automatically return the memory.
166 template <typename... Args>
167 static std::shared_ptr<DataType> AllocateSharedPtr(const Args &...args)
168 {
169 return AllocateSharedPtrD([](DataType *) {}, args...);
170 }
171
172 template <typename DeallocatorType, typename... Args>
173 static std::shared_ptr<DataType> AllocateSharedPtrD(
174 const DeallocatorType &d, const Args &...args)
175 {
176 DataType *data = Allocate(args...);
177 return std::shared_ptr<DataType>(data, [=](DataType *ptr) {
178 d(ptr);
180 });
181 }
182
183 /// \brief Allocates a chunk of raw, uninitialized memory, capable of
184 /// holding NumberOfElements objects.
185 ///
186 /// \param NumberOfElements The number of elements the array should be
187 /// capable of holding.
188 ///
189 /// This method is not meant to be called by client code. Use Array
190 /// instead. Any memory allocated from this method must be returned to the
191 /// memory pool via RawDeallocate. Failure to do so will result in memory
192 /// leaks and undefined behavior.
193 static DataType *RawAllocate(size_t NumberOfElements)
194 {
195#ifdef NEKTAR_MEMORY_POOL_ENABLED
196 return static_cast<DataType *>(
197 GetMemoryPool().Allocate(NumberOfElements * sizeof(DataType)));
198#else // NEKTAR_MEMORY_POOL_ENABLED
199#ifdef NEKTAR_USE_ALIGNED_MEM
200 return static_cast<DataType *>(
202 NumberOfElements * sizeof(DataType)));
203#else
204 return static_cast<DataType *>(
205 ::operator new(NumberOfElements * sizeof(DataType)));
206#endif
207#endif // NEKTAR_MEMORY_POOL_ENABLED
208 }
209
210 /// \brief Deallocates memory allocated from RawAllocate.
211 /// \param array A pointer to the memory returned from RawAllocate.
212 /// \param NumberOfElements The number of object held in the array.
213 ///
214 /// This method is not meant to be called by client code. Use Array
215 /// instead. Only memory allocated via RawAllocate should be returned to the
216 /// pool here.
217 static void RawDeallocate(DataType *array,
218 [[maybe_unused]] size_t NumberOfElements)
219 {
220#ifdef NEKTAR_MEMORY_POOL_ENABLED
221 GetMemoryPool().Deallocate(array, sizeof(DataType) * NumberOfElements);
222#else // NEKTAR_MEMORY_POOL_ENABLED
223#ifdef NEKTAR_USE_ALIGNED_MEM
224 free(array);
225#else
226 ::operator delete(array);
227#endif
228#endif // NEKTAR_MEMORY_POOL_ENABLED
229 }
230
231 /////////////////////////////////////////////////////////////////
232 ///\name Allocator Interface
233 /// The allocator interface allows a MemoryManager object to be used
234 /// in any object that allows an allocator parameter, such as STL
235 /// containers.
236 /////////////////////////////////////////////////////////////////
237 typedef DataType value_type;
238 typedef size_t size_type;
239 typedef ptrdiff_t difference_type;
240 typedef DataType *pointer;
241 typedef const DataType *const_pointer;
242 typedef DataType &reference;
243 typedef const DataType &const_reference;
244
246 {
247 }
248 template <typename T> MemoryManager(const MemoryManager<T> &rhs) = delete;
250 {
251 }
252
254 {
255 return &r;
256 }
258 {
259 return &r;
260 }
261
263 {
264 return RawAllocate(n);
265 }
266
268 {
269 return RawDeallocate(p, n);
270 }
271
273 {
274 new (p) DataType(val);
275 }
276
278 {
279 p->~DataType();
280 }
281
283 {
284 return std::numeric_limits<size_type>::max() / sizeof(DataType);
285 }
286
287 template <typename U> struct rebind
288 {
290 };
291
292 /////////////////////////////////////////////////////////////////
293 ///@}
294 /////////////////////////////////////////////////////////////////
295
296private:
297};
298
299template <typename DataType>
300bool operator==([[maybe_unused]] const MemoryManager<DataType> &lhs,
301 [[maybe_unused]] const MemoryManager<DataType> &rhs)
302{
303 return true;
304}
305
306template <typename DataType>
308 const MemoryManager<DataType> &rhs)
309{
310 return !(lhs == rhs);
311}
312
313} // namespace Nektar
314
315#endif // NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
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 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.
void deallocate(pointer p, size_type n)
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.
MemoryManager(const MemoryManager< T > &rhs)=delete
void construct(pointer p, const_reference val)
static std::shared_ptr< DataType > AllocateSharedPtrD(const DeallocatorType &d, const Args &...args)
static void Deallocate(DataType *&data)
Deallocate a pointer allocated by MemoryManager::Allocate.
const_pointer address(const_reference r) const
pointer allocate(size_type n)
static DataType * Allocate(const Args &...args)
Allocates a single object from the memory pool.
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, width >::type simd
Definition tinysimd.hpp:132