HMLP: High-performance Machine Learning Primitives
mem_mgr.hpp
1 // TODO: Implement fast stack allocation.
2 #ifndef _PVFMM_MEM_MGR_HPP_
3 #define _PVFMM_MEM_MGR_HPP_
4 
5 #include <omp.h>
6 #include <cstdlib>
7 #include <cstdint>
8 #include <cassert>
9 #include <vector>
10 #include <stack>
11 #include <map>
12 #include <set>
13 
14 #include <pvfmm/common.hpp>
15 
16 namespace pvfmm {
17 
18 class MemoryManager;
19 
20 #ifdef PVFMM_MEMDEBUG
21 
22 template <class ValueType> class ConstIterator {
23 
24  template <typename T> friend class ConstIterator;
25 
26  template <typename T> friend class Iterator;
27 
28  void IteratorAssertChecks(Long j = 0) const;
29 
30  public:
31  typedef std::random_access_iterator_tag iterator_category;
32  typedef const ValueType& reference;
33  typedef Long difference_type;
34  typedef ValueType value_type;
35  typedef const ValueType* pointer;
36 
37  protected:
38  char* base;
39  difference_type len, offset;
40  Long alloc_ctr;
41  void* mem_head;
42  static const Long ValueSize = sizeof(ValueType);
43 
44  public:
45  ConstIterator(void* base_ = NULL) {
46  base = (char*)base_;
47  len = 0;
48  offset = 0;
49  alloc_ctr = 0;
50  mem_head = NULL;
51  }
52 
53  // template <size_t LENGTH> ConstIterator(ValueType (&base_)[LENGTH]) { // DEPRECATED
54  // PVFMM_ASSERT(false);
55  // }
56 
57  ConstIterator(const ValueType* base_, difference_type len_, bool dynamic_alloc = false);
58 
59  template <class AnotherType> explicit ConstIterator(const ConstIterator<AnotherType>& I) {
60  this->base = I.base;
61  this->len = I.len;
62  this->offset = I.offset;
63  PVFMM_ASSERT_MSG((uintptr_t)(this->base + this->offset) % alignof(ValueType) == 0, "invalid alignment during pointer type conversion.");
64  this->alloc_ctr = I.alloc_ctr;
65  this->mem_head = I.mem_head;
66  }
67 
68  // value_type* like operators
69  reference operator*() const;
70 
71  const value_type* operator->() const;
72 
73  reference operator[](difference_type off) const;
74 
75  // Increment / Decrement
76  ConstIterator& operator++() {
77  offset += (Long)sizeof(ValueType);
78  return *this;
79  }
80 
81  ConstIterator operator++(int) {
82  ConstIterator<ValueType> tmp(*this);
83  ++*this;
84  return tmp;
85  }
86 
87  ConstIterator& operator--() {
88  offset -= (Long)sizeof(ValueType);
89  return *this;
90  }
91 
92  ConstIterator operator--(int) {
93  ConstIterator<ValueType> tmp(*this);
94  --*this;
95  return tmp;
96  }
97 
98  // Arithmetic
99  ConstIterator& operator+=(difference_type i) {
100  offset += i * (Long)sizeof(ValueType);
101  return *this;
102  }
103 
104  ConstIterator operator+(difference_type i) const {
105  ConstIterator<ValueType> tmp(*this);
106  tmp.offset += i * (Long)sizeof(ValueType);
107  return tmp;
108  }
109 
110  friend ConstIterator operator+(difference_type i, const ConstIterator& right) { return (right + i); }
111 
112  ConstIterator& operator-=(difference_type i) {
113  offset -= i * (Long)sizeof(ValueType);
114  return *this;
115  }
116 
117  ConstIterator operator-(difference_type i) const {
118  ConstIterator<ValueType> tmp(*this);
119  tmp.offset -= i * (Long)sizeof(ValueType);
120  return tmp;
121  }
122 
123  difference_type operator-(const ConstIterator& I) const {
124  // if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
125  Long diff = ((ValueType*)(base + offset)) - ((ValueType*)(I.base + I.offset));
126  PVFMM_ASSERT_MSG(I.base + I.offset + diff * (Long)sizeof(ValueType) == base + offset, "invalid memory address alignment.");
127  return diff;
128  }
129 
130  // Comparison operators
131  bool operator==(const ConstIterator& I) const { return (base + offset == I.base + I.offset); }
132 
133  bool operator!=(const ConstIterator& I) const { return !(*this == I); }
134 
135  bool operator<(const ConstIterator& I) const {
136  // if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
137  return (base + offset) < (I.base + I.offset);
138  }
139 
140  bool operator<=(const ConstIterator& I) const {
141  // if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
142  return (base + offset) <= (I.base + I.offset);
143  }
144 
145  bool operator>(const ConstIterator& I) const {
146  // if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
147  return (base + offset) > (I.base + I.offset);
148  }
149 
150  bool operator>=(const ConstIterator& I) const {
151  // if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
152  return (base + offset) >= (I.base + I.offset);
153  }
154 
155  friend std::ostream& operator<<(std::ostream& out, const ConstIterator& I) {
156  out << "(" << (long long)I.base << "+" << I.offset << ":" << I.len << ")";
157  return out;
158  }
159 };
160 
161 template <class ValueType> class Iterator : public ConstIterator<ValueType> {
162 
163  public:
164  typedef std::random_access_iterator_tag iterator_category;
165  typedef ValueType& reference;
166  typedef Long difference_type;
167  typedef ValueType value_type;
168  typedef ValueType* pointer;
169 
170  public:
171  Iterator(void* base_ = NULL) : ConstIterator<ValueType>(base_) {}
172 
173  template <size_t LENGTH> Iterator(ValueType (&base_)[LENGTH]) : ConstIterator<ValueType>(base_) {}
174 
175  Iterator(ValueType* base_, difference_type len_, bool dynamic_alloc = false) : ConstIterator<ValueType>(base_, len_, dynamic_alloc) {}
176 
177  template <class AnotherType> explicit Iterator(const ConstIterator<AnotherType>& I) : ConstIterator<ValueType>(I) {}
178 
179  // value_type* like operators
180  reference operator*() const;
181 
182  value_type* operator->() const;
183 
184  reference operator[](difference_type off) const;
185 
186  // Increment / Decrement
187  Iterator& operator++() {
188  this->offset += (Long)sizeof(ValueType);
189  return *this;
190  }
191 
192  Iterator operator++(int) {
193  Iterator<ValueType> tmp(*this);
194  ++*this;
195  return tmp;
196  }
197 
198  Iterator& operator--() {
199  this->offset -= (Long)sizeof(ValueType);
200  return *this;
201  }
202 
203  Iterator operator--(int) {
204  Iterator<ValueType> tmp(*this);
205  --*this;
206  return tmp;
207  }
208 
209  // Arithmetic
210  Iterator& operator+=(difference_type i) {
211  this->offset += i * (Long)sizeof(ValueType);
212  return *this;
213  }
214 
215  Iterator operator+(difference_type i) const {
216  Iterator<ValueType> tmp(*this);
217  tmp.offset += i * (Long)sizeof(ValueType);
218  return tmp;
219  }
220 
221  friend Iterator operator+(difference_type i, const Iterator& right) { return (right + i); }
222 
223  Iterator& operator-=(difference_type i) {
224  this->offset -= i * (Long)sizeof(ValueType);
225  return *this;
226  }
227 
228  Iterator operator-(difference_type i) const {
229  Iterator<ValueType> tmp(*this);
230  tmp.offset -= i * (Long)sizeof(ValueType);
231  return tmp;
232  }
233 
234  difference_type operator-(const ConstIterator<ValueType>& I) const { return static_cast<const ConstIterator<ValueType>&>(*this) - I; }
235 };
236 
237 template <class ValueType, Long DIM> class StaticArray : public Iterator<ValueType> {
238 
239  public:
240  StaticArray();
241 
242  ~StaticArray();
243 
244  StaticArray(std::initializer_list<ValueType> arr_) : StaticArray() {
245  // static_assert(arr_.size() <= DIM, "too many initializer values"); // allowed in C++14
246  PVFMM_ASSERT_MSG(arr_.size() <= DIM, "too many initializer values");
247  for (Long i = 0; i < arr_.size(); i++) arr[i] = arr_.begin()[i];
248  }
249 
250  private:
251  StaticArray(const StaticArray&);
252  StaticArray& operator=(const StaticArray&);
253 
254  Iterator<ValueType> arr;
255  ValueType arr_[DIM];
256 };
257 
258 #define PVFMM_PTR2ITR(type, ptr, len) pvfmm::Iterator<type>((type*)ptr, len)
259 #define PVFMM_PTR2CONSTITR(type, ptr, len) pvfmm::ConstIterator<type>((const type*)ptr, len)
260 
261 #else
262 
263 #define PVFMM_PTR2ITR(type, ptr, len) (type*) ptr
264 #define PVFMM_PTR2CONSTITR(type, ptr, len) (const type*) ptr
265 
266 #endif
267 
271 template <class T> class TypeTraits {
272 
273  public:
274  static uintptr_t ID();
275 
276  static bool IsPOD();
277 };
278 
283 
284  public:
285  static const char init_mem_val = 42;
286 
290  struct MemHead {
291  Long n_indx;
292  Long n_elem;
293  Long type_size;
294  Long alloc_ctr;
295  uintptr_t type_id;
296  unsigned char check_sum;
297  };
298 
302  MemoryManager(Long N);
303 
307  ~MemoryManager();
308 
309  static MemHead& GetMemHead(char* p);
310 
311  static void CheckMemHead(const MemHead& p);
312 
313  Iterator<char> malloc(const Long n_elem = 1, const Long type_size = sizeof(char), const uintptr_t type_id = TypeTraits<char>::ID()) const;
314 
315  void free(Iterator<char> p) const;
316 
317  void print() const;
318 
319  static void test();
320 
321  // Check all free memory equals init_mem_val
322  void Check() const;
323 
324  // A global MemoryManager object. This is the default for aligned_new and aligned_free
325  static MemoryManager& glbMemMgr() {
326  static MemoryManager m(PVFMM_GLOBAL_MEM_BUFF * 1024LL * 1024LL);
327  return m;
328  }
329 
330  private:
331  // Private constructor
332  MemoryManager();
333 
334  // Private copy constructor
335  MemoryManager(const MemoryManager& m);
336 
342  struct MemNode {
343  bool free;
344  Long size;
345  char* mem_ptr;
346  Long prev, next;
347  std::multimap<Long, Long>::iterator it;
348  };
349 
354  Long new_node() const;
355 
359  void delete_node(Long indx) const;
360 
361  char* buff; // pointer to memory buffer.
362  Long buff_size; // total buffer size in bytes.
363  Long n_dummy_indx; // index of first (dummy) MemNode in link list.
364 
365  mutable std::vector<MemNode> node_buff; // storage for MemNode objects, this can only grow.
366  mutable std::stack<Long> node_stack; // stack of available free MemNodes from node_buff.
367  mutable std::multimap<Long, Long> free_map; // pair (MemNode.size, MemNode_id) for all free MemNodes.
368  mutable omp_lock_t omp_lock; // openmp lock to prevent concurrent changes.
369  mutable std::set<void*> system_malloc; // track pointers allocated using system malloc.
370 };
371 
372 inline uintptr_t align_ptr(uintptr_t ptr) {
373  const uintptr_t ALIGN_MINUS_ONE = PVFMM_MEM_ALIGN - 1;
374  const uintptr_t NOT_ALIGN_MINUS_ONE = ~ALIGN_MINUS_ONE;
375  return ((ptr + ALIGN_MINUS_ONE) & NOT_ALIGN_MINUS_ONE);
376 }
377 
382 template <class ValueType> Iterator<ValueType> aligned_new(Long n_elem = 1, const MemoryManager* mem_mgr = &MemoryManager::glbMemMgr());
383 
389 template <class ValueType> void aligned_delete(Iterator<ValueType> A, const MemoryManager* mem_mgr = &MemoryManager::glbMemMgr());
390 
395 template <class ValueType> Iterator<ValueType> memcopy(Iterator<ValueType> destination, ConstIterator<ValueType> source, Long num);
396 
397 template <class ValueType> Iterator<ValueType> memset(Iterator<ValueType> ptr, int value, Long num);
398 
399 } // end namespace pvfmm
400 
401 #include <pvfmm/mem_mgr.txx>
402 
403 #endif //_PVFMM_MEM_MGR_HPP_
Definition: cheb_utils.hpp:12
MemoryManager class declaration.
Definition: mem_mgr.hpp:282
Header data for each memory block.
Definition: mem_mgr.hpp:290
Identify each type uniquely.
Definition: mem_mgr.hpp:271