mem_mgr.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. // TODO: Implement fast stack allocation.
  2. #ifndef _PVFMM_MEM_MGR_HPP_
  3. #define _PVFMM_MEM_MGR_HPP_
  4. #include <omp.h>
  5. #include <cstdlib>
  6. #include <stdint.h>
  7. #include <cassert>
  8. #include <vector>
  9. #include <stack>
  10. #include <map>
  11. #include <set>
  12. #include <pvfmm/common.hpp>
  13. namespace pvfmm {
  14. class MemoryManager;
  15. #ifdef PVFMM_MEMDEBUG
  16. template <class ValueType> class ConstIterator {
  17. template <typename T> friend class ConstIterator;
  18. template <typename T> friend class Iterator;
  19. public:
  20. typedef std::random_access_iterator_tag iterator_category;
  21. typedef const ValueType& reference;
  22. typedef Long difference_type;
  23. typedef ValueType value_type;
  24. typedef const ValueType* pointer;
  25. protected:
  26. char* base;
  27. difference_type len, offset;
  28. Long alloc_ctr;
  29. void* mem_head;
  30. static const Long ValueSize = sizeof(ValueType);
  31. public:
  32. ConstIterator(void* base_ = NULL) {
  33. base = (char*)base_;
  34. len = 0;
  35. offset = 0;
  36. alloc_ctr = 0;
  37. mem_head = NULL;
  38. }
  39. template <size_t LENGTH> ConstIterator(ValueType (&base_)[LENGTH]) { // DEPRECATED
  40. PVFMM_ASSERT(false);
  41. }
  42. ConstIterator(const ValueType* base_, difference_type len_, bool dynamic_alloc = false);
  43. template <class AnotherType> explicit ConstIterator(const ConstIterator<AnotherType>& I) {
  44. this->base = I.base;
  45. this->len = I.len;
  46. this->offset = I.offset;
  47. PVFMM_ASSERT_MSG((uintptr_t)(this->base + this->offset) % alignof(ValueType) == 0, "invalid alignment during pointer type conversion.");
  48. this->alloc_ctr = I.alloc_ctr;
  49. this->mem_head = I.mem_head;
  50. }
  51. // value_type* like operators
  52. reference operator*() const;
  53. const value_type* operator->() const;
  54. reference operator[](difference_type off) const;
  55. // Increment / Decrement
  56. ConstIterator& operator++() {
  57. offset += (Long)sizeof(ValueType);
  58. return *this;
  59. }
  60. ConstIterator operator++(int) {
  61. ConstIterator<ValueType> tmp(*this);
  62. ++*this;
  63. return tmp;
  64. }
  65. ConstIterator& operator--() {
  66. offset -= (Long)sizeof(ValueType);
  67. return *this;
  68. }
  69. ConstIterator operator--(int) {
  70. ConstIterator<ValueType> tmp(*this);
  71. --*this;
  72. return tmp;
  73. }
  74. // Arithmetic
  75. ConstIterator& operator+=(difference_type i) {
  76. offset += i * (Long)sizeof(ValueType);
  77. return *this;
  78. }
  79. ConstIterator operator+(difference_type i) const {
  80. ConstIterator<ValueType> tmp(*this);
  81. tmp.offset += i * (Long)sizeof(ValueType);
  82. return tmp;
  83. }
  84. friend ConstIterator operator+(difference_type i, const ConstIterator& right) { return (right + i); }
  85. ConstIterator& operator-=(difference_type i) {
  86. offset -= i * (Long)sizeof(ValueType);
  87. return *this;
  88. }
  89. ConstIterator operator-(difference_type i) const {
  90. ConstIterator<ValueType> tmp(*this);
  91. tmp.offset -= i * (Long)sizeof(ValueType);
  92. return tmp;
  93. }
  94. difference_type operator-(const ConstIterator& I) const {
  95. if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
  96. Long diff = ((ValueType*)(base + offset)) - ((ValueType*)(I.base + I.offset));
  97. PVFMM_ASSERT_MSG(I.base + I.offset + diff * (Long)sizeof(ValueType) == base + offset, "invalid memory address alignment.");
  98. return diff;
  99. }
  100. // Comparison operators
  101. bool operator==(const ConstIterator& I) const { return (base + offset == I.base + I.offset); }
  102. bool operator!=(const ConstIterator& I) const { return !(*this == I); }
  103. bool operator<(const ConstIterator& I) const {
  104. if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
  105. return (base + offset) < (I.base + I.offset);
  106. }
  107. bool operator<=(const ConstIterator& I) const {
  108. if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
  109. return (base + offset) <= (I.base + I.offset);
  110. }
  111. bool operator>(const ConstIterator& I) const {
  112. if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
  113. return (base + offset) > (I.base + I.offset);
  114. }
  115. bool operator>=(const ConstIterator& I) const {
  116. if (base != I.base) PVFMM_WARN("comparing two unrelated memory addresses.");
  117. return (base + offset) >= (I.base + I.offset);
  118. }
  119. friend std::ostream& operator<<(std::ostream& out, const ConstIterator& I) {
  120. out << "(" << (long long)I.base << "+" << I.offset << ":" << I.len << ")";
  121. return out;
  122. }
  123. };
  124. template <class ValueType> class Iterator : public ConstIterator<ValueType> {
  125. public:
  126. typedef std::random_access_iterator_tag iterator_category;
  127. typedef ValueType& reference;
  128. typedef Long difference_type;
  129. typedef ValueType value_type;
  130. typedef ValueType* pointer;
  131. public:
  132. Iterator(void* base_ = NULL) : ConstIterator<ValueType>(base_) {}
  133. template <size_t LENGTH> Iterator(ValueType (&base_)[LENGTH]) : ConstIterator<ValueType>(base_) {}
  134. Iterator(ValueType* base_, difference_type len_, bool dynamic_alloc = false) : ConstIterator<ValueType>(base_, len_, dynamic_alloc) {}
  135. template <class AnotherType> explicit Iterator(const ConstIterator<AnotherType>& I) : ConstIterator<ValueType>(I) {}
  136. // value_type* like operators
  137. reference operator*() const;
  138. value_type* operator->() const;
  139. reference operator[](difference_type off) const;
  140. // Increment / Decrement
  141. Iterator& operator++() {
  142. this->offset += (Long)sizeof(ValueType);
  143. return *this;
  144. }
  145. Iterator operator++(int) {
  146. Iterator<ValueType> tmp(*this);
  147. ++*this;
  148. return tmp;
  149. }
  150. Iterator& operator--() {
  151. this->offset -= (Long)sizeof(ValueType);
  152. return *this;
  153. }
  154. Iterator operator--(int) {
  155. Iterator<ValueType> tmp(*this);
  156. --*this;
  157. return tmp;
  158. }
  159. // Arithmetic
  160. Iterator& operator+=(difference_type i) {
  161. this->offset += i * (Long)sizeof(ValueType);
  162. return *this;
  163. }
  164. Iterator operator+(difference_type i) const {
  165. Iterator<ValueType> tmp(*this);
  166. tmp.offset += i * (Long)sizeof(ValueType);
  167. return tmp;
  168. }
  169. friend Iterator operator+(difference_type i, const Iterator& right) { return (right + i); }
  170. Iterator& operator-=(difference_type i) {
  171. this->offset -= i * (Long)sizeof(ValueType);
  172. return *this;
  173. }
  174. Iterator operator-(difference_type i) const {
  175. Iterator<ValueType> tmp(*this);
  176. tmp.offset -= i * (Long)sizeof(ValueType);
  177. return tmp;
  178. }
  179. difference_type operator-(const ConstIterator<ValueType>& I) const { return static_cast<const ConstIterator<ValueType>&>(*this) - I; }
  180. };
  181. template <class ValueType, Long DIM> class StaticArray : public Iterator<ValueType> {
  182. public:
  183. StaticArray();
  184. ~StaticArray();
  185. StaticArray(const ValueType(&arr_)[DIM]) : StaticArray() {
  186. for (Long i = 0; i < DIM; i++) arr[i] = arr_[i];
  187. }
  188. private:
  189. StaticArray(const StaticArray&);
  190. StaticArray& operator=(const StaticArray&);
  191. Iterator<ValueType> arr;
  192. };
  193. #define PVFMM_PTR2ITR(type, ptr, len) pvfmm::Iterator<type>((type*)ptr, len)
  194. #define PVFMM_PTR2CONSTITR(type, ptr, len) pvfmm::ConstIterator<type>((const type*)ptr, len)
  195. #else
  196. #define PVFMM_PTR2ITR(type, ptr, len) (type*) ptr
  197. #define PVFMM_PTR2CONSTITR(type, ptr, len) (const type*) ptr
  198. #endif
  199. /**
  200. * \brief Identify each type uniquely.
  201. */
  202. template <class T> class TypeTraits {
  203. public:
  204. static uintptr_t ID();
  205. static bool IsPOD();
  206. };
  207. /**
  208. * \brief MemoryManager class declaration.
  209. */
  210. class MemoryManager {
  211. public:
  212. static const char init_mem_val = 42;
  213. /**
  214. * \brief Header data for each memory block.
  215. */
  216. struct MemHead {
  217. Long n_indx;
  218. Long n_elem;
  219. Long type_size;
  220. Long alloc_ctr;
  221. uintptr_t type_id;
  222. unsigned char check_sum;
  223. };
  224. /**
  225. * \brief Constructor for MemoryManager.
  226. */
  227. MemoryManager(Long N);
  228. /**
  229. * \brief Constructor for MemoryManager.
  230. */
  231. ~MemoryManager();
  232. static MemHead& GetMemHead(char* p);
  233. static void CheckMemHead(const MemHead& p);
  234. Iterator<char> malloc(const Long n_elem = 1, const Long type_size = sizeof(char), const uintptr_t type_id = TypeTraits<char>::ID()) const;
  235. void free(Iterator<char> p) const;
  236. void print() const;
  237. static void test();
  238. // Check all free memory equals init_mem_val
  239. void Check() const;
  240. // A global MemoryManager object. This is the default for aligned_new and aligned_free
  241. static MemoryManager& glbMemMgr() {
  242. static MemoryManager m(PVFMM_GLOBAL_MEM_BUFF * 1024LL * 1024LL);
  243. return m;
  244. }
  245. private:
  246. // Private constructor
  247. MemoryManager();
  248. // Private copy constructor
  249. MemoryManager(const MemoryManager& m);
  250. /**
  251. * \brief Node structure for a doubly linked list, representing free and
  252. * occupied memory blocks. Blocks are split, merged or state is changed
  253. * between free and occupied in O(1) time given the pointer to the MemNode.
  254. */
  255. struct MemNode {
  256. bool free;
  257. Long size;
  258. char* mem_ptr;
  259. Long prev, next;
  260. std::multimap<Long, Long>::iterator it;
  261. };
  262. /**
  263. * \brief Return index of one of the available MemNodes from node_stack or
  264. * create new MemNode by resizing node_buff.
  265. */
  266. Long new_node() const;
  267. /**
  268. * \brief Add node index for now available MemNode to node_stack.
  269. */
  270. void delete_node(Long indx) const;
  271. char* buff; // pointer to memory buffer.
  272. Long buff_size; // total buffer size in bytes.
  273. Long n_dummy_indx; // index of first (dummy) MemNode in link list.
  274. mutable std::vector<MemNode> node_buff; // storage for MemNode objects, this can only grow.
  275. mutable std::stack<Long> node_stack; // stack of available free MemNodes from node_buff.
  276. mutable std::multimap<Long, Long> free_map; // pair (MemNode.size, MemNode_id) for all free MemNodes.
  277. mutable omp_lock_t omp_lock; // openmp lock to prevent concurrent changes.
  278. mutable std::set<void*> system_malloc; // track pointers allocated using system malloc.
  279. };
  280. inline uintptr_t align_ptr(uintptr_t ptr) {
  281. const uintptr_t ALIGN_MINUS_ONE = PVFMM_MEM_ALIGN - 1;
  282. const uintptr_t NOT_ALIGN_MINUS_ONE = ~ALIGN_MINUS_ONE;
  283. return ((ptr + ALIGN_MINUS_ONE) & NOT_ALIGN_MINUS_ONE);
  284. }
  285. /**
  286. * \brief Aligned allocation as an alternative to new. Uses placement new to
  287. * construct objects.
  288. */
  289. template <class ValueType> Iterator<ValueType> aligned_new(Long n_elem = 1, const MemoryManager* mem_mgr = &MemoryManager::glbMemMgr());
  290. /**
  291. * \brief Aligned de-allocation as an alternative to delete. Calls the object
  292. * destructors. Not sure which destructor is called for virtual classes, this
  293. * is why we also match the TypeTraits<T>::ID()
  294. */
  295. template <class ValueType> void aligned_delete(Iterator<ValueType> A, const MemoryManager* mem_mgr = &MemoryManager::glbMemMgr());
  296. /**
  297. * \brief Wrapper to memcpy. Also checks if source and destination pointers are
  298. * the same.
  299. */
  300. template <class ValueType> Iterator<ValueType> memcopy(Iterator<ValueType> destination, ConstIterator<ValueType> source, Long num);
  301. template <class ValueType> Iterator<ValueType> memset(Iterator<ValueType> ptr, int value, Long num);
  302. } // end namespace pvfmm
  303. #include <pvfmm/mem_mgr.txx>
  304. #endif //_PVFMM_MEM_MGR_HPP_