SUNphi  1.0
Memory.hpp
Go to the documentation of this file.
1 #ifndef _MEMORY_HPP
2 #define _MEMORY_HPP
3 
4 /// \file Memory.hpp
5 ///
6 /// \brief Header file for the allocation and deallocation of memory
7 /// \todo: implement memory pool and cacher
8 
9 #include <cstdlib>
10 
11 #include <debug/Crash.hpp>
12 #include <ios/Logger.hpp>
13 #include <system/SIMD.hpp>
14 #include <utility/ValWithExtreme.hpp>
15 
16 namespace SUNphi
17 {
18  /// Minimal alignment
19 #define DEFAULT_ALIGNMENT
20  16
21 
22  /// Memory manager
23  class Memory
24  {
25  /// List of dynamical allocated memory
26  std::map<void*,size_t> used;
27 
28  /// List of cached allocated memory
30 
31  /// Size of used memory
33 
34  /// Size of cached memory
36 
37  /// Use or not cache
38  bool useCache{true};
39 
40  /// Number of unaligned allocation performed
42 
43  /// Number of aligned allocation performed
45 
46  /// Number of cached memory reused
48 
49  /// Get aligned memory
50  ///
51  /// Call the system routine which allocate memory
52  void* allocateRawAligned(const size_t size, ///< Amount of memory to allocate
53  const size_t alignment) ///< Required alignment
54  {
55  // runLog()<<"Raw allocating "<<size;
56 
57  /// Result
58  void* ptr=
59  nullptr;
60 
61  /// Returned condition
62  int rc=
63  posix_memalign(&ptr,
64  alignment,
65  size);
66 
67  if(rc)
68  CRASH<<"Failed to allocate "<<size<<" with alignement "<<ALIGNMENT;
69 
70  nAlignedAlloc++;
71 
72  return
73  ptr;
74  }
75 
76  /// Add to the list of used memory
77  void pushToUsed(void* ptr,
78  const size_t size)
79  {
80  used[ptr]=
81  size;
82 
83  usedSize+=
84  size;
85 
86  // runLog()<<"Pushing to used "<<ptr<<" "<<size<<", number of used:"<<used.size();
87  }
88 
89  /// Removes a pointer from the used list, without actually freeing associated memory
90  ///
91  /// Returns the size of the memory pointed
92  size_t popFromUsed(void* ptr) ///< Pointer to the memory to move to cache
93  {
94  // runLog()<<"Popping from used "<<ptr;
95 
96  /// Iterator to search result
97  auto el=
98  used.find(ptr);
99 
100  if(el==used.end())
101  CRASH<<"Unable to find dinamically allocated memory "<<ptr;
102 
103  /// Size of memory
104  const size_t size=
105  el->second;
106 
107  usedSize-=
108  size;
109 
110  used.erase(el);
111 
112  return
113  size;
114  }
115 
116  /// Adds a memory to cache
117  void pushToCache(void* ptr, ///< Memory to cache
118  const size_t size) ///< Memory size
119  {
120  cached[size].push_back(ptr);
121 
122  cachedSize+=
123  size;
124 
125  // runLog()<<"Pushing to cache "<<size<<" "<<ptr<<", cache size: "<<cached.size();
126  }
127 
128  /// Check if a pointer is suitably aligned
129  static bool isAligned(const void* ptr,
130  const size_t alignment)
131  {
132  return
133  reinterpret_cast<uintptr_t>(ptr)%alignment==0;
134  }
135 
136  /// Pop from the cache, returning to use
137  void* popFromCache(const size_t& size,
138  const size_t& alignment)
139  {
140  // runLog()<<"Try to popping from cache "<<size;
141 
142  /// List of memory with searched size
143  auto cachedIt=
144  cached.find(size);
145 
146  if(cachedIt==cached.end())
147  return
148  nullptr;
149  else
150  {
151  /// Vector of pointers
152  auto& list=
153  cachedIt->second;
154 
155  /// Get latest cached memory with appropriate alignment
156  auto it=
157  list.end()-1;
158 
159  while(it!=list.begin()-1 and not isAligned(*it,alignment))
160  it--;
161 
162  if(it==list.begin()-1)
163  return
164  nullptr;
165  else
166  {
167  /// Returned pointer, copied here before erasing
168  void* ptr=
169  *it;
170 
171  list.erase(it);
172 
173  cachedSize-=
174  size;
175 
176  if(list.size()==0)
177  cached.erase(cachedIt);
178 
179  return
180  ptr;
181  }
182  }
183  }
184 
185  /// Move the allocated memory to cache
186  void moveToCache(void* ptr) ///< Pointer to the memory to move to cache
187  {
188  // runLog()<<"Moving to cache "<<ptr;
189 
190  /// Size of pointed memory
191  const size_t size=
192  popFromUsed(ptr);
193 
194  pushToCache(ptr,size);
195  }
196 
197  public:
198 
199  /// Enable cache usage
200  void enableCache()
201  {
202  useCache=
203  true;
204  }
205 
206  /// Disable cache usage
208  {
209  useCache=
210  false;
211 
212  clearCache();
213  }
214 
215  /// Allocate or get from cache after computing the proper size
216  template <class T=char>
217  T* provideAligned(const size_t nel,
218  const size_t alignment)
219  {
220  /// Total size to allocate
221  const size_t size=
222  sizeof(T)*nel;
223 
224  /// Allocated memory
225  void* ptr;
226 
227  // Search in the cache
228  ptr=
229  popFromCache(size,alignment);
230 
231  // If not found in the cache, allocate new memory
232  if(ptr==nullptr)
233  ptr=
234  allocateRawAligned(size,alignment);
235  else
236  nCachedReused++;
237 
238  pushToUsed(ptr,size);
239 
240  return
241  static_cast<T*>(ptr);
242  }
243 
244  /// Decleare unused the memory
245  template <class T>
246  void release(T* ptr) ///< Pointer getting freed
247  {
248  if(useCache)
249  moveToCache(static_cast<void*>(ptr));
250  else
251  {
252  popFromUsed(ptr);
253  free(ptr);
254  }
255  }
256 
257  /// Release all used memory
259  {
260  /// Iterator on elements to release
261  auto el=
262  used.begin();
263 
264  while(el!=used.end())
265  {
266  // runLog()<<"Releasing "<<el.first<<" size "<<el.second;
267 
268  /// Pointer to memory to release
269  void* ptr=
270  el->first;
271 
272  // Increment iterator before releasing
273  el++;
274 
275  release(ptr);
276  }
277  }
278 
279  /// Release all memory from cache
280  void clearCache()
281  {
282  /// Iterator to elements of the cached memory list
283  auto el=
284  cached.begin();
285 
286  while(el!=cached.end())
287  {
288  /// Number of elements to free
289  const size_t n=
290  el->second.size();
291 
292  /// Size to be removed
293  const size_t size=
294  el->first;
295 
296  // Increment before erasing
297  el++;
298 
299  for(size_t i=0;i<n;i++)
300  {
301  // runLog()<<"Removing from cache size "<<el.first;
302 
303  /// Memory to free
304  void* ptr=
305  popFromCache(size,DEFAULT_ALIGNMENT);
306 
307  free(ptr);
308  }
309  }
310  }
311 
312  /// Print to a stream
313  template <typename T>
315  {
316  return
317  stream<<"Maximal memory used: "<<usedSize.extreme()<<" bytes, currently used: "<<usedSize
318  <<" bytes, number of allocation: "<<nUnalignedAlloc<<" unaligned, "<<nAlignedAlloc<<" aligned\n"
319  <<"Maximal memory cached: "<<cachedSize.extreme()<<" bytes, currently used: "<<cachedSize
320  <<" bytes, number of reused: "<<nCachedReused;
321  }
322 
323  /// Create the memory manager
325  {
326  runLog()<<"Starting the memory manager";
327  }
328 
329  /// Destruct the memory manager
331  {
332  runLog()<<"Stopping the memory manager";
333 
335 
336  printStatistics(runLog());
337 
339 
340  clearCache();
341  }
342  };
343 
344  extern Memory memory;
345 
346 }
347 
348 #endif
T * provideAligned(const size_t nel, const size_t alignment)
Allocate or get from cache after computing the proper size.
Definition: Memory.hpp:217
void releaseAllUsedMemory()
Release all used memory.
Definition: Memory.hpp:258
ValWithMax< size_t > usedSize
Size of used memory.
Definition: Memory.hpp:32
void pushToCache(void *ptr, const size_t size)
Adds a memory to cache.
Definition: Memory.hpp:117
auto & printStatistics(T &&stream)
Print to a stream.
Definition: Memory.hpp:314
#define CRASH
Initialize the crasher.
Definition: Crash.hpp:13
#define DEFAULT_ALIGNMENT
Minimal alignment.
Definition: Memory.hpp:19
size_t popFromUsed(void *ptr)
Definition: Memory.hpp:92
ScopeIndenter(Logger &logger)
Create and increase indent level.
Definition: Logger.hpp:415
~Memory()
Destruct the memory manager.
Definition: Memory.hpp:330
void enableCache()
Enable cache usage.
Definition: Memory.hpp:200
size_t nCachedReused
Number of cached memory reused.
Definition: Memory.hpp:47
void release(T *ptr)
Decleare unused the memory.
Definition: Memory.hpp:246
void * allocateRawAligned(const size_t size, const size_t alignment)
Definition: Memory.hpp:52
void moveToCache(void *ptr)
Move the allocated memory to cache.
Definition: Memory.hpp:186
static bool isAligned(const void *ptr, const size_t alignment)
Check if a pointer is suitably aligned.
Definition: Memory.hpp:129
Logger runLog("/dev/stdout")
Global logger.
void pushToUsed(void *ptr, const size_t size)
Add to the list of used memory.
Definition: Memory.hpp:77
ValWithMax< size_t > cachedSize
Size of cached memory.
Definition: Memory.hpp:35
Memory memory
Memory manager.
Definition: SUNphi.cpp:221
decltype(auto) operator+(T1 &&smet1, T2 &&smet2)
Implement smet1+smet2.
Definition: Add.hpp:87
void disableCache()
Disable cache usage.
Definition: Memory.hpp:207
#define SCOPE_INDENT(VAR)
Mark the stream to be more indented.
Definition: File.hpp:16
Memory()
Create the memory manager.
Definition: Memory.hpp:324
void * popFromCache(const size_t &size, const size_t &alignment)
Pop from the cache, returning to use.
Definition: Memory.hpp:137
void clearCache()
Release all memory from cache.
Definition: Memory.hpp:280