TPIE

2362a60
memory.h
Go to the documentation of this file.
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 //
4 // Copyright 2011, The TPIE development team
5 //
6 // This file is part of TPIE.
7 //
8 // TPIE is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License as published by the
10 // Free Software Foundation, either version 3 of the License, or (at your
11 // option) any later version.
12 //
13 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
14 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 // License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public License
19 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
20 
24 
25 #ifndef __TPIE_MEMORY_H__
26 #define __TPIE_MEMORY_H__
27 
28 #include <tpie/config.h>
29 #include <tpie/util.h>
30 #include <tpie/resource_manager.h>
31 #include <tpie/pretty_print.h>
32 #include <mutex>
33 #include <unordered_map>
34 #include <type_traits>
35 #include <utility>
36 #include <memory>
37 #include <atomic>
38 
39 namespace tpie {
40 
44 class memory_manager final : public resource_manager {
45 public:
50  memory_manager();
51 
56  std::pair<uint8_t *, size_t> __allocate_consecutive(size_t upper_bound, size_t granularity);
57 
58  void register_allocation(size_t bytes) {
59  register_increased_usage(bytes);
60  }
61 
62  void register_deallocation(size_t bytes) {
63  register_decreased_usage(bytes);
64  }
65 
66  std::string amount_with_unit(size_t amount) const override {
67  return bits::pretty_print::size_type(amount);
68  }
69 
70 #ifndef TPIE_NDEBUG
71  // The following methods take the mutex before calling the private doubly
72  // underscored equivalent.
73  void register_pointer(void * p, size_t size, const std::type_info & t);
74  void unregister_pointer(void * p, size_t size, const std::type_info & t);
75  void assert_tpie_ptr(void * p);
76  void complain_about_unfreed_memory();
77 #endif
78 
79 protected:
80  void throw_out_of_resource_error(const std::string & s) override;
81 
82 private:
83 #ifndef TPIE_NDEBUG
84  std::mutex m_mutex;
85 
86  // Before calling these methods, you must have the mutex.
87  void __register_pointer(void * p, size_t size, const std::type_info & t);
88  void __unregister_pointer(void * p, size_t size, const std::type_info & t);
89  void __assert_tpie_ptr(void * p);
90  void __complain_about_unfreed_memory();
91 
92  std::unordered_map<void *, std::pair<size_t, const std::type_info *> > m_pointers;
93 #endif
94 };
95 
99 void init_memory_manager();
100 
104 void finish_memory_manager();
105 
112 
117 inline void __register_pointer(void * p, size_t size, const std::type_info & t) {
118 #ifndef TPIE_NDEBUG
119  get_memory_manager().register_pointer(p, size, t);
120 #else
121  unused(p);
122  unused(size);
123  unused(t);
124 #endif
125 }
126 
131 inline void __unregister_pointer(void * p, size_t size, const std::type_info & t) {
132 #ifndef TPIE_NDEBUG
133  get_memory_manager().unregister_pointer(p, size, t);
134 #else
135  unused(p);
136  unused(size);
137  unused(t);
138 #endif
139 }
140 
145 inline void assert_tpie_ptr(void * p) {
146 #ifndef TPIE_NDEBUG
147  if (p)
148  get_memory_manager().assert_tpie_ptr(p);
149 #else
150  unused(p);
151 #endif
152 }
153 
154 #ifndef DOXYGEN
155 template <typename T,
159  bool x=std::is_polymorphic<T>::value
160 >
161 struct __object_addr {
162  void * operator()(T * o) {return const_cast<void*>(static_cast<const void*>(o));}
163 };
164 
168 template <typename T>
169 struct __object_addr<T, true> {
170  void * operator()(T * o) {return const_cast<void*>(dynamic_cast<const void *>(o));}
171 };
172 #endif
173 
181 template <typename D, typename T>
182 inline D ptr_cast(T * t) { return reinterpret_cast<D>(__object_addr<T>()(t)); }
183 
184 
185 template <typename T>
186 inline T * __allocate() {
187  if(!std::is_polymorphic<T>::value) return reinterpret_cast<T *>(new uint8_t[sizeof(T)]);
188  uint8_t * x = new uint8_t[sizeof(T)+sizeof(size_t)];
189  *reinterpret_cast<size_t*>(x) = sizeof(T);
190  return reinterpret_cast<T*>(x + sizeof(size_t));
191 }
192 
193 template <typename T>
194 inline size_t tpie_size(T * p) {
195  if(!std::is_polymorphic<T>::value) return sizeof(T);
196  uint8_t * x = ptr_cast<uint8_t *>(p);
197  return * reinterpret_cast<size_t *>(x - sizeof(size_t));
198 }
199 
200 
205 template <typename T>
207  size_t size;
208  T * data;
209  array_allocation_scope_magic(size_t s): size(0), data(0) {
210  get_memory_manager().register_allocation(s * sizeof(T) );
211  size=s;
212  }
213 
214  T * allocate() {
215  data = new T[size];
216  __register_pointer(data, size*sizeof(T), typeid(T));
217  return data;
218  }
219 
220  T * finalize() {
221  T * d = data;
222  size = 0;
223  data = 0;
224  return d;
225  }
226 
228  if(size) get_memory_manager().register_deallocation(size*sizeof(T));
229  }
230 };
231 
236 template <typename T>
238  size_t deregister;
239  T * data;
240  allocation_scope_magic(): deregister(0), data(0) {}
241 
242  T * allocate() {
243  get_memory_manager().register_allocation(sizeof(T));
244  deregister = sizeof(T);
245  data = __allocate<T>();
246  __register_pointer(data, sizeof(T), typeid(T));
247  return data;
248  }
249 
250  T * finalize() {
251  T * d = data;
252  deregister = 0;
253  data = 0;
254  return d;
255  }
256 
258  if (data) __unregister_pointer(data, sizeof(T), typeid(T));
259  delete[] reinterpret_cast<uint8_t*>(data);
260  if (deregister) get_memory_manager().register_deallocation(deregister);
261  }
262 };
263 
269 template <typename T>
270 inline T * tpie_new_array(size_t size) {
272  m.allocate();
273  return m.finalize();
274 }
275 
289 template <typename T, typename ... Args>
290 inline T * tpie_new(Args &&... args) {
292  new(m.allocate()) T(std::forward<Args>(args)...);
293  return m.finalize();
294 }
295 
300 template <typename T>
301 inline void tpie_delete(T * p) throw() {
302  if (p == 0) return;
303  get_memory_manager().register_deallocation(tpie_size(p));
304  uint8_t * pp = ptr_cast<uint8_t *>(p);
305  __unregister_pointer(pp, tpie_size(p), typeid(*p));
306  p->~T();
307  if(!std::is_polymorphic<T>::value)
308  delete[] pp;
309  else
310  delete[] (pp - sizeof(size_t));
311 }
312 
318 template <typename T>
319 inline void tpie_delete_array(T * a, size_t size) throw() {
320  if (a == 0) return;
321  get_memory_manager().register_deallocation(sizeof(T) * size);
322  __unregister_pointer(a, sizeof(T) * size, typeid(T) );
323  delete[] a;
324 }
325 
326 struct tpie_deleter {
327  template <typename T>
328  void operator()(T * t) {
329  tpie_delete(t);
330  }
331 };
332 
337 template <typename T>
338 using unique_ptr=std::unique_ptr<T, tpie_deleter>;
339 
344 template <typename T, typename ... TT>
345 inline unique_ptr<T> make_unique(TT && ... tt) {
346  return unique_ptr<T>(tpie_new<T>(std::forward<TT>(tt)...));
347 }
348 
353 public:
354  memory_bucket(): count(0) {}
355 
356  std::atomic_size_t count;
357  std::string name;
358 };
359 
367 public:
368  explicit memory_bucket_ref(memory_bucket * b=nullptr) noexcept: bucket(b) {}
369  explicit operator bool() const noexcept {return bucket != nullptr;}
370  memory_bucket_ref(const memory_bucket_ref & o) = default;
371  memory_bucket_ref(memory_bucket_ref && o) = default;
372  memory_bucket_ref & operator=(const memory_bucket_ref & o) = default;
373  memory_bucket_ref & operator=(memory_bucket_ref && o) = default;
374  memory_bucket & operator*() noexcept {return *bucket;}
375  const memory_bucket & operator*() const noexcept {return *bucket;}
376  memory_bucket * operator->() noexcept {return bucket;}
377  const memory_bucket * operator->() const noexcept {return bucket;}
378  friend bool operator ==(const memory_bucket_ref & l, const memory_bucket_ref & r) noexcept {return l.bucket == r.bucket;}
379  friend bool operator !=(const memory_bucket_ref & l, const memory_bucket_ref & r) noexcept {return l.bucket != r.bucket;}
380 private:
381  memory_bucket * bucket;
382 };
383 
389 template <class T>
390 class allocator {
391 private:
392  typedef std::allocator<T> a_t;
393  a_t a;
394 public:
395  memory_bucket_ref bucket;
396 
397  typedef typename a_t::size_type size_type;
398  typedef typename a_t::difference_type difference_type;
399  typedef typename a_t::pointer pointer;
400  typedef typename a_t::const_pointer const_pointer;
401  typedef typename a_t::reference reference;
402  typedef typename a_t::const_reference const_reference;
403  typedef typename a_t::value_type value_type;
404 
405  typedef std::true_type propagate_on_container_copy_assignment;
406  typedef std::true_type propagate_on_container_move_assignment;
407  typedef std::true_type propagate_on_container_swap;
408 
409  allocator() = default;
410  allocator(memory_bucket_ref bucket) noexcept : bucket(bucket) {}
411  allocator(const allocator & o) noexcept : bucket(o.bucket) {}
412  template <typename T2>
413  allocator(const allocator<T2> & o) noexcept : bucket(o.bucket) {}
414 
415  template <class U> struct rebind {typedef allocator<U> other;};
416 
417  T * allocate(size_t size, const void * hint=0) {
418  get_memory_manager().register_allocation(size * sizeof(T));
419  if (bucket) bucket->count += size * sizeof(T);
420  T * res = a.allocate(size, hint);
421  __register_pointer(res, size, typeid(T));
422  return res;
423  }
424 
425  void deallocate(T * p, size_t n) {
426  if (p == 0) return;
427  if (bucket) bucket->count -= n * sizeof(T);
428  __unregister_pointer(p, n, typeid(T));
429  get_memory_manager().register_deallocation(n * sizeof(T));
430  return a.deallocate(p, n);
431  }
432  size_t max_size() const noexcept {return a.max_size();}
433 
434  template <typename U, typename ...TT>
435  void construct(U * p, TT &&...x) {a.construct(p, std::forward<TT>(x)...);}
436 
437  // void construct(T * p) {
438  // new(p) T();
439  // }
440  // void construct(T * p, const T& val) {a.construct(p, val);}
441  template <typename U>
442  void destroy(U * p) {
443  p->~U();
444  }
445  pointer address(reference x) const noexcept {return &x;}
446  const_pointer address(const_reference x) const noexcept {return &x;}
447 
448 
449  friend bool operator==(const allocator & l, const allocator & r) noexcept {return l.bucket == r.bucket;}
450  friend bool operator!=(const allocator & l, const allocator & r) noexcept {return l.bucket != r.bucket;}
451 
452  template <typename U>
453  friend class allocator;
454 
455 
456 };
457 
462 size_t consecutive_memory_available(size_t granularity=5*1024*1024);
463 
464 } //namespace tpie
465 
466 #endif //__TPIE_MEMORY_H__
size_t consecutive_memory_available(size_t granularity=5 *1024 *1024)
Find the largest amount of memory that can be allocated as a single chunk.
Resource management object used to track resource usage.
void __register_pointer(void *p, size_t size, const std::type_info &t)
Definition: memory.h:117
void unused(const T &x)
Declare that a variable is unused on purpose.
Definition: util.h:42
unique_ptr< T > make_unique(TT &&...tt)
Create a new unique object using tpie::new.
Definition: memory.h:345
void __unregister_pointer(void *p, size_t size, const std::type_info &t)
Definition: memory.h:131
T * tpie_new_array(size_t size)
Allocate a new array and register its memory usage.
Definition: memory.h:270
A allocator object usable in STL containers, using the TPIE memory manager.
Definition: memory.h:390
Class storring a reference to a memory bucket.
Definition: memory.h:366
memory_manager & get_memory_manager()
Return a reference to the memory manager.
Bucket used for memory counting.
Definition: memory.h:352
Miscellaneous utility functions.
void finish_memory_manager()
Used by tpie_finish to deinitialize the memory manager.
pretty_class for formatting quantities with binary prefixes
Memory management object used to track memory usage.
Definition: memory.h:44
std::unique_ptr< T, tpie_deleter > unique_ptr
like std::unique_ptr, but delete the object with tpie_delete.
Definition: memory.h:338
void tpie_delete(T *p)
Delete an object allocated with tpie_new.
Definition: memory.h:301
void assert_tpie_ptr(void *p)
In a debug build, assert that a given pointer has been allocated with tpie_new.
Definition: memory.h:145
std::pair< uint8_t *, size_t > __allocate_consecutive(size_t upper_bound, size_t granularity)
void init_memory_manager()
Used by tpie_init to initialize the memory manager.
T * tpie_new(Args &&...args)
Allocate an element of the type given as template parameter, and register its memory usage with TPIE...
Definition: memory.h:290
void tpie_delete_array(T *a, size_t size)
Delete an array allocated with tpie_new_array.
Definition: memory.h:319
D ptr_cast(T *t)
Cast between pointer types.
Definition: memory.h:182